Fragment using ScrollView inside RelativeLayout > ontouch doesn't work - android

I have been trying to find a solution for this for hours and it feels like I searched every question on stackoverflow and tried everything in the layout.
Before I tried the layout displayed below, the edittext and the two imagebuttons were inside the scrollview. In this old layout the ontouch worked perfectly in my fragment, however once I pulled out the relative layout with the edittext and the two image buttons the ontouch was not fired. Can someone help me with this problem? Any help is appreciated. Thanks
View fragmentView = inflater.inflate(R.layout.request, container, false);
fragmentView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
}
}
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#BDCCE0" >
<EditText
android:id="#+id/etsearch"
android:layout_width="210dp"
android:layout_height="wrap_content"
android:layout_marginLeft="6dp"
android:layout_marginTop="10dp"
android:hint="search..."
android:singleLine="true"
android:imeOptions="actionDone" />
<ImageButton
android:id="#+id/bsearch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#+id/etsearch"
android:layout_marginTop="9dp"
android:src="#drawable/search" />
<ImageButton
android:id="#+id/bupdaterequests"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_toRightOf="#id/bsearch"
android:layout_marginTop="9dp"
android:src="#drawable/refresh" />
<ScrollView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:fillViewport="true"
android:background="#BDCCE0"
android:layout_below="#id/etsearch" >
<TableLayout
android:id="#+id/myTableLayout"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
</TableLayout>
</ScrollView>
</RelativeLayout>

A TouchEvent starts at the "highest" element and trickles "down" the View hierarchy until it is consumed by some event. In this case the ScrollView, Buttons, or EditText all consume the event before it reaches the RelativeLayout...
basically I only want to that when someone touches outside the edit text the keyboard disappears.
I addressed this by simply making the root layout clickable and focusable.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
android:focusable="true"
android:focusableInTouchMode="true" >

android:clickable="true" resolved the issue..

Related

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 shrink when soft keyboard is shown

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());
}
});

getLayoutParams for LinearLayout under ScrollView not working

I have a LinearLayout and I controlled the height of this layout using getLayoutParams previously and it was working beautifully. Now I want the layout to be scrollable so I placed it under a ScrollView. Now for some reason the getLayoutParams stopped working. I seem to have come to a dead end trying to resolve this. Please help.
Here is my code
if(subHistories.getLayoutParams().height==0)
(subHistories.getLayoutParams()).height=ViewGroup.LayoutParams.WRAP_CONTENT;
else
(subHistories.getLayoutParams()).height=0;
Here subHistories is the layout object I want to control the height for. I want it to switch it's height from zero to wrap_content on every onClick event
And here is the relevant xml code:
...<ScrollView
android:id="#+id/left"
android:layout_width="200dp"
android:layout_height="fill_parent"
android:orientation="vertical"
android:layout_below="#id/head"
android:animateLayoutChanges="true">
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<TextView
android:id="#+id/historyBut"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:background="#5261a5"
android:paddingBottom="5dp"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:paddingTop="5dp"
android:text="Historical Places"
android:textAllCaps="false"
android:textSize="20sp"
android:typeface="normal" />
<!-- historical places category -->
<LinearLayout
android:id="#+id/histories"
android:layout_marginLeft="10dp"
android:layout_width="match_parent"
android:layout_height="0dp"
android:orientation="vertical"
android:animateLayoutChanges="true" >...
After touching layout params, call requestLayout() for the changes to take effect.
For hiding/showing a layout, consider using setVisibility() with GONE and VISIBLE instead.

Add vertical scrolling to a section of android viewPager

I have a viewPager that I populate using a FragmentStatePagerAdapter. It works fine, can go through populated pages horizontally.
However the middle section of each page on the viewPager is made up of a listView. This listview will sometimes not fit into the designated area, I need to be able to scoll vertically. But I cannot scroll vertically on this section of the viewPager at the moment.
It looks like the viewPager is consuming all the scroll events (both horizontal and vertical).
I do not want a vertical viewPager; I have seen a few answers to that on StackOverflow.
I want only the section in the middle of the viewPager to scroll vertical, and this section is a listView
This is the mainlayout for the tab with a viewPager:
<LinearLayout
android:id="#+id/history"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:background="#color/fdi_gray">
<android.support.v4.view.ViewPager
android:id="#+id/historyFragment_container"
android:layout_weight="0.85"
android:layout_width="fill_parent"
android:layout_height="0dip"/>
<include layout="#layout/page_indicator_history"
android:layout_height="0dip"
android:layout_width="fill_parent"
android:layout_weight="0.05"
android:background="#color/darker_gray"
android:layout_marginTop="2dp"/>
</LinearLayout>
And the layout out that is used by the ViewPager adapter to populate above viewPager is this:
<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:id="#+id/spaceHolderLocations">
<TextView
android:id="#+id/locationName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_marginTop="10dp"
android:layout_centerHorizontal="true"
android:textStyle="bold"
android:textSize="17sp"/>
<TextView
android:id="#+id/latlon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_below="#+id/locationName"
android:layout_marginTop="2dp"
android:layout_marginBottom="3dp"
android:layout_centerHorizontal="true"/>
<View
android:id="#+id/listViewStart"
android:layout_width="match_parent"
android:layout_height="0.5dip"
android:layout_marginLeft="3dp"
android:layout_marginRight="3dp"
android:layout_below="#+id/latlon"
android:background="#color/white" />
<ListView
android:id="#android:id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/fdi_gray"
android:layout_below="#+id/listViewStart"
android:layout_marginLeft="3dp"
android:layout_marginRight="3dp"
android:divider="#color/white"
android:dividerHeight="0.5dip"
android:padding="1dp">
</ListView>
<View
android:id="#+id/listViewEnd"
android:layout_width="match_parent"
android:layout_height="0.5dip"
android:layout_marginLeft="3dp"
android:layout_marginRight="3dp"
android:layout_below="#android:id/list"
android:background="#color/white" />
<TextView
android:id="#+id/curingLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/listViewEnd"
android:gravity="center"
android:text="#string/curingLabel"
android:layout_marginTop="10dp"
android:layout_marginLeft="30dp"
android:textSize="17sp"/>
<TextView
android:id="#+id/curingValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#+id/curingLabel"
android:layout_marginLeft="30dp"
android:layout_alignBottom="#+id/curingLabel"
android:textStyle="bold"
android:textSize="17sp"/>
Please note the listview in the above layout.
That's the section of the ViewPager that I want to be able to scroll on; but cannot, I can only scroll horizontally through the pages not vertically through the listView content if it doesn’t fit the page.
This question came close but it's not what I'm looking for: link
Thanks.
Implement the following functionality. I hope it helps you.
mList = (ListView) findViewById(R.id.list);
mList.setOnTouchListener(new View.OnTouchListener () {
#Override
public boolean onTouch(View v, MotionEvent event) {
mList.getParent().requestDisallowInterceptTouchEvent(true);
return false;
}
});
When a touch event occurs, parent always get to intercept the event. Here the parent is View Pager. What you are trying to do here is, when a touch on list view appears, request the parent not to intercept the touch event. This way, the touch event will be received by the Child, which here is ListView, and thus scrolls accordingly.
Basically you cannot set the height of your list view to be "wrap content". give a fixed height, or choose a different layout like linearlayout and set its weight to 1 will be another solution. if you set it to wrap content, it will just take all the space and go beyond the screen.

