Skip to content

Commit 82ec444

Browse files
authored
Bottom Sheet Page (#4)
* initial bottom sheet page implementation * improve animations for showing/hiding bottom sheet page
1 parent 2d8dc51 commit 82ec444

File tree

13 files changed

+224
-27
lines changed

13 files changed

+224
-27
lines changed

gradle.properties

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@ KOTLIN_VERSION=1.3.61
2222
ANDROID_X_VERSION=1.0.2
2323

2424
MIN_SDK=15
25-
TARGET_SDK=29
26-
COMPILE_SDK=29
25+
TARGET_SDK=31
26+
COMPILE_SDK=31
2727

28-
VERSION_NAME=1.1.0
29-
VERSION_CODE=4
28+
VERSION_NAME=2.0.0
29+
VERSION_CODE=5
3030
GROUP=com.klinkerapps
3131

3232
POM_DESCRIPTION=Android floating tutorial pager activity
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package xyz.klinker.android.floating_tutorial
2+
3+
import android.view.Gravity
4+
import android.view.ViewGroup
5+
import xyz.klinker.android.floating_tutorial.util.DensityConverter
6+
7+
abstract class BottomSheetTutorialPage(activity: FloatingTutorialActivity) : TutorialPage(activity) {
8+
override val rootLayoutParams: LayoutParams
9+
get() = LayoutParams(
10+
ViewGroup.LayoutParams.MATCH_PARENT,
11+
ViewGroup.LayoutParams.WRAP_CONTENT).apply {
12+
gravity = Gravity.BOTTOM
13+
14+
val dp = DensityConverter.toDp(getActivity(), 12)
15+
setMargins(dp, 0, dp, dp)
16+
}
17+
}

library/src/main/java/xyz/klinker/android/floating_tutorial/FloatingTutorialActivity.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ abstract class FloatingTutorialActivity : AppCompatActivity() {
6868
* this instead of just [finish] on the last [TutorialPage].
6969
*/
7070
fun finishAnimated() {
71-
presenter.circularRevealOut()
71+
presenter.revealOut()
7272
}
7373

7474
/**

library/src/main/java/xyz/klinker/android/floating_tutorial/TutorialPage.kt

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,18 @@ abstract class TutorialPage(private val activity: FloatingTutorialActivity) : Fr
4545
private var data: Any? = null
4646
private var pageIndex: Int? = null
4747

48+
internal open val rootLayoutParams: LayoutParams
49+
get() = LayoutParams(
50+
DensityConverter.toDp(activity, 316),
51+
ViewGroup.LayoutParams.WRAP_CONTENT).apply {
52+
gravity = Gravity.CENTER
53+
}
54+
4855
internal fun init(pageIndex: Int) {
4956
val pageCount = activity.getPageCount()
5057
this.pageIndex = pageIndex
5158

52-
val layoutParams = FrameLayout.LayoutParams(DensityConverter.toDp(activity, 316), ViewGroup.LayoutParams.WRAP_CONTENT)
53-
layoutParams.gravity = Gravity.CENTER
54-
55-
rootLayout.layoutParams = layoutParams
59+
rootLayout.layoutParams = rootLayoutParams
5660
super.addView(rootLayout)
5761

5862
if (pageIndex == pageCount - 1) setNextButtonText(R.string.tutorial_finish)
@@ -97,7 +101,7 @@ abstract class TutorialPage(private val activity: FloatingTutorialActivity) : Fr
97101
* Called the first time the [TutorialPage] is displayed. Override this to do any animation work
98102
* on the page elements.
99103
*/
100-
open fun animateLayout() { }
104+
open fun animateLayout() {}
101105

102106
/**
103107
* Get the [FloatingTutorialActivity] that this [TutorialPage] is attached to.

library/src/main/java/xyz/klinker/android/floating_tutorial/TutorialPresenter.kt

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ internal class TutorialPresenter(private val activity: FloatingTutorialActivity,
3232
* Start the [FloatingTutorialActivity] by doing a circular reveal and loading the first page.
3333
*/
3434
fun start() {
35-
circularRevealIn()
35+
revealIn()
3636
pageProvider.currentPage().onShown(true)
3737
}
3838

@@ -42,7 +42,7 @@ internal class TutorialPresenter(private val activity: FloatingTutorialActivity,
4242
fun onBackPressed() {
4343
val previousPage = pageProvider.previousPage()
4444
if (previousPage == null) {
45-
circularRevealOut()
45+
revealOut()
4646
} else {
4747
previousPage.onShown(false)
4848

@@ -58,7 +58,7 @@ internal class TutorialPresenter(private val activity: FloatingTutorialActivity,
5858
fun onNextPressed() {
5959
val nextPage = pageProvider.nextPage()
6060
if (nextPage == null) {
61-
circularRevealOut()
61+
revealOut()
6262

6363
if (activity is TutorialFinishedListener) {
6464
activity.onTutorialFinished()
@@ -76,11 +76,11 @@ internal class TutorialPresenter(private val activity: FloatingTutorialActivity,
7676
* it will be a circular reveal animation. Otherwise, it will be a alpha transition.
7777
*/
7878
@VisibleForTesting
79-
internal fun circularRevealIn() {
79+
internal fun revealIn() {
8080
val firstPage = pageProvider.currentPage()
8181
firstPage.visibility = View.VISIBLE
8282

83-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
83+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && pageProvider.currentPage() !is BottomSheetTutorialPage) {
8484
val cx = firstPage.width / 2
8585
val cy = firstPage.height / 2
8686
val finalRadius = Math.hypot(cx.toDouble(), cy.toDouble()).toFloat()
@@ -93,7 +93,7 @@ internal class TutorialPresenter(private val activity: FloatingTutorialActivity,
9393
}
9494
} else {
9595
firstPage.alpha = 0f
96-
firstPage.animate().alpha(1f).start()
96+
firstPage.animate().alpha(1f).setDuration(200).start()
9797
}
9898

9999
}
@@ -103,10 +103,10 @@ internal class TutorialPresenter(private val activity: FloatingTutorialActivity,
103103
* it will be a circular reveal animation. Otherwise, it will be a alpha transition.
104104
*/
105105
@VisibleForTesting
106-
internal fun circularRevealOut() {
106+
internal fun revealOut() {
107107
val currentPage = pageProvider.currentPage()
108108

109-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
109+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && pageProvider.currentPage() !is BottomSheetTutorialPage) {
110110
val cx = currentPage.width / 2
111111
val cy = currentPage.height / 2
112112
val initialRadius = Math.hypot(cx.toDouble(), cy.toDouble()).toFloat()
@@ -131,7 +131,7 @@ internal class TutorialPresenter(private val activity: FloatingTutorialActivity,
131131
}).start()
132132
}
133133
} else {
134-
currentPage.animate().alpha(0f).setListener(object : AnimatorListenerAdapter() {
134+
currentPage.animate().alpha(0f).setDuration(200).setListener(object : AnimatorListenerAdapter() {
135135
override fun onAnimationEnd(animation: Animator) {
136136
super.onAnimationEnd(animation)
137137
activity.close()

sample-java/src/main/AndroidManifest.xml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@
2727
<activity
2828
android:name="xyz.klinker.floating_tutorial.SampleActivity"
2929
android:theme="@style/AppTheme"
30-
android:windowSoftInputMode="stateHidden">
30+
android:windowSoftInputMode="stateHidden"
31+
android:exported="true">
3132
<intent-filter>
3233
<action android:name="android.intent.action.MAIN" />
3334
<category android:name="android.intent.category.LAUNCHER" />
@@ -49,6 +50,9 @@
4950
<activity
5051
android:name=".examples.PulseSmsPurchaseExample"
5152
android:theme="@style/tutorial_FloatingTutorialTheme" />
53+
<activity
54+
android:name=".examples.BottomSheetExample"
55+
android:theme="@style/tutorial_FloatingTutorialTheme" />
5256

5357
</application>
5458

sample-java/src/main/java/xyz/klinker/floating_tutorial/SampleActivity.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import android.view.View;
2323
import android.widget.Toast;
2424

25+
import xyz.klinker.floating_tutorial.examples.BottomSheetExample;
2526
import xyz.klinker.floating_tutorial.examples.PulseSmsPurchaseExample;
2627
import xyz.klinker.floating_tutorial.examples.RateItExample;
2728
import xyz.klinker.floating_tutorial.examples.SelectionDialogExample;
@@ -73,6 +74,13 @@ public void onClick(View view) {
7374
startActivityForResult(new Intent(SampleActivity.this, PulseSmsPurchaseExample.class), REQUEST_PURCHASE);
7475
}
7576
});
77+
78+
findViewById(R.id.bottom_sheet).setOnClickListener(new View.OnClickListener() {
79+
@Override
80+
public void onClick(View view) {
81+
startActivity(new Intent(SampleActivity.this, BottomSheetExample.class));
82+
}
83+
});
7684
}
7785

7886
@Override
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/*
2+
* Copyright (C) 2017 Luke Klinker
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package xyz.klinker.floating_tutorial.examples;
18+
19+
import java.util.ArrayList;
20+
import java.util.List;
21+
22+
import xyz.klinker.android.floating_tutorial.BottomSheetTutorialPage;
23+
import xyz.klinker.android.floating_tutorial.FloatingTutorialActivity;
24+
import xyz.klinker.android.floating_tutorial.TutorialPage;
25+
import xyz.klinker.floating_tutorial.R;
26+
import xyz.klinker.floating_tutorial.util.AnimationHelper;
27+
28+
public class BottomSheetExample extends FloatingTutorialActivity {
29+
30+
@Override
31+
public List<TutorialPage> getPages() {
32+
List<TutorialPage> pages = new ArrayList<>();
33+
34+
pages.add(new BottomSheetTutorialPage(this) {
35+
@Override
36+
public void initPage() {
37+
setContentView(R.layout.example_feature_walkthrough_page_1);
38+
setBackgroundColorResource(R.color.darkBackgroundColor);
39+
}
40+
41+
@Override
42+
public void animateLayout() {
43+
AnimationHelper.animateGroup(
44+
findViewById(R.id.feature_one_image),
45+
findViewById(R.id.bottom_text)
46+
);
47+
}
48+
});
49+
50+
pages.add(new BottomSheetTutorialPage(this) {
51+
@Override
52+
public void initPage() {
53+
setContentView(R.layout.example_feature_walkthrough_page_2);
54+
}
55+
56+
@Override
57+
public void animateLayout() {
58+
AnimationHelper.animateGroup(
59+
findViewById(R.id.bottom_text),
60+
findViewById(R.id.feature_two_image)
61+
);
62+
}
63+
});
64+
65+
pages.add(new BottomSheetTutorialPage(this) {
66+
@Override
67+
public void initPage() {
68+
setContentView(R.layout.example_feature_walkthrough_page_3);
69+
setBackgroundColorResource(R.color.colorPrimary);
70+
}
71+
72+
@Override
73+
public void animateLayout() {
74+
AnimationHelper.animateGroup(
75+
findViewById(R.id.feature_three_image_one),
76+
findViewById(R.id.feature_three_image_two),
77+
findViewById(R.id.bottom_text)
78+
);
79+
}
80+
});
81+
82+
return pages;
83+
}
84+
}

sample-kotlin/src/main/AndroidManifest.xml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@
2727
<activity
2828
android:name="xyz.klinker.floating_tutorial.SampleActivity"
2929
android:theme="@style/AppTheme"
30-
android:windowSoftInputMode="stateHidden">
30+
android:windowSoftInputMode="stateHidden"
31+
android:exported="true">
3132
<intent-filter>
3233
<action android:name="android.intent.action.MAIN" />
3334
<category android:name="android.intent.category.LAUNCHER" />
@@ -49,6 +50,9 @@
4950
<activity
5051
android:name=".examples.PulseSmsPurchaseExample"
5152
android:theme="@style/tutorial_FloatingTutorialTheme" />
53+
<activity
54+
android:name=".examples.BottomSheetExample"
55+
android:theme="@style/tutorial_FloatingTutorialTheme" />
5256

5357
</application>
5458

sample-kotlin/src/main/java/xyz/klinker/floating_tutorial/SampleActivity.kt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,7 @@ import android.os.Bundle
2222
import androidx.appcompat.app.AppCompatActivity
2323
import android.view.View
2424
import android.widget.Toast
25-
26-
import xyz.klinker.floating_tutorial.examples.FeatureWalkthroughExample
27-
import xyz.klinker.floating_tutorial.examples.PulseSmsPurchaseExample
28-
import xyz.klinker.floating_tutorial.examples.RateItExample
29-
import xyz.klinker.floating_tutorial.examples.SelectionDialogExample
30-
import xyz.klinker.floating_tutorial.examples.SimpleDialogExample
25+
import xyz.klinker.floating_tutorial.examples.*
3126

3227
class SampleActivity : AppCompatActivity() {
3328

@@ -36,6 +31,7 @@ class SampleActivity : AppCompatActivity() {
3631
private val featureTutorial: View by lazy { findViewById<View>(R.id.feature_tutorial) }
3732
private val rateIt: View by lazy { findViewById<View>(R.id.rate_it) }
3833
private val iapFlow: View by lazy { findViewById<View>(R.id.iap_flow) }
34+
private val bottomSheet: View by lazy { findViewById<View>(R.id.bottom_sheet) }
3935

4036
override fun onCreate(savedInstanceState: Bundle?) {
4137
super.onCreate(savedInstanceState)
@@ -60,6 +56,10 @@ class SampleActivity : AppCompatActivity() {
6056
iapFlow.setOnClickListener {
6157
startActivityForResult(Intent(this, PulseSmsPurchaseExample::class.java), REQUEST_PURCHASE)
6258
}
59+
60+
bottomSheet.setOnClickListener {
61+
startActivity(Intent(this, BottomSheetExample::class.java))
62+
}
6363
}
6464

6565
public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {

0 commit comments

Comments
 (0)