From 52c878c1405fd3e04464893591f364eec98aa008 Mon Sep 17 00:00:00 2001 From: Robin DAHURON Date: Fri, 26 Mar 2021 17:39:22 +0100 Subject: [PATCH] feat(*): add skip, next and previous buttons to page add PaperOnboardingPage.Builder for readability --- .../examples/fragment/FragmentsActivity.java | 41 +++- .../PaperOnboardingEngine.java | 80 ++++++++ .../paperonboarding/PaperOnboardingPage.java | 187 ++++++++++++++++++ .../drawable/onboarding_button_next_icon.xml | 5 + .../onboarding_button_previous_icon.xml | 5 + .../layout-v21/onboarding_button_layout.xml | 35 ++++ .../res/layout/onboarding_button_layout.xml | 40 ++++ .../res/layout/onboarding_main_layout.xml | 9 + 8 files changed, 396 insertions(+), 6 deletions(-) create mode 100644 paper-onboarding/src/main/res/drawable/onboarding_button_next_icon.xml create mode 100644 paper-onboarding/src/main/res/drawable/onboarding_button_previous_icon.xml create mode 100644 paper-onboarding/src/main/res/layout-v21/onboarding_button_layout.xml create mode 100644 paper-onboarding/src/main/res/layout/onboarding_button_layout.xml diff --git a/paper-onboarding-fragment-example/src/main/java/com/ramotion/paperonboarding/examples/fragment/FragmentsActivity.java b/paper-onboarding-fragment-example/src/main/java/com/ramotion/paperonboarding/examples/fragment/FragmentsActivity.java index 0df9049..0dda706 100644 --- a/paper-onboarding-fragment-example/src/main/java/com/ramotion/paperonboarding/examples/fragment/FragmentsActivity.java +++ b/paper-onboarding-fragment-example/src/main/java/com/ramotion/paperonboarding/examples/fragment/FragmentsActivity.java @@ -43,12 +43,41 @@ public void onRightOut() { private ArrayList getDataForOnboarding() { // prepare data - PaperOnboardingPage scr1 = new PaperOnboardingPage("Hotels", "All hotels and hostels are sorted by hospitality rating", - Color.parseColor("#678FB4"), R.drawable.hotels, R.drawable.key); - PaperOnboardingPage scr2 = new PaperOnboardingPage("Banks", "We carefully verify all banks before add them into the app", - Color.parseColor("#65B0B4"), R.drawable.banks, R.drawable.wallet); - PaperOnboardingPage scr3 = new PaperOnboardingPage("Stores", "All local stores are categorized for your convenience", - Color.parseColor("#9B90BC"), R.drawable.stores, R.drawable.shopping_cart); + PaperOnboardingPage scr1; + PaperOnboardingPage.Builder builder = new PaperOnboardingPage.Builder("Hotels", "All hotels and hostels are sorted by hospitality rating") + .setSkipText("Skip") + .setShowSkipButton(true) + .setShowNextButton(true) + .setShowPreviousButton(true) + .setContentIconRes(R.drawable.hotels) + .setBgColor(Color.parseColor("#678FB4")) + .setBottomBarIconRes(R.drawable.key); + + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { + builder.setNextButtonColor(Color.RED); + } + scr1 = builder.create(); + + + PaperOnboardingPage scr2 = new PaperOnboardingPage.Builder("Banks", "We carefully verify all banks before add them into the app") + .setSkipText("Skip") + .setShowSkipButton(true) + .setShowNextButton(true) + .setShowPreviousButton(true) + .setContentIconRes(R.drawable.banks) + .setBgColor(Color.parseColor("#65B0B4")) + .setBottomBarIconRes(R.drawable.wallet) + .create(); + + PaperOnboardingPage scr3 = new PaperOnboardingPage.Builder("Stores", "All local stores are categorized for your convenience") + .setSkipText("Skip") + .setShowSkipButton(true) + .setShowNextButton(true) + .setShowPreviousButton(true) + .setContentIconRes(R.drawable.stores) + .setBgColor(Color.parseColor("#9B90BC")) + .setBottomBarIconRes(R.drawable.shopping_cart) + .create(); ArrayList elements = new ArrayList<>(); elements.add(scr1); diff --git a/paper-onboarding/src/main/java/com/ramotion/paperonboarding/PaperOnboardingEngine.java b/paper-onboarding/src/main/java/com/ramotion/paperonboarding/PaperOnboardingEngine.java index b0d1c7c..36010fe 100644 --- a/paper-onboarding/src/main/java/com/ramotion/paperonboarding/PaperOnboardingEngine.java +++ b/paper-onboarding/src/main/java/com/ramotion/paperonboarding/PaperOnboardingEngine.java @@ -5,6 +5,7 @@ import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.content.Context; +import android.content.res.ColorStateList; import android.os.Build; import android.view.Gravity; import android.view.LayoutInflater; @@ -14,7 +15,9 @@ import android.view.ViewTreeObserver; import android.view.animation.AccelerateInterpolator; import android.view.animation.DecelerateInterpolator; +import android.widget.Button; import android.widget.FrameLayout; +import android.widget.ImageButton; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.RelativeLayout; @@ -43,6 +46,7 @@ public class PaperOnboardingEngine implements PaperOnboardingEngineDefaults { private final FrameLayout mContentIconContainer; private final FrameLayout mBackgroundContainer; private final LinearLayout mPagerIconsContainer; + private final FrameLayout mContentButtonContainer; private final RelativeLayout mContentRootLayout; private final LinearLayout mContentCenteredContainer; @@ -84,6 +88,7 @@ public PaperOnboardingEngine(View rootLayout, ArrayList con mContentIconContainer = (FrameLayout) rootLayout.findViewById(R.id.onboardingContentIconContainer); mBackgroundContainer = (FrameLayout) rootLayout.findViewById(R.id.onboardingBackgroundContainer); mPagerIconsContainer = (LinearLayout) rootLayout.findViewById(R.id.onboardingPagerIconsContainer); + mContentButtonContainer = rootLayout.findViewById(R.id.onboardingButtonContainer); mContentRootLayout = (RelativeLayout) mRootLayout.getChildAt(1); mContentCenteredContainer = (LinearLayout) mContentRootLayout.getChildAt(0); @@ -184,6 +189,10 @@ protected void initializeStartingState() { mContentIconContainer.addView(initContentIcon); // initial bg color mRootLayout.setBackgroundColor(activeElement.getBgColor()); + + // Setup Buttons + ViewGroup initialContentButtons = createContentButtons(activeElement); + mContentButtonContainer.addView(initialContentButtons); } /** @@ -228,12 +237,18 @@ protected void toggleContent(boolean prev) { // 6 animate centering of all content Animator centerContentAnimation = createContentCenteringVerticalAnimation(newContentText, newContentIcon); + // 7 animate buttons + ViewGroup newContentButton = createContentButtons(newElement); + mContentButtonContainer.addView(newContentButton); + Animator buttonAnimation = createContentButtonShowAnimation(mContentButtonContainer.getChildAt(mContentButtonContainer.getChildCount() - 2), newContentButton); + centerContentAnimation.start(); bgAnimation.start(); pagerMoveAnimation.start(); pagerIconAnimation.start(); contentIconShowAnimation.start(); contentTextShowAnimation.start(); + buttonAnimation.start(); if (mOnChangeListener != null) mOnChangeListener.onPageChanged(oldElementIndex, mActiveElementIndex); @@ -434,6 +449,28 @@ public void onAnimationUpdate(ValueAnimator valueAnimator) { return animations; } + private AnimatorSet createContentButtonShowAnimation(final View currentContentButton, final View newContentButton) { + AnimatorSet animations = new AnimatorSet(); + Animator currentContentFadeOut = ObjectAnimator.ofFloat(currentContentButton, "alpha", 1, 0); + currentContentFadeOut.setDuration(ANIM_CONTENT_TEXT_HIDE_TIME); + currentContentFadeOut.addListener(new AnimatorEndListener() { + @Override + public void onAnimationEnd(Animator animation) { + mContentButtonContainer.removeView(currentContentButton); + } + }); + animations.playTogether(currentContentFadeOut); + + Animator newContentFadeIn = ObjectAnimator.ofFloat(newContentButton, "alpha", 0, 1); + newContentFadeIn.setDuration(ANIM_CONTENT_TEXT_SHOW_TIME); + + animations.playTogether(newContentFadeIn); + + animations.setInterpolator(new DecelerateInterpolator()); + + return animations; + } + /** * @param iconDrawableRes drawable resource for icon * @param isActive is active element @@ -486,6 +523,49 @@ protected ImageView createContentIconView(PaperOnboardingPage PaperOnboardingPag return contentIcon; } + protected ViewGroup createContentButtons(PaperOnboardingPage activeElement) { + LayoutInflater vi = LayoutInflater.from(mAppContext); + ViewGroup contentButtons = (ViewGroup) vi.inflate(R.layout.onboarding_button_layout, mContentButtonContainer, false); + Button skipButton = contentButtons.findViewById(R.id.onboardingButtonSkip); + skipButton.setText(activeElement.getSkipText()); + skipButton.setVisibility(activeElement.getShowSkipButton()? View.VISIBLE: View.GONE); + + ImageButton previousButton = contentButtons.findViewById(R.id.onboardingButtonPrevious); + previousButton.setVisibility(activeElement.getShowPreviousButton()?View.VISIBLE: View.GONE); + + ImageButton nextButton = contentButtons.findViewById(R.id.onboardingButtonNext); + nextButton.setVisibility(activeElement.getShowNextButton()?View.VISIBLE: View.GONE); + + skipButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (mOnRightOutListener != null) + mOnRightOutListener.onRightOut(); + } + }); + + nextButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + toggleContent(false); + } + }); + + previousButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + toggleContent(true); + } + }); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + previousButton.setImageTintList(ColorStateList.valueOf(activeElement.getPreviousButtonColor())); + nextButton.setImageTintList(ColorStateList.valueOf(activeElement.getNextButtonColor())); + } + + return contentButtons; + } + /** * @return index of currently active element */ diff --git a/paper-onboarding/src/main/java/com/ramotion/paperonboarding/PaperOnboardingPage.java b/paper-onboarding/src/main/java/com/ramotion/paperonboarding/PaperOnboardingPage.java index d90beba..706aad2 100644 --- a/paper-onboarding/src/main/java/com/ramotion/paperonboarding/PaperOnboardingPage.java +++ b/paper-onboarding/src/main/java/com/ramotion/paperonboarding/PaperOnboardingPage.java @@ -1,5 +1,10 @@ package com.ramotion.paperonboarding; +import android.graphics.Color; +import android.os.Build; + +import androidx.annotation.RequiresApi; + import java.io.Serializable; /** @@ -13,6 +18,123 @@ public class PaperOnboardingPage implements Serializable { private int contentIconRes; private int bottomBarIconRes; + private boolean showSkipButton; + private boolean showNextButton; + private boolean showPreviousButton; + private String skipText; + + private int previousButtonColor; + private int nextButtonColor; + + public static class Builder { + private String titleText; + private String descriptionText; + private int bgColor; + private int contentIconRes; + private int bottomBarIconRes; + + private boolean showSkipButton; + private boolean showNextButton; + private boolean showPreviousButton; + private String skipText; + + private int previousButtonColor; + private int nextButtonColor; + + + public Builder() { + init(); + } + + public Builder(String titleText, String descriptionText) { + init(); + this.titleText = titleText; + this.descriptionText = descriptionText; + } + + private void init() { + titleText = ""; + descriptionText = ""; + bgColor = Color.TRANSPARENT; + contentIconRes = -1; + bottomBarIconRes = -1; + showNextButton = false; + showSkipButton = false; + showPreviousButton = false; + skipText = ""; + previousButtonColor = Color.BLACK; + nextButtonColor = Color.BLACK; + } + + public Builder setTitleText(String titleText) { + this.titleText = titleText; + return this; + } + + public Builder setDescriptionText(String descriptionText) { + this.descriptionText = descriptionText; + return this; + } + + public Builder setBgColor(int bgColor) { + this.bgColor = bgColor; + return this; + } + + public Builder setContentIconRes(int contentIconRes) { + this.contentIconRes = contentIconRes; + return this; + } + + public Builder setBottomBarIconRes(int bottomBarIconRes) { + this.bottomBarIconRes = bottomBarIconRes; + return this; + } + + public Builder setShowSkipButton(boolean showSkipButton) { + this.showSkipButton = showSkipButton; + return this; + } + + public Builder setShowNextButton(boolean showNextButton) { + this.showNextButton = showNextButton; + return this; + } + + public Builder setShowPreviousButton(boolean showPreviousButton) { + this.showPreviousButton = showPreviousButton; + return this; + } + + public Builder setSkipText(String skipText) { + this.skipText = skipText; + return this; + } + + @RequiresApi(21) + public Builder setPreviousButtonColor(int color) { + this.previousButtonColor = color; + return this; + } + + @RequiresApi(21) + public Builder setNextButtonColor(int color) { + this.nextButtonColor = color; + return this; + } + + public PaperOnboardingPage create() { + PaperOnboardingPage res = new PaperOnboardingPage(titleText, descriptionText, bgColor, contentIconRes, bottomBarIconRes); + res.setShowNextButton(showNextButton); + res.setShowSkipButton(showSkipButton); + res.setShowPreviousButton(showPreviousButton); + res.setSkipText(skipText); + res.setNextButtonColor(nextButtonColor); + res.setPreviousButtonColor(previousButtonColor); + return res; + } + } + public PaperOnboardingPage() { } @@ -22,6 +144,9 @@ public PaperOnboardingPage(String titleText, String descriptionText, int bgColor this.bottomBarIconRes = bottomBarIconRes; this.descriptionText = descriptionText; this.titleText = titleText; + this.showSkipButton = false; + this.showNextButton = false; + this.showPreviousButton = false; } public String getTitleText() { @@ -64,6 +189,55 @@ public void setBgColor(int bgColor) { this.bgColor = bgColor; } + + public boolean getShowSkipButton() { + return showSkipButton; + } + + public void setShowSkipButton(boolean showSkipButton) { + this.showSkipButton = showSkipButton; + } + + public boolean getShowNextButton() { + return showNextButton; + } + + public void setShowNextButton(boolean showNextButton) { + this.showNextButton = showNextButton; + } + + public boolean getShowPreviousButton() { + return showPreviousButton; + } + + public void setShowPreviousButton(boolean showPreviousButton) { + this.showPreviousButton = showPreviousButton; + } + + public int getPreviousButtonColor() { + return this.previousButtonColor; + } + + public void setPreviousButtonColor(int color) { + this.previousButtonColor = color; + } + + public int getNextButtonColor() { + return this.nextButtonColor; + } + + public void setNextButtonColor(int color) { + this.nextButtonColor = color; + } + + public String getSkipText() { + return skipText; + } + + public void setSkipText(String skipText) { + this.skipText = skipText; + } + @Override public boolean equals(Object o) { if (this == o) return true; @@ -74,8 +248,14 @@ public boolean equals(Object o) { if (bgColor != that.bgColor) return false; if (contentIconRes != that.contentIconRes) return false; if (bottomBarIconRes != that.bottomBarIconRes) return false; + if (showNextButton != that.showNextButton) return false; + if (showPreviousButton != that.showPreviousButton) return false; + if (showSkipButton != that.showSkipButton) return false; + if (titleText != null ? !titleText.equals(that.titleText) : that.titleText != null) return false; + if (skipText != null ? !skipText.equals(that.skipText) : that.skipText != null) + return false; return descriptionText != null ? descriptionText.equals(that.descriptionText) : that.descriptionText == null; } @@ -84,12 +264,19 @@ public boolean equals(Object o) { public int hashCode() { int result = titleText != null ? titleText.hashCode() : 0; result = 31 * result + (descriptionText != null ? descriptionText.hashCode() : 0); + result = 31 * result + (skipText != null ? skipText.hashCode() : 0); result = 31 * result + bgColor; result = 31 * result + contentIconRes; result = 31 * result + bottomBarIconRes; + result = 31 * result + bottomBarIconRes; + result = 31 * result + (showSkipButton? 1: 0); + result = 31 * result + (showPreviousButton? 1: 0); + result = 31 * result + (showNextButton? 1: 0); return result; } + + @Override public String toString() { return "PaperOnboardingPage{" + diff --git a/paper-onboarding/src/main/res/drawable/onboarding_button_next_icon.xml b/paper-onboarding/src/main/res/drawable/onboarding_button_next_icon.xml new file mode 100644 index 0000000..3d6bf99 --- /dev/null +++ b/paper-onboarding/src/main/res/drawable/onboarding_button_next_icon.xml @@ -0,0 +1,5 @@ + + + diff --git a/paper-onboarding/src/main/res/drawable/onboarding_button_previous_icon.xml b/paper-onboarding/src/main/res/drawable/onboarding_button_previous_icon.xml new file mode 100644 index 0000000..a11a80b --- /dev/null +++ b/paper-onboarding/src/main/res/drawable/onboarding_button_previous_icon.xml @@ -0,0 +1,5 @@ + + + diff --git a/paper-onboarding/src/main/res/layout-v21/onboarding_button_layout.xml b/paper-onboarding/src/main/res/layout-v21/onboarding_button_layout.xml new file mode 100644 index 0000000..f825dd7 --- /dev/null +++ b/paper-onboarding/src/main/res/layout-v21/onboarding_button_layout.xml @@ -0,0 +1,35 @@ + +