Added OverscrollLinearLayoutManager to fix scrolling in AppDetails2
This commit is contained in:
parent
343e91280a
commit
03a8151875
@ -13,6 +13,7 @@ import android.graphics.Bitmap;
|
|||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.support.design.widget.AppBarLayout;
|
||||||
import android.support.design.widget.CoordinatorLayout;
|
import android.support.design.widget.CoordinatorLayout;
|
||||||
import android.support.v4.content.LocalBroadcastManager;
|
import android.support.v4.content.LocalBroadcastManager;
|
||||||
import android.support.v7.app.AlertDialog;
|
import android.support.v7.app.AlertDialog;
|
||||||
@ -46,6 +47,7 @@ import org.fdroid.fdroid.installer.InstallerService;
|
|||||||
import org.fdroid.fdroid.net.Downloader;
|
import org.fdroid.fdroid.net.Downloader;
|
||||||
import org.fdroid.fdroid.net.DownloaderService;
|
import org.fdroid.fdroid.net.DownloaderService;
|
||||||
import org.fdroid.fdroid.views.AppDetailsRecyclerViewAdapter;
|
import org.fdroid.fdroid.views.AppDetailsRecyclerViewAdapter;
|
||||||
|
import org.fdroid.fdroid.views.OverscrollLinearLayoutManager;
|
||||||
import org.fdroid.fdroid.views.ShareChooserDialog;
|
import org.fdroid.fdroid.views.ShareChooserDialog;
|
||||||
import org.fdroid.fdroid.views.apps.FeatureImage;
|
import org.fdroid.fdroid.views.apps.FeatureImage;
|
||||||
|
|
||||||
@ -59,6 +61,8 @@ public class AppDetails2 extends AppCompatActivity implements ShareChooserDialog
|
|||||||
|
|
||||||
private FDroidApp fdroidApp;
|
private FDroidApp fdroidApp;
|
||||||
private App app;
|
private App app;
|
||||||
|
private CoordinatorLayout coordinatorLayout;
|
||||||
|
private AppBarLayout appBarLayout;
|
||||||
private RecyclerView recyclerView;
|
private RecyclerView recyclerView;
|
||||||
private AppDetailsRecyclerViewAdapter adapter;
|
private AppDetailsRecyclerViewAdapter adapter;
|
||||||
private LocalBroadcastManager localBroadcastManager;
|
private LocalBroadcastManager localBroadcastManager;
|
||||||
@ -91,10 +95,42 @@ public class AppDetails2 extends AppCompatActivity implements ShareChooserDialog
|
|||||||
|
|
||||||
localBroadcastManager = LocalBroadcastManager.getInstance(this);
|
localBroadcastManager = LocalBroadcastManager.getInstance(this);
|
||||||
|
|
||||||
|
coordinatorLayout = (CoordinatorLayout) findViewById(R.id.rootCoordinator);
|
||||||
|
appBarLayout = (AppBarLayout) coordinatorLayout.findViewById(R.id.app_bar);
|
||||||
recyclerView = (RecyclerView) findViewById(R.id.rvDetails);
|
recyclerView = (RecyclerView) findViewById(R.id.rvDetails);
|
||||||
adapter = new AppDetailsRecyclerViewAdapter(this, app, this);
|
adapter = new AppDetailsRecyclerViewAdapter(this, app, this);
|
||||||
LinearLayoutManager lm = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
|
OverscrollLinearLayoutManager lm = new OverscrollLinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
|
||||||
lm.setStackFromEnd(false);
|
lm.setStackFromEnd(false);
|
||||||
|
|
||||||
|
/** The recyclerView/AppBarLayout combo has a bug that prevents a "fling" from the bottom
|
||||||
|
* to continue all the way to the top by expanding the AppBarLayout. It will instead stop
|
||||||
|
* with the app bar in a collapsed state. See here: https://code.google.com/p/android/issues/detail?id=177729
|
||||||
|
* Not sure this is the exact issue, but it is true that while in a fling the RecyclerView will
|
||||||
|
* consume the scroll events quietly, without calling the nested scrolling mechanism.
|
||||||
|
* We fix this behavior by using an OverscrollLinearLayoutManager that will give us information
|
||||||
|
* of overscroll, i.e. when we have not consumed all of a scroll event, and use this information
|
||||||
|
* to send the scroll to the app bar layout so that it will expand itself.
|
||||||
|
*/
|
||||||
|
lm.setOnOverscrollListener(new OverscrollLinearLayoutManager.OnOverscrollListener() {
|
||||||
|
@Override
|
||||||
|
public int onOverscrollX(int overscroll) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int onOverscrollY(int overscroll) {
|
||||||
|
int consumed = 0;
|
||||||
|
if (overscroll < 0) {
|
||||||
|
CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
|
||||||
|
CoordinatorLayout.Behavior behavior = lp.getBehavior();
|
||||||
|
if (behavior != null && behavior instanceof AppBarLayout.Behavior) {
|
||||||
|
((AppBarLayout.Behavior) behavior).onNestedScroll(coordinatorLayout, appBarLayout, recyclerView, 0, 0, 0, overscroll);
|
||||||
|
consumed = overscroll; // Consume all of it!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
});
|
||||||
recyclerView.setLayoutManager(lm);
|
recyclerView.setLayoutManager(lm);
|
||||||
recyclerView.setAdapter(adapter);
|
recyclerView.setAdapter(adapter);
|
||||||
|
|
||||||
|
@ -0,0 +1,91 @@
|
|||||||
|
package org.fdroid.fdroid.views;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.support.v7.widget.LinearLayoutManager;
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is like a standard LinearLayoutManager but with an option to add an
|
||||||
|
* overscroll listener. This can be used to consume overscrolls, e.g. to draw custom
|
||||||
|
* "glows".
|
||||||
|
*/
|
||||||
|
public class OverscrollLinearLayoutManager extends LinearLayoutManager {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A listener interface to get overscroll infromation.
|
||||||
|
*/
|
||||||
|
public interface OnOverscrollListener {
|
||||||
|
/**
|
||||||
|
* Notifies the listener that an overscroll has happened in the x direction.
|
||||||
|
* @param overscroll If negative, the recycler view has been scrolled to the "start"
|
||||||
|
* position. If positive to the "end" position.
|
||||||
|
* @return Return the amount of overscroll consumed. Returning 0 will let the
|
||||||
|
* recycler view handle this in the default way. Return "overscroll" to consume the
|
||||||
|
* whole event.
|
||||||
|
*/
|
||||||
|
int onOverscrollX(int overscroll);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notifies the listener that an overscroll has happened in the y direction.
|
||||||
|
* @param overscroll If negative, the recycler view has been scrolled to the "top"
|
||||||
|
* position. If positive to the "bottom" position.
|
||||||
|
* @return Return the amount of overscroll consumed. Returning 0 will let the
|
||||||
|
* recycler view handle this in the default way. Return "overscroll" to consume the
|
||||||
|
* whole event.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int onOverscrollY(int overscroll);
|
||||||
|
}
|
||||||
|
|
||||||
|
private OnOverscrollListener overscrollListener = null;
|
||||||
|
|
||||||
|
public OverscrollLinearLayoutManager(Context context) {
|
||||||
|
super(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public OverscrollLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
|
||||||
|
super(context, orientation, reverseLayout);
|
||||||
|
}
|
||||||
|
|
||||||
|
public OverscrollLinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||||
|
super(context, attrs, defStyleAttr, defStyleRes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the {@link OverscrollLinearLayoutManager.OnOverscrollListener} to get information about
|
||||||
|
* when the parent recyclerview is overscrolled.
|
||||||
|
*
|
||||||
|
* @param listener Listener to add
|
||||||
|
* @see OverscrollLinearLayoutManager.OnOverscrollListener
|
||||||
|
*/
|
||||||
|
public void setOnOverscrollListener(OnOverscrollListener listener) {
|
||||||
|
overscrollListener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
|
||||||
|
int consumed = super.scrollHorizontallyBy(dx, recycler, state);
|
||||||
|
int overscrollX = dx - consumed;
|
||||||
|
if (overscrollX != 0) {
|
||||||
|
if (overscrollListener != null) {
|
||||||
|
int consumedByListener = overscrollListener.onOverscrollX(overscrollX);
|
||||||
|
consumed += consumedByListener;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
|
||||||
|
int consumed = super.scrollVerticallyBy(dy, recycler, state);
|
||||||
|
int overscrollY = dy - consumed;
|
||||||
|
if (overscrollY != 0) {
|
||||||
|
if (overscrollListener != null) {
|
||||||
|
int consumedByListener = overscrollListener.onOverscrollY(overscrollY);
|
||||||
|
consumed += consumedByListener;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user