Horizontal scroll swipe in a webview component inside Pageviewer in Android - android

I have a set of Viewpagers which i have implemented using the PageAdapters. In some of the Pages in the Pageviewer, i have webviews. The webviews has horizontal scrollers inside(Something similar to a Range selecter). When i try to drag some range, the page also gets swiped.
What exactly i need help is when i make any operation on a particular element/component in a webview, how can i avoid the pageviewer swiping and the operation inside the webview is accomplished.

You need to extend the Webview widget and override two methods as follows:
#Override
public boolean onInterceptTouchEvent(MotionEvent p_event)
{
return true;
}
#Override
public boolean onTouchEvent(MotionEvent p_event)
{
if (p_event.getAction() == MotionEvent.ACTION_MOVE && getParent() != null)
{
getParent().requestDisallowInterceptTouchEvent(true);
}
return super.onTouchEvent(p_event);
}

Related

Can I control when a swipe is allowed in a TabLayout/ViewPager app?

I'm doing some prototyping for my second app which will be using a TabLayout and ViewPager to display a series of 4 pages in a specific order so that the user can do a task in a logical manner. I will need to make sure that the user doesn't jump from an early page to a later page until the work on the early page is completed. Is that even possible in a TabLayout/ViewPager app?
All the examples I have seen so far demonstrate three tabs and show the user swiping effortlessly from one to the next and back again. None of the examples even HINT that it's possible to prevent swiping (or tabbing) to one of the other pages until a given condition is met. I need to understand if it's even POSSIBLE to limit swiping/tabbing in an app like this.
I would like the user to finish the "work" on the first page and then signal that he/she is done by clicking a NEXT button. The user should NOT be able to proceed to another page unless NEXT has been pressed. (The NEXT button is essentially the user's way of telling the app that he's finished with the first page.) By the same token, if a user is on one of the later pages, I don't want him to be able to go back to a prior page in most pages: I want to write program logic that decides if it's okay to take him back to a previous page based on what has happened so far.
Can I do what I'm proposing in Android Studio 3.1.4? If yes, what are the main classes/methods I will use to control the swiping and tabbing?
If this is NOT possible in Android, approach SHOULD I use to build my app?
Use Lockable View Pager to disable swipe in viewpager from user input touch
public class LockableViewPager extends ViewPager {
private boolean swipeLocked;
public LockableViewPager(Context context) {
super(context);
}
public LockableViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
public boolean getSwipeLocked() {
return swipeLocked;
}
public void setSwipeLocked(boolean swipeLocked) {
this.swipeLocked = swipeLocked;
}
#Override
public boolean onTouchEvent(MotionEvent event) {
return !swipeLocked && super.onTouchEvent(event);
}
#Override
public boolean onInterceptTouchEvent(MotionEvent event) {
return !swipeLocked && super.onInterceptTouchEvent(event);
}
#Override
public boolean canScrollHorizontally(int direction) {
return !swipeLocked && super.canScrollHorizontally(direction);
}
}
After setting up viewpager in Tablayout try below code for tablayout to disable tab switching on touch
LinearLayout tabStrip = ((LinearLayout)mTabLayout.getChildAt(0));
for(int i = 0; i < tabStrip.getChildCount(); i++) {
tabStrip.getChildAt(i).setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
return true;
}
});
}
Refer for tab touch selection disabling.
https://stackoverflow.com/a/37810306/3787344

Pass touch event from NestedScrollView to parent view's

