Bug P2
Status Update
Comments
ph...@sprylab.com <ph...@sprylab.com> #2
Over to Ralston to take a look. I imagine with the new relocation logic it should be fixed?
ph...@sprylab.com <ph...@sprylab.com> #3
What is happening here is that the TextField does not know that it is in a scrollable container, and since the keyboard is going to hide the currently focused text, the text field calls View.requestRectangleOnScreen which causes the entire app to pan up, and that clips the top bar.
The Relocation APIs are experimental right now. It is not used in TextField as we are past the alpha stage and can only use stable APIs in TextField. So this bug can only be fixed post 1.0
ph...@sprylab.com <ph...@sprylab.com> #4
This should be fixed by
I verified that this sample code now works when soft input mode is AdjustResize.
ph...@sprylab.com <ph...@sprylab.com> #6
I think I have a workaround:
I needed to override the following methods in my base fragment class:
override fun onAttach(context: Context) {
super.onAttach(context)
parentFragment?.let {
userVisibleHint = it.userVisibleHint && userVisibleHint
setMenuVisibility(it.isMenuVisible && isMenuVisible)
}
}
override fun setUserVisibleHint(isVisibleToUser: Boolean) {
super.setUserVisibleHint(isVisibleToUser)
if (isAdded) {
val fragments = childFragmentManager.fragments
for (fragment in fragments) {
fragment.userVisibleHint = isVisibleToUser
}
}
}
@SuppressLint("RestrictedApi")
override fun setMenuVisibility(menuVisible: Boolean) {
super.setMenuVisibility(menuVisible)
if (isAdded) {
val fragments = childFragmentManager.fragments
for (fragment in fragments) {
fragment.setMenuVisibility(menuVisible)
}
}
}
And in my Adapter:
@SuppressLint("RestrictedApi")
@Override
public void setPrimaryItem(final ViewGroup container, final int position, final Object object) {
try {
final Fragment fragment = (Fragment) object;
final Field currentPrimaryItemField = FragmentStatePagerAdapter.class.getDeclaredField("mCurrentPrimaryItem");
currentPrimaryItemField.setAccessible(true);
final Fragment currentPrimaryItem = (Fragment) currentPrimaryItemField.get(this);
if (fragment != currentPrimaryItem) {
if (currentPrimaryItem != null) {
currentPrimaryItem.setMenuVisibility(false);
currentPrimaryItem.setUserVisibleHint(false);
}
fragment.setMenuVisibility(FRAGMENT_OF_PAGER.isMenuVisible());
fragment.setUserVisibleHint(FRAGMENT_OF_PAGER.getUserVisibleHint());
currentPrimaryItemField.set(this, fragment);
}
} catch (final NoSuchFieldException | IllegalAccessException e) {
LOG.warn("Could not handle setPrimaryItem", e);
// Fallback to super
super.setPrimaryItem(container, position, object);
}
}
I needed to override the following methods in my base fragment class:
override fun onAttach(context: Context) {
super.onAttach(context)
parentFragment?.let {
userVisibleHint = it.userVisibleHint && userVisibleHint
setMenuVisibility(it.isMenuVisible && isMenuVisible)
}
}
override fun setUserVisibleHint(isVisibleToUser: Boolean) {
super.setUserVisibleHint(isVisibleToUser)
if (isAdded) {
val fragments = childFragmentManager.fragments
for (fragment in fragments) {
fragment.userVisibleHint = isVisibleToUser
}
}
}
@SuppressLint("RestrictedApi")
override fun setMenuVisibility(menuVisible: Boolean) {
super.setMenuVisibility(menuVisible)
if (isAdded) {
val fragments = childFragmentManager.fragments
for (fragment in fragments) {
fragment.setMenuVisibility(menuVisible)
}
}
}
And in my Adapter:
@SuppressLint("RestrictedApi")
@Override
public void setPrimaryItem(final ViewGroup container, final int position, final Object object) {
try {
final Fragment fragment = (Fragment) object;
final Field currentPrimaryItemField = FragmentStatePagerAdapter.class.getDeclaredField("mCurrentPrimaryItem");
currentPrimaryItemField.setAccessible(true);
final Fragment currentPrimaryItem = (Fragment) currentPrimaryItemField.get(this);
if (fragment != currentPrimaryItem) {
if (currentPrimaryItem != null) {
currentPrimaryItem.setMenuVisibility(false);
currentPrimaryItem.setUserVisibleHint(false);
}
fragment.setMenuVisibility(FRAGMENT_OF_PAGER.isMenuVisible());
fragment.setUserVisibleHint(FRAGMENT_OF_PAGER.getUserVisibleHint());
currentPrimaryItemField.set(this, fragment);
}
} catch (final NoSuchFieldException | IllegalAccessException e) {
LOG.warn("Could not handle setPrimaryItem", e);
// Fallback to super
super.setPrimaryItem(container, position, object);
}
}
jg...@google.com <jg...@google.com>
ph...@sprylab.com <ph...@sprylab.com> #7
This still happens with FragmentStatePagerAdapter and mode BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT
ph...@sprylab.com <ph...@sprylab.com> #8
I think the cause is this:
boolean performOptionsItemSelected(@NonNull MenuItem item) {
if (!mHidden) {
if (mHasMenu && mMenuVisible) {
if (onOptionsItemSelected(item)) {
return true;
}
}
return mChildFragmentManager.dispatchOptionsItemSelected(item);
}
return false;
}
It is not checking the parents - it should actually call isMenuVisible()
boolean performOptionsItemSelected(@NonNull MenuItem item) {
if (!mHidden) {
if (mHasMenu && mMenuVisible) {
if (onOptionsItemSelected(item)) {
return true;
}
}
return mChildFragmentManager.dispatchOptionsItemSelected(item);
}
return false;
}
It is not checking the parents - it should actually call isMenuVisible()
ph...@sprylab.com <ph...@sprylab.com> #9
Confirmed, my workaround now looks like this:
packageandroidx.fragment.app
import android.view.MenuItem
abstract class FixedMenuFragment(contentLayoutId: Int) : Fragment(contentLayoutId) {
override fun performOptionsItemSelected(item: MenuItem): Boolean {
if (!mHidden) {
if (mHasMenu && isMenuVisible) {
if (onOptionsItemSelected(item)) {
return true
}
}
return mChildFragmentManager.dispatchOptionsItemSelected(item)
}
return false
}
}
This way nested ViewPager work correctly with the menus
package
import android.view.MenuItem
abstract class FixedMenuFragment(contentLayoutId: Int) : Fragment(contentLayoutId) {
override fun performOptionsItemSelected(item: MenuItem): Boolean {
if (!mHidden) {
if (mHasMenu && isMenuVisible) {
if (onOptionsItemSelected(item)) {
return true
}
}
return mChildFragmentManager.dispatchOptionsItemSelected(item)
}
return false
}
}
This way nested ViewPager work correctly with the menus
Description
Our articles are one ViewPager and each article has another ViewPager for it's pages.
Basically:
Root
|
-- Article 1
|
-- Page 1
-- Page 2
-- Page 3
-- Article 2
|
-- Page 1
-- Page 2
-- Page 3
Unfortunately the ViewPager does not correctly handle this with nested Fragments which each have menu items. (e.g. a Bookmark item for each page). Paging works as expected but the menu shows all items even from pages which are not visible.