summaryrefslogtreecommitdiff
path: root/library/main/src/com/android/setupwizardlib/template/RequireScrollMixin.java
diff options
context:
space:
mode:
Diffstat (limited to 'library/main/src/com/android/setupwizardlib/template/RequireScrollMixin.java')
-rw-r--r--library/main/src/com/android/setupwizardlib/template/RequireScrollMixin.java418
1 files changed, 198 insertions, 220 deletions
diff --git a/library/main/src/com/android/setupwizardlib/template/RequireScrollMixin.java b/library/main/src/com/android/setupwizardlib/template/RequireScrollMixin.java
index fd3303b..02bcc1c 100644
--- a/library/main/src/com/android/setupwizardlib/template/RequireScrollMixin.java
+++ b/library/main/src/com/android/setupwizardlib/template/RequireScrollMixin.java
@@ -18,244 +18,222 @@ package com.android.setupwizardlib.template;
import android.os.Handler;
import android.os.Looper;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.Button;
-
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
-
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
import com.android.setupwizardlib.TemplateLayout;
import com.android.setupwizardlib.view.NavigationBar;
/**
- * A mixin to require the a scrollable container (BottomScrollView, RecyclerView or ListView) to
- * be scrolled to bottom, making sure that the user sees all content above and below the fold.
+ * A mixin to require the a scrollable container (BottomScrollView, RecyclerView or ListView) to be
+ * scrolled to bottom, making sure that the user sees all content above and below the fold.
*/
public class RequireScrollMixin implements Mixin {
- /* static section */
-
- /**
- * Listener for when the require-scroll state changes. Note that this only requires the user to
- * scroll to the bottom once - if the user scrolled to the bottom and back-up, scrolling to
- * bottom is not required again.
- */
- public interface OnRequireScrollStateChangedListener {
+ /* static section */
- /**
- * Called when require-scroll state changed.
- *
- * @param scrollNeeded True if the user should be required to scroll to bottom.
- */
- void onRequireScrollStateChanged(boolean scrollNeeded);
- }
+ /**
+ * Listener for when the require-scroll state changes. Note that this only requires the user to
+ * scroll to the bottom once - if the user scrolled to the bottom and back-up, scrolling to bottom
+ * is not required again.
+ */
+ public interface OnRequireScrollStateChangedListener {
/**
- * A delegate to detect scrollability changes and to scroll the page. This provides a layer
- * of abstraction for BottomScrollView, RecyclerView and ListView. The delegate should call
- * {@link #notifyScrollabilityChange(boolean)} when the view scrollability is changed.
- */
- interface ScrollHandlingDelegate {
-
- /**
- * Starts listening to scrollability changes at the target scrollable container.
- */
- void startListening();
-
- /**
- * Scroll the page content down by one page.
- */
- void pageScrollDown();
- }
-
- /* non-static section */
-
- @NonNull
- private final TemplateLayout mTemplateLayout;
-
- private final Handler mHandler = new Handler(Looper.getMainLooper());
-
- private boolean mRequiringScrollToBottom = false;
-
- // Whether the user have seen the more button yet.
- private boolean mEverScrolledToBottom = false;
-
- private ScrollHandlingDelegate mDelegate;
-
- @Nullable
- private OnRequireScrollStateChangedListener mListener;
-
- /**
- * @param templateLayout The template containing this mixin
- */
- public RequireScrollMixin(@NonNull TemplateLayout templateLayout) {
- mTemplateLayout = templateLayout;
- }
-
- /**
- * Sets the delegate to handle scrolling. The type of delegate should depend on whether the
- * scrolling view is a BottomScrollView, RecyclerView or ListView.
- */
- public void setScrollHandlingDelegate(@NonNull ScrollHandlingDelegate delegate) {
- mDelegate = delegate;
- }
-
- /**
- * Listen to require scroll state changes. When scroll is required,
- * {@link OnRequireScrollStateChangedListener#onRequireScrollStateChanged(boolean)} is called
- * with {@code true}, and vice versa.
- */
- public void setOnRequireScrollStateChangedListener(
- @Nullable OnRequireScrollStateChangedListener listener) {
- mListener = listener;
- }
-
- /**
- * @return The scroll state listener previously set, or {@code null} if none is registered.
- */
- public OnRequireScrollStateChangedListener getOnRequireScrollStateChangedListener() {
- return mListener;
- }
-
- /**
- * Creates an {@link OnClickListener} which if scrolling is required, will scroll the page down,
- * and if scrolling is not required, delegates to the wrapped {@code listener}. Note that you
- * should call {@link #requireScroll()} as well in order to start requiring scrolling.
+ * Called when require-scroll state changed.
*
- * @param listener The listener to be invoked when scrolling is not needed and the user taps on
- * the button. If {@code null}, the click listener will be a no-op when scroll
- * is not required.
- * @return A new {@link OnClickListener} which will scroll the page down or delegate to the
- * given listener depending on the current require-scroll state.
- */
- public OnClickListener createOnClickListener(@Nullable final OnClickListener listener) {
- return new OnClickListener() {
- @Override
- public void onClick(View view) {
- if (mRequiringScrollToBottom) {
- mDelegate.pageScrollDown();
- } else if (listener != null) {
- listener.onClick(view);
- }
- }
- };
- }
-
- /**
- * Coordinate with the given navigation bar to require scrolling on the page. The more button
- * will be shown instead of the next button while scrolling is required.
+ * @param scrollNeeded True if the user should be required to scroll to bottom.
*/
- public void requireScrollWithNavigationBar(@NonNull final NavigationBar navigationBar) {
- setOnRequireScrollStateChangedListener(
- new OnRequireScrollStateChangedListener() {
- @Override
- public void onRequireScrollStateChanged(boolean scrollNeeded) {
- navigationBar.getMoreButton()
- .setVisibility(scrollNeeded ? View.VISIBLE : View.GONE);
- navigationBar.getNextButton()
- .setVisibility(scrollNeeded ? View.GONE : View.VISIBLE);
- }
- });
- navigationBar.getMoreButton().setOnClickListener(createOnClickListener(null));
- requireScroll();
- }
-
- /**
- * @see #requireScrollWithButton(Button, CharSequence, OnClickListener)
- */
- public void requireScrollWithButton(
- @NonNull Button button,
- @StringRes int moreText,
- @Nullable OnClickListener onClickListener) {
- requireScrollWithButton(button, button.getContext().getText(moreText), onClickListener);
- }
-
- /**
- * Use the given {@code button} to require scrolling. When scrolling is required, the button
- * label will change to {@code moreText}, and tapping the button will cause the page to scroll
- * down.
- *
- * <p>Note: Calling {@link View#setOnClickListener} on the button after this method will remove
- * its link to the require-scroll mechanism. If you need to do that, obtain the click listener
- * from {@link #createOnClickListener(OnClickListener)}.
- *
- * <p>Note: The normal button label is taken from the button's text at the time of calling this
- * method. Calling {@link android.widget.TextView#setText} after calling this method causes
- * undefined behavior.
- *
- * @param button The button to use for require scroll. The button's "normal" label is taken from
- * the text at the time of calling this method, and the click listener of it will
- * be replaced.
- * @param moreText The button label when scroll is required.
- * @param onClickListener The listener for clicks when scrolling is not required.
- */
- public void requireScrollWithButton(
- @NonNull final Button button,
- final CharSequence moreText,
- @Nullable OnClickListener onClickListener) {
- final CharSequence nextText = button.getText();
- button.setOnClickListener(createOnClickListener(onClickListener));
- setOnRequireScrollStateChangedListener(new OnRequireScrollStateChangedListener() {
- @Override
- public void onRequireScrollStateChanged(boolean scrollNeeded) {
- button.setText(scrollNeeded ? moreText : nextText);
- }
+ void onRequireScrollStateChanged(boolean scrollNeeded);
+ }
+
+ /**
+ * A delegate to detect scrollability changes and to scroll the page. This provides a layer of
+ * abstraction for BottomScrollView, RecyclerView and ListView. The delegate should call {@link
+ * #notifyScrollabilityChange(boolean)} when the view scrollability is changed.
+ */
+ interface ScrollHandlingDelegate {
+
+ /** Starts listening to scrollability changes at the target scrollable container. */
+ void startListening();
+
+ /** Scroll the page content down by one page. */
+ void pageScrollDown();
+ }
+
+ /* non-static section */
+
+ private final Handler handler = new Handler(Looper.getMainLooper());
+
+ private boolean requiringScrollToBottom = false;
+
+ // Whether the user have seen the more button yet.
+ private boolean everScrolledToBottom = false;
+
+ private ScrollHandlingDelegate delegate;
+
+ @Nullable private OnRequireScrollStateChangedListener listener;
+
+ /** @param templateLayout The template containing this mixin */
+ public RequireScrollMixin(@NonNull TemplateLayout templateLayout) {
+ }
+
+ /**
+ * Sets the delegate to handle scrolling. The type of delegate should depend on whether the
+ * scrolling view is a BottomScrollView, RecyclerView or ListView.
+ */
+ public void setScrollHandlingDelegate(@NonNull ScrollHandlingDelegate delegate) {
+ this.delegate = delegate;
+ }
+
+ /**
+ * Listen to require scroll state changes. When scroll is required, {@link
+ * OnRequireScrollStateChangedListener#onRequireScrollStateChanged(boolean)} is called with {@code
+ * true}, and vice versa.
+ */
+ public void setOnRequireScrollStateChangedListener(
+ @Nullable OnRequireScrollStateChangedListener listener) {
+ this.listener = listener;
+ }
+
+ /** @return The scroll state listener previously set, or {@code null} if none is registered. */
+ public OnRequireScrollStateChangedListener getOnRequireScrollStateChangedListener() {
+ return listener;
+ }
+
+ /**
+ * Creates an {@link OnClickListener} which if scrolling is required, will scroll the page down,
+ * and if scrolling is not required, delegates to the wrapped {@code listener}. Note that you
+ * should call {@link #requireScroll()} as well in order to start requiring scrolling.
+ *
+ * @param listener The listener to be invoked when scrolling is not needed and the user taps on
+ * the button. If {@code null}, the click listener will be a no-op when scroll is not
+ * required.
+ * @return A new {@link OnClickListener} which will scroll the page down or delegate to the given
+ * listener depending on the current require-scroll state.
+ */
+ public OnClickListener createOnClickListener(@Nullable final OnClickListener listener) {
+ return new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ if (requiringScrollToBottom) {
+ delegate.pageScrollDown();
+ } else if (listener != null) {
+ listener.onClick(view);
+ }
+ }
+ };
+ }
+
+ /**
+ * Coordinate with the given navigation bar to require scrolling on the page. The more button will
+ * be shown instead of the next button while scrolling is required.
+ */
+ public void requireScrollWithNavigationBar(@NonNull final NavigationBar navigationBar) {
+ setOnRequireScrollStateChangedListener(
+ new OnRequireScrollStateChangedListener() {
+ @Override
+ public void onRequireScrollStateChanged(boolean scrollNeeded) {
+ navigationBar.getMoreButton().setVisibility(scrollNeeded ? View.VISIBLE : View.GONE);
+ navigationBar.getNextButton().setVisibility(scrollNeeded ? View.GONE : View.VISIBLE);
+ }
});
- requireScroll();
- }
-
- /**
- * @return True if scrolling is required. Note that this mixin only requires the user to
- * scroll to the bottom once - if the user scrolled to the bottom and back-up, scrolling to
- * bottom is not required again.
- */
- public boolean isScrollingRequired() {
- return mRequiringScrollToBottom;
+ navigationBar.getMoreButton().setOnClickListener(createOnClickListener(null));
+ requireScroll();
+ }
+
+ /** @see #requireScrollWithButton(Button, CharSequence, OnClickListener) */
+ public void requireScrollWithButton(
+ @NonNull Button button, @StringRes int moreText, @Nullable OnClickListener onClickListener) {
+ requireScrollWithButton(button, button.getContext().getText(moreText), onClickListener);
+ }
+
+ /**
+ * Use the given {@code button} to require scrolling. When scrolling is required, the button label
+ * will change to {@code moreText}, and tapping the button will cause the page to scroll down.
+ *
+ * <p>Note: Calling {@link View#setOnClickListener} on the button after this method will remove
+ * its link to the require-scroll mechanism. If you need to do that, obtain the click listener
+ * from {@link #createOnClickListener(OnClickListener)}.
+ *
+ * <p>Note: The normal button label is taken from the button's text at the time of calling this
+ * method. Calling {@link android.widget.TextView#setText} after calling this method causes
+ * undefined behavior.
+ *
+ * @param button The button to use for require scroll. The button's "normal" label is taken from
+ * the text at the time of calling this method, and the click listener of it will be replaced.
+ * @param moreText The button label when scroll is required.
+ * @param onClickListener The listener for clicks when scrolling is not required.
+ */
+ public void requireScrollWithButton(
+ @NonNull final Button button,
+ final CharSequence moreText,
+ @Nullable OnClickListener onClickListener) {
+ final CharSequence nextText = button.getText();
+ button.setOnClickListener(createOnClickListener(onClickListener));
+ setOnRequireScrollStateChangedListener(
+ new OnRequireScrollStateChangedListener() {
+ @Override
+ public void onRequireScrollStateChanged(boolean scrollNeeded) {
+ button.setText(scrollNeeded ? moreText : nextText);
+ }
+ });
+ requireScroll();
+ }
+
+ /**
+ * @return True if scrolling is required. Note that this mixin only requires the user to scroll to
+ * the bottom once - if the user scrolled to the bottom and back-up, scrolling to bottom is
+ * not required again.
+ */
+ public boolean isScrollingRequired() {
+ return requiringScrollToBottom;
+ }
+
+ /**
+ * Start requiring scrolling on the layout. After calling this method, this mixin will start
+ * listening to scroll events from the scrolling container, and call {@link
+ * OnRequireScrollStateChangedListener} when the scroll state changes.
+ */
+ public void requireScroll() {
+ delegate.startListening();
+ }
+
+ /**
+ * {@link ScrollHandlingDelegate} should call this method when the scrollability of the scrolling
+ * container changed, so this mixin can recompute whether scrolling should be required.
+ *
+ * @param canScrollDown True if the view can scroll down further.
+ */
+ void notifyScrollabilityChange(boolean canScrollDown) {
+ if (canScrollDown == requiringScrollToBottom) {
+ // Already at the desired require-scroll state
+ return;
}
-
- /**
- * Start requiring scrolling on the layout. After calling this method, this mixin will start
- * listening to scroll events from the scrolling container, and call
- * {@link OnRequireScrollStateChangedListener} when the scroll state changes.
- */
- public void requireScroll() {
- mDelegate.startListening();
+ if (canScrollDown) {
+ if (!everScrolledToBottom) {
+ postScrollStateChange(true);
+ requiringScrollToBottom = true;
+ }
+ } else {
+ postScrollStateChange(false);
+ requiringScrollToBottom = false;
+ everScrolledToBottom = true;
}
-
- /**
- * {@link ScrollHandlingDelegate} should call this method when the scrollability of the
- * scrolling container changed, so this mixin can recompute whether scrolling should be
- * required.
- *
- * @param canScrollDown True if the view can scroll down further.
- */
- void notifyScrollabilityChange(boolean canScrollDown) {
- if (canScrollDown == mRequiringScrollToBottom) {
- // Already at the desired require-scroll state
- return;
- }
- if (canScrollDown) {
- if (!mEverScrolledToBottom) {
- postScrollStateChange(true);
- mRequiringScrollToBottom = true;
- }
- } else {
- postScrollStateChange(false);
- mRequiringScrollToBottom = false;
- mEverScrolledToBottom = true;
- }
- }
-
- private void postScrollStateChange(final boolean scrollNeeded) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- if (mListener != null) {
- mListener.onRequireScrollStateChanged(scrollNeeded);
- }
+ }
+
+ private void postScrollStateChange(final boolean scrollNeeded) {
+ handler.post(
+ new Runnable() {
+ @Override
+ public void run() {
+ if (listener != null) {
+ listener.onRequireScrollStateChanged(scrollNeeded);
}
+ }
});
- }
+ }
}