Scrollview does not shrink when soft keyboard is shown - android

I have a simple chat activity, with a message entry box at the top and then a scrollview with the message list. When the soft keyboard is opened, I want the scrollview to shrink so that the last message is not covered by the keyboard. This is my xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="8dp" >
<TextView
android:id="#+id/chat_with"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:text="Chat with Gordon" />
<RelativeLayout
android:id="#+id/msg_container"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/chat_with"
android:layout_marginTop="10dp">
<EditText
android:id="#+id/chat_message"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="Type your message" />
<ImageButton
android:id="#+id/chat_send"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:background="#00000000"
android:src="#+android:drawable/ic_menu_send" />
</RelativeLayout>
<ScrollView
android:id="#+id/chat_container"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/msg_container"
android:layout_marginTop="15dp"
android:padding="10dp"
android:isScrollContainer="true"
>
<RelativeLayout
android:id="#+id/chat_text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<TextView
android:id="#+id/msg1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hi, how are you?"
android:layout_alignParentRight="true"/>
<TextView
android:id="#+id/msg2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="hey! All right"
android:layout_alignParentLeft="true"
android:layout_below="#+id/msg1"/>
</RelativeLayout>
</ScrollView>
</RelativeLayout>
I just manually inserted two messages but there will be many of them in the real app. I already tried with the adjustPan|adjustResize solution, but it does not work, when I fire the keyboard the layout is unchanged and the last messages are covered by the keyboard. How can I avoid this?
Thanks for your help!

I solved this problem by using the manifest. In the activity I used:
android:windowSoftInputMode="stateHidden|adjustResize"
This way the keyboard starts out hidden and then when the user clicks in the EditText the keyboard will show up and the rest of the screen gets resized.
Look into the windowSoftInputMode for other settings for keyboard behavior (e.g. just covering up screen instead of resizing).
Edit:
To scroll the scroll view to the bottom after the keyboard shows up I needed to use a slight delay because sometimes the scroll would happen first and then the keyboard showed up and the scroll view was no longer at the bottom. I ended up not keeping this for other reasons, but to delay the scroll a bit one can do this:
// now scroll to the bottom
ScrollView sv = (ScrollView) findViewById(R.id.myScrollView);
sv.post(new Runnable() {
#Override
public void run() {
ScrollView sv = (ScrollView) findViewById(R.id.myScrollView);
sv.scrollTo(0, sv.getBottom());
}
});

Related

Android Studio - Scrollview moves outside the screen on keyboard open

I want to make a chat screen which has an EditText and a Button at the bottom (wrapped in a LinearLayout), and a ScrollView for the messages at the top. The problem is that when the user taps the EditText and the keyboard opens, the ScrollView will go off screen as a result of moving up. I would like to move the Layout (with the EditBox and the Button) above the keyboard and the ScrollView to be resized to fit the screen. The problem is shown on the pictures below:
As you can see, the line that writes "Chat" (left image) has disappeared in the right image.
I use this XML code:
<?xml version="1.0" encoding="utf-8"?>
<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:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="15sp"
android:orientation="vertical"
android:background="#ccdcf7"
tools:context="com.orionz.sockettest.ChatActivity">
<ScrollView
android:id="#+id/scroll"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="15"
android:isScrollContainer="false">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="#+id/chatBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:text="Chat\n"
android:textColor="#000000"
android:textIsSelectable="true"
android:textSize="22dp" />
</LinearLayout>
</ScrollView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center|bottom"
android:orientation="horizontal">
<EditText
android:id="#+id/msgInput"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0.8"
android:ems="10"
android:hint="Message..."
android:inputType="text" />
<Button
android:id="#+id/sendButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0.2"
android:background="#drawable/mybutton"
android:padding="5sp"
android:text="Send"
android:textColor="#ffffff"
android:textSize="20sp" />
</LinearLayout>
</LinearLayout>
I have seen many answers such as setting the android:windowSoftInputMode but none has worked. I use Android Studio. Any help would be appreciated.
Try to replace the ScrollView with a ListView like this :
<ListView
android:id="#+id/list_view"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1">
</ListView>
store all the messages in an ArrayList, and set an adapter to the ListView you made :
ListView listView=(ListView) findViewById(R.id.list_view);
ArrayAdapter<String> adapter=new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,ArrayList);
listView.setAdapter(adapter);
Finally, add a listenner on your Button writing these lines :
EditText editText= (EditText) findViewById(R.id.msgInput);
ArrayList.add(editText.getText().toString());
adapter.notifyDataSetChanged();
Finally, I found what was wrong in my case.
The theme was full screen. In the style of the activity I had this line that caused the problem:
<item name="android:windowFullscreen">true</item>
In the java code, I gave a command to open the keyboard on the start of the activity:
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
which was also part of the problem
After adding the adjustResize property to the activity in the manifest, everything worked fine:
android:windowSoftInputMode="adjustResize"
Wrap Scrollview to the whole layout.
i.e place editText and button inside Scrollview and set scrollView Height to android:layout_height="match_parent"

