0

I have a viewpager with webviews that can potentially scroll left and right. The user can have unsaved data, in which case i want to disable the viewpager, and if the user attempts to scroll off the page, i want to show an unsaved dialog window.

I looked at this solution but it's not quite what i need. Since always returning true will disable my fragment's webview from scrolling also.

public class CustomViewPager extends ViewPager {

private boolean isPagingEnabled = true;

public CustomViewPager(Context context) {
    super(context);
}

public CustomViewPager(Context context, AttributeSet attrs) {
    super(context, attrs);
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    return this.isPagingEnabled && super.onTouchEvent(event);
}

@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
    return this.isPagingEnabled && super.onInterceptTouchEvent(event);
}

public void setPagingEnabled(boolean b) {
    this.isPagingEnabled = b;
}
}

Currently, i have a custom webview, where i override onTouch, and check if i can scroll horizontally. I have a method which checks if my webview can scroll left or right. Which seems to work correctly.

    public boolean canScrollHorizontally(int direction){
        final int offset = computeHorizontalScrollOffset();
        final int range = computeHorizontalScrollRange() -computeHorizontalScrollExtent();
        if (range == 0) return false;
        if (direction < 0) {
            return offset > 0;
        } else {
            return offset < range - 1;
        }
}

And an ontouch listener on my webview, which i believe is working correctly? If I return true if the user attempts to drag left and the view has space to drag. If not, i return false, which hopefully will pass the event back to the viewpager.

    public boolean onTouchEvent(MotionEvent event) {
    float x;
    float y;
    x = event.getX();
    y = event.getY();
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            mStartDragX = x;
            mStartDragY = y;
            break;
        case MotionEvent.ACTION_MOVE:
                if(Math.abs(mStartDragX - ev.getX()) > SWIPE_MIN_DISTANCE){

                if (mStartDragX < x && canScrollHorizontally(-1)) {
                    // Left to Right
                    return true;
                } else if(mStartDragX > x && canScrollHorizontally(1)){
                    // Right to Left
                    return true;
                }else{
                    // pass to viewpager?
                    return false;
                }
         }
    }
    return super.onTouchEvent(event);
}

My ontouch event for my viewpager is where i get a little lost, If the Pager is disabled. I want to display a dialog to the user.

@Override
public boolean onTouchEvent(MotionEvent ev) {
    float x;
    float y;
    if(this.enabled) {
        return super.onTouchEvent(ev);
    } else{
        x = ev.getX();
        y = ev.getY();
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mStartDragX = x;
                mStartDragY = y;
                break;
            case MotionEvent.ACTION_MOVE:
                if(Math.abs(mStartDragX - ev.getX()) > SWIPE_MIN_DISTANCE){
                    showDialog()??
                }
        }
    }
    return true;
}

Can someone suggest the best way to do this?

Community
  • 1
  • 1
android_student
  • 1,246
  • 1
  • 13
  • 32

1 Answers1

0

One possible way you could accomplish this would be to change the state of the PagerAdapter driving the ViewPager so that it says there is only one view -- the view that is locked. When unlocking, you would roll back the PagerAdapter to have all the views. The trick to making this work would be a careful implementation of getItemPosition() so that web page you're locking isn't removed and added back again.

For example:

public void setLocked(boolean isLocked) {
    mIsLocked = isLocked;
    notifyDataSetChanged();
}

@Override
public int getCount() {
    return mIsLocked ? 1 : mViews.size();
}

I had a situation once where the addition/removal/reordering of views was so complex I ended up writing a complete PagerAdapter implementation.

kris larson
  • 30,387
  • 5
  • 62
  • 74
  • Hmm... this could possibly work! I never thought of doing it that way. However, I would still need to detect when the user attempts to swipe the viewpager, and then pop up a dialog asking them if they want to save their data before moving on. Perhaps, i could have some combination of ontouchevents and your solution? I'll have to think that over some more tonight. Thanks for the suggestion! – android_student Mar 09 '15 at 04:46
  • 1
    Think about how Google UIs work, for instance GMail deleting a message or Chrome closing a tab. Rather than pop an "Are you sure?" dialog, their preference is to let you do it and provide an undo button. Also think about the Contextual Action Bar, how selecting a message actually puts you into a different mode. Based on that, you might consider displaying Save/Discard buttons once the user starts making changes that lock the swipe. Once the Save or Discard button is pressed, the swipe would be unlocked. Then you wouldn't need to detect the swipe attempt when locked. – kris larson Mar 09 '15 at 14:54
  • However, if you were set on using a dialog for this, you may not even have to involve the PagerAdapter. The ViewPager has some logic that looks at the view being swiped and determines if there is a widget that can respond to the horizontal scroll and if so, defers the swipe events to that widget. So another approach might be to activate a transparent HorizontalScrollView over the top of your WebView that has onScrollChanged() overridden to detect the swipe. Kind of an ugly hack, but that requirement to allow the WebView to scroll while shutting off the ViewPager requires some tricky code. – kris larson Mar 09 '15 at 15:03