Search code examples
androidscrollviewandroid-scrollview

Stopping a scroll view on specific locations on Android


My ultimate goal is to stop the scroll in specific locations, so the objects being viewed are shown completely, and the solution I came up with is by checking the scrollX location of the view when the touch is released. I did have a momentum issue, as the scroll could still continue due to the scroll velocity also after catching the touch event, I solved that using MotionEvent.ACTION_CANCEL, which I am not happy with, as the scrollTo is optically pleasing, but the MotionEvent.ACTION_CANCEL kills its effect.

My question is, is there a more elegant way to do this? Ideal would be if I could simply instruct my ScrollView NOT to have momentum/velocity.

    myView.setOnTouchListener(new HorizontalScrollView.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            if (event.getAction() == MotionEvent.ACTION_UP) {
                event.setAction(MotionEvent.ACTION_CANCEL);
                int x = myView.getScrollX();
                if (x < 150)
                    myView.scrollTo(0,0);
                else if (x<450)
                    myView.scrollTo(300,0);
                else
                    myView.scrollTo(600,0);
            }
            return false;
        }
    });

Solution

  • If you want to scroll precisely to show specific view, this answer should help you. What you have to do is to call myView.scrollTo(0, view.getBottom()) or myView.smoothScrollTo(0, view.getBottom()) on UI thread. This way, view object will be displayed fully.


    EDIT: It seems to me that what you're trying to achieve here is very close to what ViewPager does: your intention is to move between the views with a swipe/fling gesture, providing full visibility to the paged views contents.

    If you were to use ViewPager, this is how your code may have looked:

    viewPager.setAdapter(new PagerAdapter() {
    
                @Override
                public boolean isViewFromObject(View view, Object object) {
                    return view == object;
                }
    
                @Override
                public int getCount() {
                    return getViewCount();
                }
    
                @Override
                public Object instantiateItem(ViewGroup container, int position) {
                    View view = getViewAtPosition(position);
                    container.addView(view);
                    return view;
                }
    
                @Override
                public void destroyItem(ViewGroup container, int position, Object view) {
                    container.removeView((View) view);
                }
            });
    

    Where getViewCount() and getViewAtPosition() methods have to be implemented accordingly to how many displayed views you want and the way they are instantiated.