Using adjustResize with fragments and requestFocus - android

I'm trying to create an activity with a single RelativeLayout used as a fragment container, where each fragment has a separate background color that bleeds under a translucent status bar, and where the activity as a whole accounts for the keyboard size.
The layout for the activity is:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
The fragments are wrapped with:
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true" />
And the activity is defined as:
<activity android:screenOrientation="portrait"
android:name=".login.LoginActivity"
android:windowSoftInputMode="adjustResize" />
Everything is working fine for the first fragment. The activity resizes the RelativeLayout, the fragment contained within it resizes to adjust for the keyboard, and everything is fine. However, when replacing one fragment with another that uses <requestFocus /> on its <EditText />, the keyboard stays up but the second fragment that is pushed on takes the full screen size (under the keyboard). Closing and re-opening the keyboard causes the activity to re-measure and then everything is fine. Similarly, if the keyboard changes height during the fragment transition (when moving from a field that doesn't support autocorrection to one that does, so the keyboard gets taller), the fragment measures correctly. So it only appears to be a problem when transitioning between two fragments where the keyboard size is constant.
Adding fitsSytemWindows=true to the wrapping RelativeLayout fixes the problem, but also prevents the fragment's view from appearing under the status bar, which isn't what I want. Is there some way to force the fragment to re-measure or something that I'm missing? This is using native fragments, not app-compat.

Related

Scrollable layout when keyboard pops up, but without focus change

I have a UX problem with my layout. I want that is possible that the user can scroll over the compleat layout without a focus change when the keyboard popes up.
This is what the Layout looks like when the activity starts
This is what happens when the user clicks to the Big Text EditText
This is what I want the layout to look like, the positions should stand in the same way as before, but it should be possible to scroll to the bottom with the keyboard open
The rootView of my layout is
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
I also try to add android:windowSoftInputMode="adjustResize" and android:windowSoftInputMode="adjustPan" the the activity in the Manifest.xml but it does not solve my problem.

NestedScrollView not saving fragment scroll stated when navigated back

My App uses a single activity architecture which has a NestedScrollView in the activity layout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/root_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.android.navigationadvancedsample.MainActivity">
<androidx.core.widget.NestedScrollView
android:id="#+id/app_scroll_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:fillViewport="true">
<FrameLayout
android:id="#+id/nav_host_container"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</androidx.core.widget.NestedScrollView>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/bottom_nav"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:menu="#menu/bottom_nav"/>
</LinearLayout>
My issue is that that when I scroll a fragment, then navigate to another, then go back, the scroll position is reset. I've seen another answer which stated that adding IDs to the layouts should fix the issue, but it hasn't for me. Also, interestingly, the scroll position saves fine on configuration change.
I'm using NavigationComponents, could this be related? Here's a sample project that reproduces the issue (based on Google's NavigationAdvancedSample)
NestedScrollView has wrapped the Navigation Container in the activity_main layout. So it is the activity that saves the scroll state. There are 3 fragments. Home fragment has fixed height, Leaderboard and Register fragments are scrolling. When you scroll in the Leaderboard or Register and switch to the other one the scroll state does not change(since both can scroll to roughly the same height) but if you switch to home fragment scroll state resets because it has fixed height(size of the screen). Replacing NestedScrollView with the ScrollView didn't change anything as I examined it.
I think the right design is to wrap each fragment with NestedScrollView and set and get scroll state for each fragment.
Navigation component does not add the fragment to the activity state but replace it. So fragments get recreated after by switching between them. So you see scroll state is being reset. You can check it yourself by putting some log in the onCreateView of first fragment and see the log appears twice.

Android BottomSheetBehavior with Keyboard adjustResize

I have the following layout in an activity.
<CoordinatorLayout ...>
<ScrollView ...>
<LinearLayout
...
android:orientation="vertical">
<!-- Some stuff -->
<EditText ...>
<!-- Some more stuff -->
<View
android:id="#+id/keyboard_extender"
...>
</LinearLayout>
</ScrollView>
<LinearLayout
android:id="#+id/bottom_sheet"
android:orientation="vertical"
...
app:layout_behavior="android...BottomSheetBehavior">
<!-- Even more stuff -->
</LinearLayout>
</CoordinatorLayout>
and I want that the keyboard shouldn't push up the bottom_sheet but it should push up the keyboard_extender. Please note that the bottom_sheet is not a BottomSheetDialog but just a view using the android.support.design.widget.BottomSheetBehavior. This can't be changed to a BottomSheetDialog because I want the rest of the screen to remain active at the same time as the bottom_sheet
I never set the visibility of the bottom_sheet to View.GONE. I only change its state from BottomSheetBehavior.EXPANDED to BottomSheetBehavior.COLLAPSED and back. Also, I want the bottom_sheet to be visible only when the keyboard isn't.
Since I need that the keyboard_extender should always be above the keyboard, I have set in the AndroidManifest.xml that android:windowSoftInputMode="adjustResize" (which I assume is unavoidable)
I have a method which when called should hide the keyboard and show the bottom_sheet, but the problem I'm facing is that the bottom_sheet starts animating to BottomSheetBehavior.EXPANDED at the same time that the keyboard starts hiding, and when the keyboard starts hiding, the screen is actually resized because of the windowSoftInputMode="adjustResize" and the bottom_sheet starts expanding from the top of the keyboard and it doesn't move down along with the keyboard. So, when the keyboard completely hides, the bottom_sheet is actually sitting in the middle of the screen (just above the height of the keyboard).
Ideally, I'd like that the keyboard starts hiding and the bottom_sheet starts expanding at the same time, but the bottom_sheet starts expanding from the bottom of the screen and not the top of the keyboard.
The very hacky fix I'm currently using to overcome this issue is to delay the expanding of the bottom_sheet by SoftInput.KEYBOARD_POPUP_DELAY, which seems to be working for the time being. Is there any cleaner alternative?

Android how to ignore auto resizing when keyboard pops up?

let's say I have a view that is made up of 2 layers -> top layer and bottom layer. I place them both in a frame layout.
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- bottom layer -->
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="#drawable/some_image_you_shouldnt_shrink"/>
<!-- top layer -->
<EditText
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/somewhat_transparent"/>
</FrameLayout>
now, presumably, when i tap on the editText, the keyboard will pop up, and shrink the size of the edit text. However, it seems that the bottom layer is ALSO getting resized. How do i prevent this bottom layer from getting resized?
Note: the framelayout is in a fragment, and the activity that holds this fragment must declare android:windowSoftInputMode="adjustResize".
EDIT*********
Just to clarify, i want the editText layer to adjust as high as the keyboard needs to. however, i don't want the image behind it to adjust at all
i only have 1 activity that handles these similar types of fragments.
You can't prevent a single view from resizing if you set android:windowSoftInputMode="adjustResize". But if you just want to set a non-resizing background, there is a work-around. Instead of setting the background image in the ImageView through XML, add this in your onCreate() method
getWindow().setBackgroundDrawableResource(R.drawable.some_image_you_shouldnt_shrink);
try this in the manifest
android:windowSoftInputMode="stateVisible|adjustPan"

Android soft keyboard hides split bar

I have an activity that loads a fragments at runtime. When I start the application, the activity loads a fragment with an EditText. I use ActionBarSherlock with splitActionBarWhenNarrow so I have a split bar (an action bar at the botton of the screen). When the EditText get focus and the soft keyboard is loaded, it goes on top of the split bar, hiding it. On the action bar I also use NAVIGATION_MODE_LIST and I use the dropdown menu to load another fragment. When I load the other fragment, the lower action bar appears correctly on top of the soft keyboard, even if I go to the other fragment, at it keeps working correctly. I'll add some screenshot to clear it up:
First fragment loader, split bar not visibile with soft keyboard
After loading the second fragment using action bar navigation
Reloading another fragment, action bar still visibile
I tried with a test project with minimal code just to load the fragment and the behavior is the same, the split bar is hidden by the soft keyboard.
How can I make it show the split bar from the beginning?
Edit: android:windowSoftInputMode="adjustResize" doesn't change anything in this behavior
Activity layout:
<it.bem.remailr.MyFrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/fragment_container"
android:orientation="horizontal"
android:background="#drawable/bg_no_repeat"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
Fragment layout:
<it.bem.remailr.MyRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<EditText
android:id="#+id/editText1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="top|left"
android:inputType="textMultiLine|textNoSuggestions"
android:windowSoftInputMode="adjustPan"
android:background="#00000000"
android:hint="#string/text_hint"
android:scrollHorizontally="false" >
</EditText>
<ProgressBar
android:id="#+id/progressBar1"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true" />
Have you tried posting a layout request to the main thread immediately following the input method being shown? You can determine whether the input method is shown/hidden by overriding the onSizeChanged() callback in your root View. As a dirty proof of concept, you could just post that layout request after a given duration (ensuring that you show the input method beforehand).
You could also use the ViewServer to run hierarchyviewer on your device, not emulator in order to determine what Views are present (that is, if the candidates are covering the split Action Bar). From what I remember though, the candidate views are added to the root Dialog that contains the KeyboardView anyway, so it's likely the split Action Bar is just under the space bar, as it were, rather than under the candidate view.
In order to implement onSizeChanged() you must extend the ViewGroup class that is at the root of your View hierachy. For example, you may have a LinearLayout as your root ViewGroup and all your Views are children of this. What you do then is create a new class called MyLinearLayout that extends LinearLayout, put MyLinearLayout as your root View in the xml file, and then implement the onSizeChanged() callback. It will then be called by the System when the input method is shown.

Categories

Resources