How to move focus out of ScrollView on Android with a remote control?

An app has the following in a layout:
<LinearLayout
android:id="#+id/linearLayoutContents"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:focusable="true"
android:minWidth="120dip"
android:focusableInTouchMode="true"
android:text="#string/set_up">
<requestFocus />
</Button>
...
</LinearLayout>
<ScrollView
android:id="#+id/scrollViewNewDevice"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1">
//Some EditText and AutoCompleteTextView controls
</ScrollView>
</LinearLayout>
You can see that the button gets focus intially. Once the focus is moved into the ScrollView, it can never get out of it with a remote control. Could anyone offer a tip on how to get the focus out of a ScrollView with a remote control?
I am using android:nextFocusUp = "#id/buttonAboveScrollView" for the top element inside the ScrollView to allow the focus to move out of the ScrollView when a remote control is used.

ScrollView does not resize directly after child changes

I've run into a very annoying problem regarding ScrollView resizing, and I'm running out of possible solutions.
I have a FragmentPager containing several different Fragments, one of which has a ScrollView.
The Fragment with the ScrollView is made up of a Spinner and the ScrollView containing a LinearLayout with several rows of other Views (such as SeekBars, Buttons, Edittexts) in it.
Depending on which option is select in the Spinner, the ScrollView shows different views. To do so, some Views have their visibility turned to Gone, while others are turned to Visible.
This works great, except for the fact that the ScrollView does not seem to resize itself properly upon choosing a different option using the Spinner.
When the ScrollView is full of Views, and therefore scrollable, if the user selects an option which shows less Viewsthan required to fill the ViewPort the ScrollView still scrolls.
When the user then chooses the old option again, the ScrollView is now unable to scroll since it took on the size required for the previous option.
When the user then chooses the SAME option again, the ScrollView suddenly is scrollable, since it is now resized to the actual size required.
What is going on here? And better yet, how can I fix this annoying problem?
My layout:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/control_scroll"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#99000000"
android:fillViewport="true" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="20dp"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#DD000000"
android:gravity="bottom"
android:orientation="vertical" >
<TextView
android:id="#+id/lamp_choose_tv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="2dp"
android:paddingLeft="5dp"
android:text="#string/choose_lamp_text"
android:textColor="#FFFFFF"
android:textSize="14sp" />
</LinearLayout>
<Spinner
android:id="#+id/lamp_select_spinner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:textColor="#FFFFFF" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#DD000000"
android:gravity="bottom"
android:orientation="vertical" >
<TextView
android:id="#+id/lamp_settings_tv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="2dp"
android:background="#44000000"
android:paddingLeft="5dp"
android:text="#string/lamp_settings_text"
android:textColor="#FFFFFF"
android:textSize="14sp" />
</LinearLayout>
<!-- Lamp name -->
<LinearLayout
android:id="#+id/naam_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="bottom"
android:paddingBottom="3dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:paddingTop="3dp" >
<TextView
android:id="#+id/bridge_naam"
style="#style/ConfigText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="#string/config_lightname"
android:textColor="#FFFFFF"
android:textSize="16sp" />
<EditText
android:id="#+id/lamp_naam_input"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:background="#drawable/tasstextfield"
android:inputType="textNoSuggestions"
android:textColor="#FFFFFF" >
</EditText>
</LinearLayout>
<View
android:id="#+id/separator"
android:layout_width="fill_parent"
android:layout_height="0.5dp"
android:background="#android:color/black"
android:visibility="visible" />
<!-- Rest of the views -->
Things I already tried:
ForceLayout/requestLayout on the parent ScrollView
Invalidate the ScrollView
ForceLayout/requestLayout on the containing LinearLayout
Invalidating the LinearLayout
Invalidating all children of the ScrollView
ForceLayout/requestLayout on all children of the ScrollView
This might not be the most enjoyable solution, but it might work.
Use a handler to post a delayed message to refresh the view a second time, as if the user would choose the same option twice after having click on the refresh button.
// The code when the user wants to update the views
myButton.setOnClickListener(new OnClickListener{
#Override
public void onClick(View view) {
updateView();
Message m = Message.obtain();
m.what = UPDATE_TAG;
mHandler.sendMessageDelayed(msg, 200);
}
})
...
final int UPDATE_TAG = 1;
public void updateView() {
// Code where View.GONE and View.VISIBLE + invalidate is used.
}
Handler mHandler = new Handler {
#Override
public void handleMessage(Message input_msg) {
if(msg.what == UPDATE_TAG) {
updateView();
}
}
}
Try with this changes
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/control_scroll"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#99000000"
android:fillViewport="true" >
Quit the android:layout_weight="1"
I suppose that LinearLayout uses some kind of caching mechanism to avoid measuring childs every time. Or maybe I'm wrong.
However, you can try to use RelativeLayout instead of bunch of LinearLayout. This will solve your problem and also this will be much more efficient, since nested ViewGroups isn't good for performance.
You can go ahead and set the ScrollView height to "wrap_content" so that even if the child views change the ScrollView can adjust to the new setting