I have a ViewPager below a NestedScrollView width some top padding, and clipToPadding(false) and transparent background (like as image).
My ViewPager can't get touch event and doesn't work.
How can I solve this problem?
(I can't change my structure and can't move ViewPager to above of NestedScrollView or set TopMargin to NestedScrollView)
NestedScrollView
nestedScrollView = new NestedScrollView(getContext());
nestedScrollView.setFillViewport(true);
nestedScrollView.setLayoutParams(scrollParams);
nestedScrollView.setClipToPadding(false);
Solution:
This Problem solved With overwriting NestedScrollView and Override onTouchEvent.
(Thanks to #petrumo)
public class MyNestedScrollView extends NestedScrollView {
private boolean topZone = false;
public MyNestedScrollView(Context context) {
super(context);
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
if(ev.getAction() == MotionEvent.ACTION_DOWN ){
topZone = (getPaddingTop() - getScrollY() > ev.getY());
}
if(topZone){
if(ev.getAction() == MotionEvent.ACTION_UP){
topZone = false;
}
return false;
}
return super.onTouchEvent(ev);
}
}
There is a workaround for this case, you can override onInterceptTouchEvent and onTouchEvent in the nestedscrollview. There are posts explaining how to do it, https://developer.android.com/training/gestures/viewgroup.html and http://neevek.net/posts/2013/10/13/implementing-onInterceptTouchEvent-and-onTouchEvent-for-ViewGroup.html. When you intercept the event, based on the position and your custom logic you would decide to not use the touch to leave it for the viewpager or let the default scrollview logic handle it.
I am not in favor of this solution, but as you explained you need to have the NestedScrollview cover the viewPager, unless you can reconsider the restrictions

Disable / Enable Scroll for ListView in android

I have a ListView inside ScrollView. I can enable scroll of ListView by
listView.getParent().requestDisallowInterCeptTouchEvent(true);
But the problem is when i scroll up in listView and it reaches top it should scroll to parent view i.e. parent scroll has to work . How can i do this ? any suggestion please.
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;
}
});
OR
To make the View unselectable just get the view and .setClickable(false)
OR
listView.setScrollContainer(false);
You can override ScrollView class and insert these methods inside:
private boolean isScrollEnabled = true;
public void enableScroll(boolean isScrollEnabled ) {
this.isScrollEnabled = isScrollEnabled ;
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (isScrollEnabled) {
return super.onInterceptTouchEvent(ev);
} else {
return false;
}
}
This is the cleanest solution to achieve this. You only call scrollView.enableScroll(true) to enable scrolling or scrollView.enableScroll(false) to disable it.
I would suggest to embed your upper view i.e any viewgroup above list view into listview header. ListView has a method, listview.addHeaderView(). That way you would be able to scroll your list (Whole View) even on small size display and you don't need scrollview.

Disable CoverFlow Scrolling until Popup Appears

