Merge "Allow ActionBarShadowController to attach to Views."
This commit is contained in:
committed by
Android (Google) Code Review
commit
934d626c99
@@ -27,7 +27,6 @@ import androidx.annotation.VisibleForTesting;
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
import androidx.lifecycle.LifecycleObserver;
|
||||
import androidx.lifecycle.OnLifecycleEvent;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
/**
|
||||
* UI controller that adds a shadow appear/disappear animation to action bar scroll.
|
||||
@@ -41,40 +40,36 @@ public class ActionBarShadowController implements LifecycleObserver {
|
||||
|
||||
@VisibleForTesting
|
||||
ScrollChangeWatcher mScrollChangeWatcher;
|
||||
private RecyclerView mRecyclerView;
|
||||
private View mScrollView;
|
||||
private boolean mIsScrollWatcherAttached;
|
||||
|
||||
/**
|
||||
* Wire up the animation to to an {@link Activity}. Shadow will be applied to activity's
|
||||
* action bar.
|
||||
*/
|
||||
public static ActionBarShadowController attachToRecyclerView(
|
||||
Activity activity, Lifecycle lifecycle, RecyclerView recyclerView) {
|
||||
return new ActionBarShadowController(activity, lifecycle, recyclerView);
|
||||
public static ActionBarShadowController attachToView(
|
||||
Activity activity, Lifecycle lifecycle, View scrollView) {
|
||||
return new ActionBarShadowController(activity, lifecycle, scrollView);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wire up the animation to to a {@link View}. Shadow will be applied to the view.
|
||||
*/
|
||||
public static ActionBarShadowController attachToRecyclerView(
|
||||
View anchorView, Lifecycle lifecycle, RecyclerView recyclerView) {
|
||||
return new ActionBarShadowController(anchorView, lifecycle, recyclerView);
|
||||
public static ActionBarShadowController attachToView(
|
||||
View anchorView, Lifecycle lifecycle, View scrollView) {
|
||||
return new ActionBarShadowController(anchorView, lifecycle, scrollView);
|
||||
}
|
||||
|
||||
private ActionBarShadowController(Activity activity, Lifecycle lifecycle,
|
||||
RecyclerView recyclerView) {
|
||||
mScrollChangeWatcher =
|
||||
new ActionBarShadowController.ScrollChangeWatcher(activity);
|
||||
mRecyclerView = recyclerView;
|
||||
private ActionBarShadowController(Activity activity, Lifecycle lifecycle, View scrollView) {
|
||||
mScrollChangeWatcher = new ActionBarShadowController.ScrollChangeWatcher(activity);
|
||||
mScrollView = scrollView;
|
||||
attachScrollWatcher();
|
||||
lifecycle.addObserver(this);
|
||||
}
|
||||
|
||||
private ActionBarShadowController(View anchorView, Lifecycle lifecycle,
|
||||
RecyclerView recyclerView) {
|
||||
mScrollChangeWatcher =
|
||||
new ActionBarShadowController.ScrollChangeWatcher(anchorView);
|
||||
mRecyclerView = recyclerView;
|
||||
private ActionBarShadowController(View anchorView, Lifecycle lifecycle, View scrollView) {
|
||||
mScrollChangeWatcher = new ActionBarShadowController.ScrollChangeWatcher(anchorView);
|
||||
mScrollView = scrollView;
|
||||
attachScrollWatcher();
|
||||
lifecycle.addObserver(this);
|
||||
}
|
||||
@@ -83,21 +78,21 @@ public class ActionBarShadowController implements LifecycleObserver {
|
||||
private void attachScrollWatcher() {
|
||||
if (!mIsScrollWatcherAttached) {
|
||||
mIsScrollWatcherAttached = true;
|
||||
mRecyclerView.addOnScrollListener(mScrollChangeWatcher);
|
||||
mScrollChangeWatcher.updateDropShadow(mRecyclerView);
|
||||
mScrollView.setOnScrollChangeListener(mScrollChangeWatcher);
|
||||
mScrollChangeWatcher.updateDropShadow(mScrollView);
|
||||
}
|
||||
}
|
||||
|
||||
@OnLifecycleEvent(ON_STOP)
|
||||
private void detachScrollWatcher() {
|
||||
mRecyclerView.removeOnScrollListener(mScrollChangeWatcher);
|
||||
mScrollView.setOnScrollChangeListener(null);
|
||||
mIsScrollWatcherAttached = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the drop shadow as the scrollable entity is scrolled.
|
||||
*/
|
||||
final class ScrollChangeWatcher extends RecyclerView.OnScrollListener {
|
||||
final class ScrollChangeWatcher implements View.OnScrollChangeListener {
|
||||
|
||||
private final Activity mActivity;
|
||||
private final View mAnchorView;
|
||||
@@ -112,9 +107,9 @@ public class ActionBarShadowController implements LifecycleObserver {
|
||||
mActivity = null;
|
||||
}
|
||||
|
||||
// RecyclerView scrolled.
|
||||
@Override
|
||||
public void onScrolled(RecyclerView view, int dx, int dy) {
|
||||
public void onScrollChange(View view, int scrollX, int scrollY, int oldScrollX,
|
||||
int oldScrollY) {
|
||||
updateDropShadow(view);
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import static androidx.lifecycle.Lifecycle.Event.ON_STOP;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.isNull;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
@@ -49,6 +50,8 @@ public class ActionBarShadowControllerTest {
|
||||
@Mock
|
||||
private RecyclerView mRecyclerView;
|
||||
@Mock
|
||||
private View mScrollView;
|
||||
@Mock
|
||||
private Activity mActivity;
|
||||
@Mock
|
||||
private ActionBar mActionBar;
|
||||
@@ -66,51 +69,60 @@ public class ActionBarShadowControllerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void attachToRecyclerView_shouldAddScrollWatcherAndUpdateActionBar() {
|
||||
public void attachToView_shouldAddScrollWatcherAndUpdateActionBar() {
|
||||
when(mRecyclerView.canScrollVertically(-1)).thenReturn(false);
|
||||
|
||||
ActionBarShadowController.attachToRecyclerView(mActivity, mLifecycle, mRecyclerView);
|
||||
ActionBarShadowController.attachToView(mActivity, mLifecycle, mRecyclerView);
|
||||
|
||||
verify(mActionBar).setElevation(ActionBarShadowController.ELEVATION_LOW);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void attachToRecyclerView_customViewAsActionBar_shouldUpdateElevationOnScroll() {
|
||||
public void attachToView_scrollView_shouldAddScrollWatcherAndUpdateActionBar() {
|
||||
when(mScrollView.canScrollVertically(-1)).thenReturn(false);
|
||||
|
||||
ActionBarShadowController.attachToView(mActivity, mLifecycle, mScrollView);
|
||||
|
||||
verify(mActionBar).setElevation(ActionBarShadowController.ELEVATION_LOW);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void attachToView_customViewAsActionBar_shouldUpdateElevationOnScroll() {
|
||||
// Setup
|
||||
mView.setElevation(50);
|
||||
when(mRecyclerView.canScrollVertically(-1)).thenReturn(false);
|
||||
final ActionBarShadowController controller =
|
||||
ActionBarShadowController.attachToRecyclerView(mView, mLifecycle, mRecyclerView);
|
||||
ActionBarShadowController.attachToView(mView, mLifecycle, mRecyclerView);
|
||||
assertThat(mView.getElevation()).isEqualTo(ActionBarShadowController.ELEVATION_LOW);
|
||||
|
||||
// Scroll
|
||||
when(mRecyclerView.canScrollVertically(-1)).thenReturn(true);
|
||||
controller.mScrollChangeWatcher.onScrolled(mRecyclerView, 10 /* dx */, 10 /* dy */);
|
||||
controller.mScrollChangeWatcher.onScrollChange(mRecyclerView, 10, 10, 0, 0);
|
||||
assertThat(mView.getElevation()).isEqualTo(ActionBarShadowController.ELEVATION_HIGH);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void attachToRecyclerView_lifecycleChange_shouldAttachDetach() {
|
||||
ActionBarShadowController.attachToRecyclerView(mActivity, mLifecycle, mRecyclerView);
|
||||
public void attachToView_lifecycleChange_shouldAttachDetach() {
|
||||
ActionBarShadowController.attachToView(mActivity, mLifecycle, mRecyclerView);
|
||||
|
||||
verify(mRecyclerView).addOnScrollListener(any());
|
||||
verify(mRecyclerView).setOnScrollChangeListener(any());
|
||||
|
||||
mLifecycle.handleLifecycleEvent(ON_START);
|
||||
mLifecycle.handleLifecycleEvent(ON_STOP);
|
||||
verify(mRecyclerView).removeOnScrollListener(any());
|
||||
verify(mRecyclerView).setOnScrollChangeListener(isNull());
|
||||
|
||||
mLifecycle.handleLifecycleEvent(ON_START);
|
||||
verify(mRecyclerView, times(2)).addOnScrollListener(any());
|
||||
verify(mRecyclerView, times(3)).setOnScrollChangeListener(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onScrolled_nullAnchorViewAndActivity_shouldNotCrash() {
|
||||
final Activity activity = null;
|
||||
final ActionBarShadowController controller =
|
||||
ActionBarShadowController.attachToRecyclerView(activity, mLifecycle, mRecyclerView);
|
||||
ActionBarShadowController.attachToView(activity, mLifecycle, mRecyclerView);
|
||||
|
||||
// Scroll
|
||||
controller.mScrollChangeWatcher.onScrolled(mRecyclerView, 10 /* dx */, 10 /* dy */);
|
||||
controller.mScrollChangeWatcher.onScrollChange(mRecyclerView, 10, 10, 0, 0);
|
||||
// no crash
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user