SoftKeyboard hiding EditText

I have a layout that uses an EditText to let users search a database and populate a ListView. The EditText is about 2/3 of the way from the top of the screen (positioned over an ImageView, and followed by some intro text.)
The problem is that the soft keyboard hides the EditText, so the user can't see what he's typing. (I disabled the auto-suggest.)
I've tried LinearLayout, RelativeLayout, paddings, and different alignments/centerings, but I still can't get it to work right. The EditText is either hidden, gets pushed off the top of the screen, or get "squished" and distorted.
Suggestions???
One possible workaround is to move the EditText to the top of the screen. However, this deviates from the graphic design that I was given.
Another possible workaround is for me to make the soft keyboard open in full screen (not sure how, though). This will still hide the EditText, but then I can re-enable the auto-suggestion so the user can see what he's typing... sort of... because he can only see the suggestions for what he's typing.
Here's my latest attempt. See "introFrame".
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:orientation="vertical">
<LinearLayout android:id="#+id/titleContainer"
android:orientation="horizontal" android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView android:text="#string/title_string"
android:textSize="15sp" android:textColor="#FFFFFF"
android:textStyle="bold" android:paddingLeft="5dp"
android:layout_height="fill_parent" android:layout_width="wrap_content" />
</LinearLayout>
<FrameLayout
android:id="#+id/introFrame"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal" >
<ImageView
android:src="#drawable/main_search_image"
android:scaleType="center"
android:layout_gravity="center"
android:layout_height="wrap_content"
android:layout_width="wrap_content"/>
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:paddingTop="140dp" >
<LinearLayout android:id="#+id/introSearchContainer"
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical" >
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1" >
<EditText android:id="#+id/intro_search_box"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint=" Enter keyword "
android:imeOptions="actionGo"
android:inputType="textFilter"
android:maxLines="1" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<Button android:id="#+id/intro_search_button"
android:background="#drawable/custom_button_go"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
<TextView
android:text="#string/search_intro"
android:textSize="15sp"
android:textColor="#FFFFFF"
android:layout_height="wrap_content"
android:layout_width="fill_parent" />
</LinearLayout>
</FrameLayout>
<LinearLayout android:id="#+id/listContainer"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ListView android:id="#+id/itemlist" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:cacheColorHint="#00000000" />
<TextView android:text="No data found" android:layout_width="fill_parent"
android:layout_height="fill_parent" android:gravity="center"
android:textSize="16sp" android:textColor="#FFFFFF" android:id="#+id/android:empty" />
</LinearLayout>
</LinearLayout>
What you're looking for is the Activity's windowSoftInputMode attribute. You set this in your AndroidManifest.xml file, and give it a value such as:
adjustResize: "The activity's main window is always resized to make room for the soft keyboard on screen."
adjustPan: "The activity's main window is not resized to make room for the soft keyboard. Rather, the contents of the window are automatically panned so that the current focus is never obscured by the keyboard and users can always see what they are typing. This is generally less desirable than resizing, because the user may need to close the soft keyboard to get at and interact with obscured parts of the window."
adjustResize will probably work for you, as long as you wrap the layout in a ScrollView. It may have negative effects if you have a bitmap image in the background, as it will be resized as well, in which case you may want to use adjustPan instead.
<activity android:windowSoftInputMode="adjustResize" />
or
<activity android:windowSoftInputMode="adjustPan" />
More information is available at the above link.
What has worked for me is to drop my highest-level LinearLayout in a scrollView (the ScrollView can only have one child). This allowed the entire activity/form to scroll up and not clutter the EditText in focus.
First, I set in my activity:
<activity android:windowSoftInputMode="adjustPan" />
Then I did the ScrollView thing I'm talking about:
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- STUFF -->
</LinearLayout>
</ScrollView>
just use following in manifest...
<activity
android:windowSoftInputMode="adjustPan">
try giving the edit text a layout_weight (i.e. layout_weight=1) , this may have some other effects on your other layout items that you may have to work through, but this may help it stay visible when soft keyboard pops up

