我使用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>
答案 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中使用此类并从那里继续。