10

I've just started writing a custom view in Android (for the first time) and I've realised that I need to implement a scrolling feature.

The custom view also uses a header containing some text (which should stay fixed and not scroll).

I've read through the documentation on GestureDetector.SimpleOnGestureListener and Scroller. I also read the documentation on Animating a Scroll Gesture but I found the examples difficult to understand. I've also looked at other questions on Stack Overflow which helped a little.

Using what I understood from the documentation with the Stack Overflow answer as a reference to guide me, I have added the following to my custom view:

Variables and fields:

private OverScroller mScroller; private final GestureDetector mGestureDetector = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() { @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { // Note 0 as the x-distance to prevent horizontal scrolling scrollBy(0, (int) distanceY); return true; } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { final int maxScrollX = 0; // wholeViewHeight is height of everything that is drawn int wholeViewHeight = calculateWholeHeight(); int visibleHeight = getHeight(); final int maxScrollY = wholeViewHeight - visibleHeight; mScroller.forceFinished(true); mScroller.fling(0, // No startX as there is no horizontal scrolling getScrollY(), 0, // No velocityX as there is no horizontal scrolling - (int) velocityY, 0, maxScrollX, 0, maxScrollY); invalidate(); return true; } @Override public boolean onDown(MotionEvent e) { if (!mScroller.isFinished()) { mScroller.forceFinished(true); } return true; } }); 

Initialization of mScroller:

// Called from the constructor private void init() { mScroller = new OverScroller(getContext(), new FastOutLinearInInterpolator()); ... } 

Stuff in onDraw():

@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); ... if (mScroller.computeScrollOffset()) { scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); } } 

Stuff in onTouchEvent():

@Override public boolean onTouchEvent(MotionEvent event) { return mGestureDetector.onTouchEvent(event); } 

The result of these additions is a custom view which can scroll vertically (and not horizontally), however there are a few issues:

  1. I can scroll further past what is drawn
  2. There is no edge glow effect as I reach the end of the custom view (I mean like a RecyclerView or ScrollView)
  3. All of the custom view scrolls as opposed to just a certain part of it
  4. I don't fully understand what is going on

Could someone explain how scrolling works in a custom view and how to implement it properly with these features?

3
  • 1
    Hello, Farbod Salamat-Zadeh. Have you found any solution for this? I am also stuck on the same problem i.e; "I can scroll further past what is drawn" Commented Oct 4, 2016 at 12:08
  • @AdeelShahzad Not yet. If you come up with a solution do let me know though. :) Commented Oct 4, 2016 at 12:10
  • Hi, Farbod. I couldn't come up with a solution so I just threw a ScrollView inside a ViewPager. Commented Nov 16, 2016 at 8:43

1 Answer 1

5

May I offer a simple layout that has a fixed header and vertically scrolling content that sounds like it will do what you want and does not require complex programming? It may save you from having to spend hours of research and programming in the long run:

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <FrameLayout android:id="@+id/header" android:layout_width="match_parent" android:layout_height="wrap_content"/> <android.support.v4.widget.NestedScrollView android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:fillViewport="true"> <FrameLayout android:id="@+id/scrolling_content" android:layout_width="match_parent" android:layout_height="wrap_content"/> </android.support.v4.widget.NestedScrollView> </LinearLayout> 

Using this layout, you would replace or insert inside the FrameLayout with ID "header" with your fixed header view. You would then put your scolling content inside of the FrameLayout with ID "scrolling_content". The NestedScrollingView would be located directly below your fixed header and automatically give you the scrolling behavior you want without any further code.

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks for your answer. Would I be able to replace the second FrameLayout with part of my custom view to enable it to scroll?
Yes, but remember NestedScrollView can only have one direct child. As long as you don't try to put 2 views directly into NestedScrollView it will work fine. Also remember that any views inside a vertically scrolling NestedScrollView cannot have a layout_height of "match_parent", as if this value were honored it would create an infinitely long scroll.
Thanks for the clarification. I'll try using a NestedScrollView and see how that works for me. However, I would still like to know how it can be implemented (using GestureDetector, OverScroller, etc.) for a custom View. I've started a bounty for this, so if you have an alternative answer, do post it. :)
Thanks, will see if I come up with anything.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.