Android Scrollview in RelativeLayout with ButtonBar

I'm trying to implement a login view where several EditTexts and a logo are displayed on the screen with a ButtonBar at the bottom, something like this:
alt text http://russellhaering.com/media/addAccount.png
The problem is that on very small screens, especially when they are rotated sideways, the entire main view doesn't fit onto the screen.
I currently have
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#234C59" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:paddingTop="5dip"
android:paddingLeft="15dip"
android:paddingRight="15dip"
android:orientation="vertical" >
<ImageView
android:id="#+id/logo"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:scaleType="fitCenter"
android:layout_centerHorizontal="true"
android:src="#drawable/logo" />
<EditText
android:id="#+id/input_email"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dip"
android:inputType="textEmailAddress"
android:singleLine="true"
android:hint="Username or email" />
<EditText
android:id="#+id/input_password"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop=""
android:inputType="textPassword"
android:singleLine="true"
android:hint="Password" />
</LinearLayout>
<LinearLayout
android:id="#+id/buttonbar_login"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:orientation="horizontal"
style="#android:style/ButtonBar" >
<Button
android:id="#+id/button_signup"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Sign Up" />
<Button
android:id="#+id/button_login"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Log In" />
</LinearLayout>
</RelativeLayout>
I've tried encapsulating the first LinnearLayout in a ScrollView that looks like this:
<ScrollView
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<!-- Linear Layout Here -->
</ScrollView>
But that introduces two problems:
The ScrollView doesn't scroll, even on screens where the data doesn't all fit
The ButtonBar floats on top of the onscreen keyboard, obscuring even more of the screen when the keyboard comes up.
Everything worked great when I had the buttons inside the ScrollView, but now that I have them in the ButtonBar I'm having a lot of trouble figuring this out.
It turned out that the solution required two steps:
The inability to scroll was a result of the ScrollView being behind the Button Bar. To fix this, I defined the ScrollView below the Button Bar, then used android:layout_above="#id/buttonbar_login" to force the ScrollView to reside entirely above the Button Bar.
Apparently when the onscreen keyboard is opened, if you have a ScrollView it will be resized allowing the Button Bar to float up with the keyboard. To fix this I modified the manifest and added android:windowSoftInputMode="adjustPan" to prevent the ScrollView from resizing.
If your use case supports hiding of the button bar in landscape orientation you can check Resources.getSystem().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE and set the button bar to View.GONE.
You also probably need to set android:windowSoftInputMode="adjustResize" on the <activity> in your manifest file. Android will only put it in adjustResize automatically when the root layout is a ScrollView (iirc).

Categories

Resources