Android:EditText焦点跳转到ScrollView内的另一个

时间:2014-01-20 17:10:05

标签: android android-edittext scrollview

我使用ViewPager水平相邻多个片段。每个片段都有一个ScrollView,其中包含一个包含许多EditText视图的表。当我单击EditText时,它会获得焦点,然后将其丢失到最左边片段中的其他EditText。有时焦点切换会立即发生,有时我在输入EditText时会发生。通常,最左边片段中最顶端的EditText会抢夺焦点。

当单击最左边片段中的EditText时,即使它不是最顶层的,也看不到问题。它就像Android一样不喜欢专注于不在左边缘的TextView。这听起来很熟悉吗?

我没有成功尝试在ScrollView中覆盖findFocus()方法,如randomly-jumping中的Skip所示。附带的源代码很大,但它可能对其他人有用......

package com.example.slideViewPager;

import java.util.ArrayList;

import com.example.slideViewPager.R;

import android.content.Context;
import android.graphics.Color;
import android.graphics.Typeface;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;

public class SlideViewPager extends FragmentActivity {
    private static Context g;
    private static ArrayList<String> pages;
    private static int currentItem;    // restore page position after tilt
    private static int[] scrollStateY;
    private static NotesViewFragment[] fragmentArray;
    private static int id;            // to create unique view ids

    @Override
    public void onCreate(Bundle savedInstanceState) {
        g = getApplicationContext();
        setContentView(R.layout.activity_slide_view_pager);
        pages = new ArrayList<String>();
        for (int i = 0; i < 4; ++i)
            pages.add(Integer.toString(i));

        if (savedInstanceState == null) {
            currentItem = 0;
            scrollStateY = new int[pages.size()];    // assume all 0s
            id = 0;
        }
        else {
            currentItem = savedInstanceState.getInt("currentItem");
            scrollStateY = savedInstanceState.getIntArray("scrollStateY");
            id = savedInstanceState.getInt("id");
            System.out.println("Notes onCreate RESTORE: currentItem="+currentItem+"; id="+id);
        }

        fragmentArray = new NotesViewFragment[pages.size()];
        System.out.println("onCreate: start");
        super.onCreate(savedInstanceState);
        ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
        NotesPagerAdapter pagerAdapter = new NotesPagerAdapter(getSupportFragmentManager());
        viewPager.setAdapter(pagerAdapter);
        viewPager.setCurrentItem(currentItem);
        viewPager.setOnPageChangeListener(onPageChangeListener);
        System.out.println("onCreate: done");
    }

    @Override
    public void onSaveInstanceState(Bundle bundle) {
        System.out.println("Notes: onSaveInstanceState: currentItem="+currentItem);
        super.onSaveInstanceState(bundle);
        bundle.putInt("currentItem", currentItem);
        bundle.putIntArray("scrollStateY", scrollStateY);
        bundle.putInt("id", id);
    }

    public void onBackPressed() {
        System.out.println("Notes: onBackPressed: currentItem="+currentItem);
        super.onBackPressed();
    }

    /////////////////////////////////////////////////////////////////
    public static class NotesPagerAdapter extends FragmentPagerAdapter {

        public NotesPagerAdapter(FragmentManager fm) {
            super(fm);
            System.out.println("NotesPagerAdapter: this="+this);
        }

        @Override
        public Fragment getItem(int position) {
            String pageNum = pages.get(position);
            NotesViewFragment notesViewFragment = NotesViewFragment.initialize(pageNum, position);        // create new fragment
            System.out.println("NotesPagerAdapter: getItem: CREATED position:"+position+" = page:"+pageNum+"; fragment="+notesViewFragment);
            return notesViewFragment;
        }

        @Override
        public int getCount() {
            return pages.size();
        }

        // nothing being done here
        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            System.out.println("NotesPagerAdapter: destroyItem position="+position);
            super.destroyItem(container, position, object);
        }