I am using cover flow in my project and while display of cover flow on button click i am showing popup.
(Coverflow in android is the style to display images in line which is scrolled on touch as we generally see in media player and can be selected ;It's based on the Android Gallery widget and is used in the same way, with a ViewAdapter. My main aim when coding this coverflow widget was to create an easily re-usable component using the standard Android 2D libraries
reference :- http://www.inter-fuser.com/2010/01/android-coverflow-widget.html)
s
- now when popup is displayed i don't want my coverflow to
scroll/navigate on touch i.e i want to disable coverflow untill popup
is displayed
i have already tried all the code below but it is not help full to
disable coverflow.
coverFlow.clearFocus();
Popup.setFocusable(true);
coverFlow.setClickable(false);
coverFlow.setFocusable(false);
coverFlow.setEnabled(false);
coverFlow.setSelected(false);
can any one help me out in this matter ?
I don't know what source code of CoverFlow you are using. But you can custom it.
Extend the CoverFlow (which already extends Gallery, i think), override the onTouchEvent and onInterceptTouchEvent methods with return false if you don't want the CoverFlow scroll, and add the method to set this attribute.
The code maybe looks like :
#Override
public boolean onTouchEvent(MotionEvent event) {
if (this.enabled) {
return super.onTouchEvent(event);
}
return false;
}
#Override
public boolean onInterceptTouchEvent(MotionEvent event) {
if (this.enabled) {
return super.onInterceptTouchEvent(event);
}
return false;
}
public void setScrollEnabled(boolean enabled) {
this.enabled = enabled;
}
And then you can set the CoverFlow scroll or not by using setScrollEnabled method

Let parent View assume MotionEvents if child returns false

I have a application that need event handling on a unusual way.
For my question, let me first explain a simple case that the current event handling system of Android don't fits for me.
Supposing that I have a FrameLayout (that I'll call ViewSwiper since now) that all Views added on it are MATCH_PARENT X MATCH_PARENT (that I'll call PageView), it's handles events by translating the actual View and replace it based on the direction of moving.
This component I already have done and work properly ( Using Animation to swipe views ).
But the problem is on that PageView I add on top of it, in case of ImageViews that return false on it's onTouchEvent, the ViewSwiper will handle the events and let another PageView enter the screen, but if I add a ScrollView on that, all the events will be consumed by the Scroll and the ViewSwiper will not have chance to replace the PageView.
So I figured out that returning false onTouchEvent of the ScrollView the parent can assume it's events, I wrote this sub-class of ScrollView to test it:
public class ScrollViewVertical extends ScrollView {
public ScrollViewVertical(Context context) {
super(context);
setOverScrollMode(OVER_SCROLL_ALWAYS);
setVerticalScrollBarEnabled(false);
}
public boolean onTouchEvent(MotionEvent evt) {
super.onTouchEvent(evt);
return false;
}
}
But returning false make any further events to get dispatched to the parent, but I need these events for VERTICAL scrolling, so I have the idea to return falses only if the user are moving HORIZONTAL, that's what my code looks like:
public class ScrollViewVertical extends ScrollView {
private MovementTracker moveTracker;
public ScrollViewVertical(Context context) {
super(context);
setOverScrollMode(OVER_SCROLL_ALWAYS);
setVerticalScrollBarEnabled(false);
moveTracker = new MovementTracker();
}
public boolean onTouchEvent(MotionEvent evt) {
if (moveTracker.track(evt))
if (moveTracker.getDirection() == Direction.HORIZONTAL)
return false;
return super.onTouchEvent(evt);
}
}
PS: MovementTracker will returns true on track() after some events and tell on which direction the user is moving.
But in that case, the ScrollView keep receiving events since it's returns true on the first events.
Any ideas on how can I handle the events on ViewSwiper when it's child returns false (even if some trues are returned).
PS: I can give more info about this if needed, and accept different solutions also.
Based on answers I tried the following:
#Override
public boolean dispatchTouchEvent(MotionEvent ev) {
onTouchEvent(ev);
return intercept;
}
public boolean onTouchEvent(MotionEvent evt) {
boolean x = super.onTouchEvent(evt);
if (moveTracker.track(evt)) {
intercept = moveTracker.getDirection() != Direction.VERTICAL;
if (!intercept)
getParent().requestDisallowInterceptTouchEvent(false);
}
return x;
}
Still nothing.
try this in onTouchEvent() of the scrollview
//if (evt.getAction() == MotionEvent.ACTION_MOVE) {
if (moveTracker.track(evt)){
if (moveTracker.getDirection() == Direction.VERTICAL){
//Or the direction you want the scrollview keep moving
getParent().requestDisallowInterceptTouchEvent(true);
}
}
return true;
Update
Please try the following to the custom Scrollview
#Override
public boolean dispatchTouchEvent(MotionEvent ev) {
super.dispatchTouchEvent(ev);
return false;
}
And nothing else
This way i assume the MotionEvent will perform on both views. And since they don't conflict (One is vertical the other one is Horizontal) this could work
Based on the answer from weakwire, I came to the following solution:
On ViewSwiper
#Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if(!super.dispatchTouchEvent(ev))
onTouchEvent(ev);
return true;
}
And on ScrollHorizontal I return false on dispatchTouchEvent when I don't need then anymore.

Categories

Resources