How to consume child view's touch event in parent view's touchlistener?

In my application I want to get the touch event of all child view's in my parent view's onTouchListener but I could not get this.
Example:
In my activity's view I have one frame layout which has some buttons and edittexts in it. So whenever I touch buttons or edit text I want to get this touch event in framlayout's onTouchListeners.
Here is my code..
Activity:
private FrameLayout rootView;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
rootView = (FrameLayout) findViewById(R.id.rootview);
rootView.setOnTouchListener(new OnTouchListener()
{
#Override
public boolean onTouch(View v, MotionEvent event)
{
Log.e("Touch Event: ", " X: " + event.getX() + " Y: " + event.getY());
return false;
}
});
}
main.xml:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="10dip"
android:id="#+id/rootview">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#android:color/white"
android:orientation="vertical"
android:layout_gravity="center"
android:padding="10dip">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:padding="4dp"
android:text="Login"
android:textColor="#android:color/black"
android:textSize="16dp"
android:textStyle="bold" />
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="Username"
android:textColor="#android:color/black"
android:textSize="14dp"
android:textStyle="bold" />
<EditText
android:id="#+id/edttextusername"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:imeOptions="flagNoExtractUi"
android:singleLine="true" />
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="Password"
android:textColor="#android:color/black"
android:textSize="14dp"
android:textStyle="bold" />
<EditText
android:id="#+id/edttextpassword"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:imeOptions="flagNoExtractUi"
android:password="true" />
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:orientation="horizontal"
android:padding="10dp" >
<Button
android:id="#+id/btnlogin"
android:layout_width="0dip"
android:layout_height="40dip"
android:layout_marginRight="5dp"
android:layout_weight="1"
android:enabled="false"
android:text="Login"
android:padding="5dip"
android:textColor="#android:color/black"
android:textStyle="bold"
/>
<Button
android:id="#+id/btncall"
android:layout_width="0dip"
android:layout_height="40dip"
android:layout_marginLeft="5dp"
android:layout_weight="1"
android:padding="5dip"
android:text="Cancel"
android:textColor="#android:color/black"
android:textStyle="bold" />
</LinearLayout>
</LinearLayout>
</FrameLayout>
Problem: So whenver I touch the buttons or edittext I can't get touch co-ordition in my frame layout's onTouchListener (It's not called).
Note: I don't want to add separate onTouchListener for all childViews.
Thanks in advance.
You could accomplish that by overriding dispatchTouchEvent in the layout.
public class MyFrameLayout extends FrameLayout {
#Override
public boolean dispatchTouchEvent(MotionEvent e) {
// do what you need to with the event, and then...
return super.dispatchTouchEvent(e);
}
}
Then use that layout in place of the usual FrameLayout:
<com.example.android.MyFrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="10dip"
android:id="#+id/rootview">
...
You could also skip the super call entirely if you need to prevent child views from receiving the event, but I think this would be rare. If you need to recreate some, but not all, of the default functionality, there is a lot to rewrite:
http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.1.1_r1/android/view/ViewGroup.java#ViewGroup.dispatchTouchEvent%28android.view.MotionEvent%29
I have tried similar design with (only one onTouch Listener on a root FrameLayout) and it worked. I get all the points provided that onTouch return true instead of false. Otherwise, I just get the first point. I couldn't find out the reason for this "return" issue since I expect opposite behaviour.
However, based on my experience, if you set any of child view clickable, then its parent's onTouch will not work. If you have another solution and if you share, that would be great.
2 solutions:
Use onInterceptTouchEvent on the ViewGroup, as shown here
Avoid having the layout handle the touch events, and have a view that is the child view of the layout, that covers its whole size, to handle the touch events.
It's not as efficient as extending classes, but it is much easier and doesn't require to create new files/classes.
example:
Just add the touch events to the view, and it will handle them instead of any of the other views.
It can be achieved by using "onInterceptTouchEvent". Please try this,it may work
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
onTouchEvent(ev);
return false;
}

Categories

Resources