        @Override
        public float getPageWidth(int position) {
            System.out.println("NotesPagerAdapter: getPageWidth position="+position);
            return (1.0f/2);    // vary # pages/view
        }
    }

    //////////////////////////////////////////////////////
    public static class NotesViewFragment extends Fragment {
        private int position;    // needed to save scrollY into scrollStateY[]
        private String pageNum;    // index
        private ScrollView itemScrollView;

        public NotesViewFragment() {
            super();
            System.out.println("NotesViewFragment: new this:"+this);
        }

        public static NotesViewFragment initialize(String page, int position) {
            NotesViewFragment notesViewFragment = new NotesViewFragment();
            System.out.println("NotesViewFragment: initialize: this:"+notesViewFragment+"; page: "+page+"; position="+position);
            Bundle args = new Bundle();
            args.putString("pageNum", page);
            args.putInt("position", position);
            scrollStateY[position] = 0;        // start at top
            notesViewFragment.setArguments(args);
            return notesViewFragment;
        }

        @Override
        public void onSaveInstanceState(Bundle outState) {
            super.onSaveInstanceState(outState);
            System.out.println("NotesViewFragment: onSaveInstanceState this:"+this+"; page: "+pageNum+"; scrollView="+itemScrollView);
            // itemScrollView will be null occasionally (attached but not createViewed)
            if (itemScrollView != null)
                scrollStateY[position] = itemScrollView.getScrollY();
            outState.putString("pageNum", pageNum);
        }

        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            Bundle args = getArguments();
            if (args != null) {
                pageNum = args.getString("pageNum");
                position = args.getInt("position");
                fragmentArray[position] = this;
                System.out.println("NotesViewFragment: onCreate: this:"+this+"; page: "+pageNum+"; position="+position+"; yPos="+scrollStateY[position]);
            }
            else    // should not happen
                System.out.println("NotesViewFragment: onCreate: NO ARGS !!! this:"+this);            
        }

        public void onDestroyView() {
            super.onDestroyView();
            if (itemScrollView != null)        // could be null if not createViewed
                scrollStateY[position] = itemScrollView.getScrollY();

            System.out.println("NotesViewFragment: onDestroyView: "+pageNum+" this="+this+"; scrollY="+scrollStateY[position]);
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            if (savedInstanceState != null) {    // config change happened
                pageNum = savedInstanceState.getString("pageNum");
                System.out.println("NotesViewFragment: onCreateView: RESTORED "+pageNum+" this="+this+"; yPos="+scrollStateY[position]);
            }
            else
                System.out.println("NotesViewFragment: onCreateView: "+pageNum+"; this="+this);

            // Inflate the layout containing a title and body text.
            ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.fragment_screen_slide_page, container, false);
            TableLayout itemNotesTable = (TableLayout) rootView.findViewById(R.id.tableLayoutNotes);
            TextView itemTitle = (TextView) rootView.findViewById(R.id.textViewTitle);
            itemScrollView = (ScrollView) rootView.findViewById(R.id.scroll_form);
            itemTitle.setText("Team "+pageNum);

            for (int i = 0; i < 12; ++i) {
                TableRow tr = new TableRow(g);
                tr.setId(++id);

                ImageView itemThumbnail = new ImageView(g);
                itemThumbnail.setId(++id);
                itemThumbnail.setImageResource(R.drawable.notes);    // set icon
                tr.addView(itemThumbnail);

                LinearLayout ll = new LinearLayout(g);
                ll.setId(++id);
                ll.setOrientation(LinearLayout.VERTICAL);
                String text = " Team "+pageNum;
                ll.addView(makeTextItem(text, false));

                TextView textView;
                if ((id % 2) == 0) {    // make some entries editable
                    textView = new EditText(g);
                    textView.setFocusable(true);
                    textView.setFocusableInTouchMode(true);
                    textView.setImeOptions(EditorInfo.IME_FLAG_NO_ENTER_ACTION);
                    textView.setOnFocusChangeListener(onFocusChangeListener);
                }
                else
                    textView = new TextView(g);

                textView.setId(++id);
                String str = "Line "+i+" is blah blah blah and more blah blah blah";
                textView.setText(str);
                textView.setTextColor(Color.BLACK);
                textView.setTextSize(16);
                textView.setPadding(2, 2,  2,  2);        // start, top, end, bottom
                ll.addView(textView);
                tr.addView(ll);
                itemNotesTable.addView(tr);
                tr.setOnClickListener(noteClicked);        // make everything in table row clickable
            }

            if (scrollStateY[position] != 0) {
                itemScrollView.post(new Runnable() {
                    public void run() {
                        itemScrollView.scrollTo(0, scrollStateY[position]);
                    }
                });
            }
            return rootView;
        }

        // called from fillNotes
        private static TextView makeTextItem(String label, boolean bold) {
            TextView item = new TextView(g);
            item.setId(++id);
            item.setText(label);
            item.setTextColor(Color.BLACK);
            item.setTextSize(16);
            if (bold)
                item.setTypeface(null, Typeface.BOLD);
            return item;
        }
    }

    // listens for horizontal page scrolls
    ViewPager.OnPageChangeListener onPageChangeListener = new ViewPager.SimpleOnPageChangeListener() {
        @Override
        public void onPageSelected(int position) {
            System.out.println("onPageChangeListener: leaving page:"+currentItem+"; for page: "+position);
            currentItem = position;
        }
    };

    static View.OnFocusChangeListener onFocusChangeListener = new View.OnFocusChangeListener() {

        @Override
        public void onFocusChange(View view, boolean hasFocus) {
            System.out.println("onFocusChangeListener: "+hasFocus+"; "+view);
            if (! hasFocus) {
                EditText editText = (EditText) view;
                String text = editText.getText().toString();
                System.out.println("onFocusChangeListener: "+text);
            }
        }
    };

    static OnClickListener noteClicked = new OnClickListener() {
        public void onClick(View tr) {
            for (View parent = tr; parent != null; parent = (View) parent.getParent()) {
                for (NotesViewFragment fragment : fragmentArray)
                    if (fragment != null  &&  fragment.itemScrollView == parent) {
                        System.out.println("noteClicked: page: "+fragment.pageNum);
                        return;
                    }
            }
        }
    };
}

