I have multiple fragments horizontally adjacent using a ViewPager. Each fragment has a ScrollView that contains a table with many EditText views. When I click on a EditTex
I found the problem, it was the lines in the main activity XML: activity_slide_view_pager.xml
android:focusableInTouchMode="true"
android:descendantFocusability="beforeDescendants"
This was causing the RelativeLayout to grab focus.
As an addition to @Cameron Ketcham answer, the best fix of the issue is Creating your own CustomViewpager class that extends from ViewPager and overriding the RequestChildFocus method with null so as to disable the automatic focus behavior.
Your customeViewPager class will look something like this
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
}
}
You can now use this class in your xml and continue from there.
Focus is changing to the leftmost fragment because that fragment is the current item of the ViewPager
. You might try to use setCurrentItem(item)
to set the current item to the other fragment (when the user clicks on it) so the left one doesn't steal focus.
This is happening because at the end of the populate()
function of the ViewPager
it will always give focus to a view that is in the current item. You could also fix this issue by copying the ViewPager
source and changing this code to allow any fragment which is on the
screen to have a child with focus.
Change this:
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;
}
}
}
}
}
To something like this:
if (hasFocus()) {
View currentFocused = findFocus();
ItemInfo ii = currentFocused != null ? infoForAnyChild(currentFocused) : null;
if (ii == null || !infoIsOnScreen(ii)) {
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
ii = infoForChild(child);
if (ii != null && infoIsOnScreen(ii)) {
if (child.requestFocus(FOCUS_FORWARD)) {
break;
}
}
}
}
}
public boolean infoIsOnScreen(ItemInfo info) {
// Code to determine if the view is on the screen using ii.offset etc.
}