Lets say I have a ScrollView of LinearLayout (vertical) with a NumberPicker inside. In addition the LinearLayout does contain enough widgets so it scrolls.
Below is a sample XML code fragment:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<!-- Some widgets here so it scrolls -->
<NumberPicker
android:id="#+id/npSec"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
On Android 4.1.2 (Galaxy S3) it works great... You scroll the the layout and once scroll the NumberPicker - only the NumberPicker scrolls.
On the other hand, on Android 4.0.x the layout scrolls well, BUT when the NumberPicker tries to be scrolled it does something awkward like scroll half value and stop between the value; from there - only the LinearLayout get scrolled and the NumberPicker is stuck.
This guy asked the exactly the same question and didn't get any answer: NumberPicker on ScrollView doesn't scroll on Android 4.0.4
How disable ScrollView - This one won't do the job because both ScrollView and NumberPicker are vertical
I will really appreciate any good solution, or direction...
Thank you in advance,
Mark.
I know this is an old question, still...
This works for me:
numberPicker.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(final View v, final MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_MOVE && v.getParent() != null) {
v.getParent().requestDisallowInterceptTouchEvent(true);
}
if (event.getAction() == MotionEvent.ACTION_UP) {
v.performClick();
}
v.onTouchEvent(event);
return true;
}
});
Related
I have a VerticalViewPager whose Fragment content I want to scroll horizontally. The vertical paging works fine until the horizontal content is big enough to scroll. After that the touch events are not passed on to the ViewPager and so paging no longer works.
MVCE
This can be reproduced by setting up a simple project as given in this answer that I just posted.
Replace the fragment_one.xml file with
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true" >
<TextView
android:id="#+id/textview"
android:textSize="30sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</HorizontalScrollView>
</RelativeLayout>
and set the text to anything long enough to scroll horizontally.
Things I've tried
NestedScrollView: That quickly turned out to be a dead end since it is apparently not available for horizontal scrolling. I thought about converting the source code to a HorizontalNextedScrollView but that would not be a trivial project.
Custom HorizontalScrollView: I tried converting answers like this and this for horizontal scrolling, but was unsuccessful. I'm going to continue experimenting in this area.
This is not a DoubleViewPager but I feel like the solution should be similar.
In order to answer this and other similar questions, it is very helpful to understand how the Android Framework handles touch events. My fuller answer on that is here, but I will include the summary diagram below.
The HorizontalScrollView (ViewGroup B in the diagram) is handling all touch events before the VerticalViewPager (ViewGroup A) has a chance to. So the solution is to use onInterceptTouchEvent() in the VerticalViewPager to selectively filter out vertical scrolls. For that it is easiest to just use a GestureDetector.SimpleOnGestureListener.onScroll().
Here are the relevant changes you need to make to the VerticalViewPager class to accomplish that:
public class VerticalViewPager extends ViewPager {
GestureDetector mDetector;
private void init() {
// ...
mDetector = new GestureDetector(getContext(), new VerticalScrollListener());
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
super.onInterceptTouchEvent(flipXY(ev));
flipXY(ev);
return mDetector.onTouchEvent(ev);
}
class VerticalScrollListener extends GestureDetector.SimpleOnGestureListener {
#Override
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
return Math.abs(distanceY) > Math.abs(distanceX);
}
}
}
I have two listViews in the same LinearLayout. Each listView looks like this:
<ListView
android:layout_width="fill_parent"
android:layout_height="0dp"
android:id="#+id/listViewReceived"
android:layout_weight="1"
>
</ListView>
<ListView ><!--same as above-->
The issue is that the two listViews have a scrollbar but I want show all the items without a scrollbar.
if I make scrolling in anyone the listviews the movement is generated internally. but I want show scrollbar in entire the screen. how the green bar. https://drive.google.com/file/d/0B_Z2NZi-dbUMc3FCOTQ1UDNWRnM/view
issue is that the two listView have your scrollbar but I want show all the items without scrollbar.
Add this to all of the listview
android:scrollbars="none"
android:scrollbars=none will define which scrollbars to display or show any at all. This won’t disable scrolling as such (you’ll be able to scroll in the appropriate direction) but just hide the scrollbars from the user interface. Try Following Code
listView.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_MOVE) {
return true; // Indicates that this has been handled by you and will not be forwarded further.
}
return false;
}
});
I am new to android development and I am stuck upon following problem. I have been working hard for days and not able to find a solution. In this question I am explaining what steps that I have exactly taken to implement. Please have a look at my procedure and either suggest a solution or an improvisation or an alternative way through which this can be handled.
I want to design a screen which is divided into three parts. The structure of my screen is as follows :
The parent layout of the whole screen is a Scroll-View. The rough structure of the layout file is :
<ScrollView>
<!-- Other Views (Part: 1) -->
<RelativeLayout>
<!-- Part 2 -->
<LinearLayout android:orientation = "vertical">
<LinearLayout android:orientation = "horizontal">
<Button1 /> <Button1 /> </Button3>
</LinearLayout>
<LinearLayout android:orientation = "horizontal">
<Button4 /> <Button5 /> </Button6>
</LinearLayout>
</LinearLayout>
<ImageView>
</RelativeLayout>
<!--Other Views (Part 3) -->
</ScrollView>
The part of interest is the middle part that is the Relative layout. The Things that I want to
Implement is that :
I want to detect a swipe on this RelativeLayout. So with every swipe to either Left or
Right I update the the images and the text that is there on these buttons.
I want to be able to scroll the screen from anywhere on the screen.
To be able to click on the buttons.
Now let me tell you what I have done and the problems that I am facing. To detect the swipe on the relative layout I have set an onTouchListener on the relative layout. The overridden onTouch method is :
public boolean onTouch(View v, MotionEvent event) {
scrollview.requestDisallowInterceptTouchEvent(true);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
downX = event.getX();
downY = event.getY();
return true;
}
case MotionEvent.ACTION_UP: {
if(v instanceof Button){
v.performClick();
}
upX = event.getX();
upY = event.getY();
float deltaX = downX - upX;
float deltaY = downY - upY;
// swipe horizontal?
if (Math.abs(deltaX) > MIN_DISTANCE) {
// left or right
if (deltaX < 0) {
this.onLeftToRightSwipe();
return true;
}
if (deltaX > 0) {
this.onRightToLeftSwipe();
return true;
}
}
}
}
return false;
}
Since , the buttons occupy all the space on the relative layout , I had to set this Listener on
all the inner Linear Layouts and Buttons. To detect the button click and disallow the scroll view to intercept I had to include scrollview.requestDisallowInterceptTouchEvent(true) .
But the problem is that now I am not able to scroll on this Relative layout.
The Swipe and Button clicks are working exactly as they should but , now it is not detecting the scroll.
If I remove the scrollview.requestDisallowInterceptTouchEvent(true) , the scroll is detected but the swipe is not . This is giving a very bad user experience and overall a negative feedback from all of those to who I have shown the application.
So what i want is that , user should be able to scroll from any point of the screen plus he should be able to swipe on the relative layout and also be able to click on the buttons.
Please Help! Could the possible solutions be like :
1) implementing a simpleOnGesture Listener or Detector? override fling event? Please provide valuable and useful pointers.
I suggest you to use ViewPager to accomplish this. You can learn more about ViewPagers from this link: http://developer.android.com/training/animation/screen-slide.html
And there is also a sample code in the website that you can see how it works. It allows you to swipe through pages and also scroll down in each page.
So the main.xml file looks like this:
<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
And the fragment.xml file looks like this:
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView android:id="#android:id/text1"
style="?android:textAppearanceLarge"
android:textStyle="bold"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp" />
<TextView style="?android:textAppearanceMedium"
android:lineSpacingMultiplier="1.2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/lorem_ipsum" />
</LinearLayout>
</ScrollView>
I have to add pull-to-refresh functionality to refresh info on main screen. Here`s a scheme of my screen UI (red area should handle pulling):
I use ready solution for pull-to-refresh. Due to documentation, my red layout should be one of these classes:
ListView
ExpandableListView
GridView
WebView
ScrollView
HorizontalScrollView
ViewPager
But I have ListView on my screen, so I am not able to use ScrollView as red layout. And I`m stuck with this problem. It is possible to use UITableView into UIScrollView in iOS, but in Android one I have no idea what to do in such cases.
Any help will be appreciated. Thanks!
Why not replace the listview by a LinearLayout and then you can use the ScrollView?
You just need to create a layout for the items in the linearlayout and then adding them using something like this:
LinearLayout layout = (LinearLayout)findViewById(R.id.MyListLayout);
for (int i=0; i<list.size(); i++) {
Item item = list.get(i);
View view = inflater.inflate(R.layout.MyRowLayout, null);
Textview myTextView = view.findViewById(R.id.MyTextView);
myTextView.setText(item.getString());
list.addView(vi);
}
Is the pull-to-refresh horizontal or vertical?
In case it's horizontal, use a HorizontalScrollView (a ViewPager would do, too), and then place a Table?Layout inside it.
In case it's horizontal, well, I don't think I like that design (the pull-to-refresh area should just be the ListView), but I believe there is some way to use the ListView without its internal scrolling so that you can rely on a parent ScrollView to do the scrolling, but I'd need to check the code of an old problem to "remember" how to do that.
I've solved this issue, but forgot to write about it :)
My layout.xml file looks like this:
<com.handmark.pulltorefresh.library.PullToRefreshScrollView
android:id="#+id/home_info_pulltorefresh"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true" >
<LinearLayout
android:id="#+id/home_info_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/white_background"
android:baselineAligned="false"
android:orientation="horizontal" >
<LinearLayout
android:id="#+id/charts_container"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2"
android:orientation="vertical"
android:paddingRight="5dp" >
<FrameLayout
android:id="#+id/frame_container_chart_top"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<FrameLayout
android:id="#+id/frame_container_chart_bottom"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>
<FrameLayout
android:id="#+id/frame_container_right"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
</LinearLayout>
</com.handmark.pulltorefresh.library.PullToRefreshScrollView>
android:fillViewport="true" is used to stretch its content to fill the viewport (make height of scroll match_parent)
I add Fragment containing ListView programmatically (R.layout.frame_container_right Fragment resource ID)
Everything worked fine, but when I tried to scroll ListView down, my ScrollView began to scroll. Scrolling ListView up worked fine. Also I noticed that if I tap ListView, move finger left or right and then try to scroll down, touch events are not transmitted from ListView to ScrollView and I get expected behavior. So I've decided to emulate this situation programmatically:
mListViewReviews.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
long startTime = SystemClock.uptimeMillis();
long duration = 1;
MotionEvent e = MotionEvent.obtain(startTime, startTime + duration, MotionEvent.ACTION_MOVE, event
.getX(), event.getY() + 10, 0);
MotionEvent ev = MotionEvent.obtain(startTime + duration, startTime + duration * 2,
MotionEvent.ACTION_MOVE, event.getX(), event.getY() + 20, 0);
v.dispatchTouchEvent(e);
v.dispatchTouchEvent(ev);
}
return false;
}
});
As a result, I've got working ListView with proper cell reuse and working pull-to-refresh logic. Thanks!
I'd like to create a layout width GridView that takes the whole screen (fill_parent for both width and height).
Number of columns is X, number of rows is Y (filled with own adapter, extending BaseAdapter).
What I don't want is scrolling. I'd like to have all items visible, no vertical scroll bar.
Thanks in advance.
Try to set the following OnTouchListener:
gridView.setOnTouchListener(new OnTouchListener(){
public boolean onTouch(View v, MotionEvent event) {
return event.getAction() == MotionEvent.ACTION_MOVE);
}
});
set attribute android:scrollingCache="false" in your GridView
<ListView android:id="#+id/android:list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scrollingCache="false"
android:layout_weight="1" />
..maybe:
mKeypadGrid.setEnabled(false);
will solve your problem. It disabled scroll but other functionality I need was working. Not sure if it will fit to your needs.. Cheers