有几个XML文件:fragment_screen_slide_page.xml ..........

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/content"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/textViewTitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:text=""
        android:textAppearance="?android:attr/textAppearanceLarge" />

    <View
        android:id="@+id/separator"
        android:layout_width="fill_parent"
        android:layout_height="1dip"
        android:layout_alignParentRight="true"
        android:layout_marginTop="4dp"
        android:layout_below="@+id/textViewTitle"
        android:background="#888888" />

    <ScrollView
        android:id="@+id/scroll_form"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@+id/separator" >

        <TableLayout
            android:id="@+id/tableLayoutNotes"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:stretchColumns="1"  >
        </TableLayout>
    </ScrollView>
</RelativeLayout>

和activity_slide_view_pager.xml ----------

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"

    android:descendantFocusability="beforeDescendants"
    android:focusableInTouchMode="true"
    tools:context=".Page" >

    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</RelativeLayout>

3 个答案:

答案 0 :(得分:3)

焦点正在变为最左边的片段,因为该片段是ViewPager的当前项。您可能会尝试使用setCurrentItem(item)将当前项目设置为其他片段(当用户点击它时),因此左侧的项目不会窃取焦点。

这种情况正在发生,因为在populate()的{​​{1}}函数结束时,它始终会将焦点放在当前项目中的视图上。您还可以通过复制ViewPager源并更改此代码来修复此问题,以允许其上的任何片段 屏幕让孩子有焦点。

改变这个:

ViewPager

对于这样的事情:

if (hasFocus()) {
    View currentFocused = findFocus();
    ItemInfo ii = currentFocused != null ? infoForAnyChild(currentFocused) : null;
    if (ii == null || ii.position != mCurItem) {
        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            ii = infoForChild(child);
            if (ii != null && ii.position == mCurItem) {
                if (child.requestFocus(FOCUS_FORWARD)) {
                    break;
                }
            }
        }
    }
}

答案 1 :(得分:2)

我发现了问题,它是主要活动XML中的行:activity_slide_view_pager.xml

    android:focusableInTouchMode="true"
    android:descendantFocusability="beforeDescendants"

这导致RelativeLayout获得焦点。

答案 2 :(得分:1)

作为@Cameron Ketcham回答的补充,该问题的最佳解决方法是创建自己的CustomViewpager类,该类从ViewPager扩展并使用null覆盖RequestChildFocus方法,以禁用自动焦点行为。

您的customeViewPager类看起来像这样

public class CustomeViewPager extends ViewPager {

   public CustomeViewPager(Context context) {
      super(context);
   }

   public CustomeViewPager(Context context, AttributeSet attrs) {
       super(context, attrs);
   }

   @Override
   public void requestChildFocus(View child, View focused) {
       //Do nothing, disables automatic focus behaviour

   }

}

您现在可以在xml中使用此类并从那里继续。