diff --git a/CHANGELOG.md b/CHANGELOG.md
index e7689f3..48b1cfe 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,7 +1,12 @@
Change Log
==========
-## Version 2.0.0, 2.0.1 *(2021-05-22)* 🚀
+## Version 2.0.2 *(2021-05-31)* 🚀
+
+* 🆕 `registerLifecycle(lifecycleOwner: LifecycleOwner)` method added.
+* 🛠️ Java sample converted into a `Fragment` example.
+
+## Version 2.0.0, 2.0.1 *(2021-05-22)*
* 🆕 Previous boring custom layout system removed. And view-binding supported custom layout system added. See `CarouselListener` in the sample app for details. 🎉
* 🆕 The carousel is now supported Infinite ∞ looping (Infinite Carousel) 🥳! It's default now. You can disable it by setting `infiniteCarousel` to `false`.
diff --git a/README.md b/README.md
index 5242332..b0f268f 100644
--- a/README.md
+++ b/README.md
@@ -26,10 +26,10 @@ dependencies {
// Material Components for Android. Replace the version with the latest version of Material Components library.
implementation 'com.google.android.material:material:1.3.0'
- // Optional: Circle Indicator (To fix the xml preview "Missing classes" error)
+ // Circle Indicator (To fix the xml preview "Missing classes" error)
implementation 'me.relex:circleindicator:2.1.6'
- implementation 'org.imaginativeworld.whynotimagecarousel:whynotimagecarousel:2.0.1'
+ implementation 'org.imaginativeworld.whynotimagecarousel:whynotimagecarousel:2.0.2'
}
```
diff --git a/gradle.properties b/gradle.properties
index 63feb68..c0221cc 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -24,7 +24,7 @@ kotlin.code.style=official
# ----------------
GROUP=org.imaginativeworld.whynotimagecarousel
POM_ARTIFACT_ID=whynotimagecarousel
-VERSION_NAME=2.0.1
+VERSION_NAME=2.0.2
# ----------------
POM_NAME=Why Not! Image Carousel!
POM_DESCRIPTION=An easy, super simple and customizable image carousel view for Android.
diff --git a/sample/build.gradle b/sample/build.gradle
index b0f7c36..905fa27 100644
--- a/sample/build.gradle
+++ b/sample/build.gradle
@@ -65,6 +65,9 @@ dependencies {
implementation 'com.github.bumptech.glide:glide:4.12.0'
kapt 'com.github.bumptech.glide:compiler:4.12.0'
+ // Kotlin
+ implementation "androidx.fragment:fragment-ktx:1.3.4"
+
// debugImplementation because LeakCanary should only run in debug builds.
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.7'
}
diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml
index 79ac768..43f4a87 100644
--- a/sample/src/main/AndroidManifest.xml
+++ b/sample/src/main/AndroidManifest.xml
@@ -9,7 +9,6 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
-
@@ -17,6 +16,8 @@
+
+
\ No newline at end of file
diff --git a/sample/src/main/java/org/imaginativeworld/whynotimagecarousel/sample/JavaActivity.java b/sample/src/main/java/org/imaginativeworld/whynotimagecarousel/sample/JavaActivity.java
index e9b2f77..c764073 100644
--- a/sample/src/main/java/org/imaginativeworld/whynotimagecarousel/sample/JavaActivity.java
+++ b/sample/src/main/java/org/imaginativeworld/whynotimagecarousel/sample/JavaActivity.java
@@ -1,187 +1,19 @@
package org.imaginativeworld.whynotimagecarousel.sample;
-import android.content.Context;
-import android.graphics.Color;
-import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.ViewGroup;
-import android.widget.ImageView;
import androidx.appcompat.app.AppCompatActivity;
-import androidx.core.content.ContextCompat;
-import androidx.recyclerview.widget.RecyclerView;
-import androidx.viewbinding.ViewBinding;
-import com.google.android.material.button.MaterialButton;
-
-import org.imaginativeworld.whynotimagecarousel.listener.CarouselListener;
-import org.imaginativeworld.whynotimagecarousel.listener.CarouselOnScrollListener;
-import org.imaginativeworld.whynotimagecarousel.model.CarouselGravity;
-import org.imaginativeworld.whynotimagecarousel.model.CarouselItem;
-import org.imaginativeworld.whynotimagecarousel.model.CarouselType;
import org.imaginativeworld.whynotimagecarousel.sample.databinding.ActivityJavaBinding;
-import org.imaginativeworld.whynotimagecarousel.utils.Utils;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import me.relex.circleindicator.CircleIndicator2;
public class JavaActivity extends AppCompatActivity {
private ActivityJavaBinding binding;
- private Context context;
-
- private boolean isStarted = false;
-
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityJavaBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
-
- context = this;
-
- binding.carousel.registerLifecycle(getLifecycle());
-
- binding.carousel.setShowTopShadow(false);
- binding.carousel.setTopShadowAlpha(0.6f); // 0 to 1, 1 means 100%
- binding.carousel.setTopShadowHeight(Utils.dpToPx(32, context)); // px value of dp
-
- binding.carousel.setShowBottomShadow(true);
- binding.carousel.setBottomShadowAlpha(0.7f); // 0 to 1, 1 means 100%
- binding.carousel.setBottomShadowHeight(Utils.dpToPx(48, context)); // px value of dp
-
- binding.carousel.setShowCaption(true);
- binding.carousel.setCaptionMargin(Utils.dpToPx(8, context)); // px value of dp
- binding.carousel.setCaptionTextSize(Utils.spToPx(16, context)); // px value of sp
-
- binding.carousel.setShowIndicator(false);
- binding.carousel.setIndicatorMargin(Utils.dpToPx(0, context)); // px value of dp
-
- binding.carousel.setImageScaleType(ImageView.ScaleType.CENTER_CROP);
-
- binding.carousel.setCarouselBackground(new ColorDrawable(Color.parseColor("#333333")));
- binding.carousel.setImagePlaceholder(ContextCompat.getDrawable(
- this,
- R.drawable.ic_wb_cloudy_with_padding
- ));
-
- binding.carousel.setCarouselPadding(Utils.dpToPx(0, context));
- binding.carousel.setCarouselPaddingStart(Utils.dpToPx(0, context));
- binding.carousel.setCarouselPaddingTop(Utils.dpToPx(0, context));
- binding.carousel.setCarouselPaddingEnd(Utils.dpToPx(0, context));
- binding.carousel.setCarouselPaddingBottom(Utils.dpToPx(0, context));
-
- binding.carousel.setShowNavigationButtons(false);
- binding.carousel.setPreviousButtonLayout(R.layout.custom_previous_button_layout);
- binding.carousel.setPreviousButtonId(R.id.custom_btn_previous);
- binding.carousel.setPreviousButtonMargin(Utils.dpToPx(8, context)); // px value of dp
- binding.carousel.setNextButtonLayout(R.layout.custom_next_button_layout);
- binding.carousel.setNextButtonId(R.id.custom_btn_next);
- binding.carousel.setNextButtonMargin(Utils.dpToPx(8, context)); // px value of dp
-
- binding.carousel.setCarouselType(CarouselType.SHOWCASE);
-
- binding.carousel.setCarouselGravity(CarouselGravity.CENTER);
-
- binding.carousel.setScaleOnScroll(false);
- binding.carousel.setScalingFactor(.15f);
- binding.carousel.setAutoWidthFixing(true);
- binding.carousel.setAutoPlay(false);
- binding.carousel.setAutoPlayDelay(3000); // Milliseconds
- binding.carousel.setInfiniteCarousel(true);
- binding.carousel.setTouchToPause(true);
-
- binding.carousel.setOnScrollListener(new CarouselOnScrollListener() {
- @Override
- public void onScrolled(@NotNull RecyclerView recyclerView, int dx, int dy, int position, @Nullable CarouselItem carouselItem) {
- // ...
- }
-
- @Override
- public void onScrollStateChanged(@NotNull RecyclerView recyclerView, int newState, int position, @Nullable CarouselItem carouselItem) {
- // ...
- }
- });
-
- binding.carousel.setCarouselListener(new CarouselListener() {
- @Nullable
- @Override
- public ViewBinding onCreateViewHolder(@NotNull LayoutInflater layoutInflater, @NotNull ViewGroup parent) {
- // ...
- return null;
- }
-
- @Override
- public void onBindViewHolder(@NotNull ViewBinding binding, @NotNull CarouselItem item, int position) {
- // ...
- }
-
- @Override
- public void onLongClick(int position, @NotNull CarouselItem carouselItem) {
- // ...
- }
-
- @Override
- public void onClick(int position, @NotNull CarouselItem carouselItem) {
- // ...
- }
- });
-
- CircleIndicator2 indicator = findViewById(R.id.custom_indicator);
- binding.carousel.setIndicator(indicator);
-
- MaterialButton previousBtn = findViewById(R.id.btn_goto_previous);
- previousBtn.setOnClickListener(v -> binding.carousel.previous());
-
- MaterialButton nextBtn = findViewById(R.id.btn_goto_next);
- nextBtn.setOnClickListener(v -> binding.carousel.next());
-
- List list = new ArrayList<>();
-
- // Dummy header
- Map headers = new HashMap<>();
- headers.put("header_key", "header_value");
-
- int index = 1;
- for (String item : DataSet.INSTANCE.getOne()) {
- list.add(
- new CarouselItem(
- item,
- "Image " + index++ + " of " + DataSet.INSTANCE.getOne().size(),
- headers
- )
- );
- }
-
- binding.carousel.setData(list);
-
- // ----------------------------------------------------------------
-
- binding.fabPlay.setOnClickListener(v -> {
- if (isStarted) {
-
- isStarted = false;
- binding.carousel.stop();
-
- binding.fabPlay.setText("Start");
-
- } else {
-
- isStarted = true;
- binding.carousel.start();
-
- binding.fabPlay.setText("Stop");
-
- }
- });
-
}
}
diff --git a/sample/src/main/java/org/imaginativeworld/whynotimagecarousel/sample/SampleFragment.java b/sample/src/main/java/org/imaginativeworld/whynotimagecarousel/sample/SampleFragment.java
new file mode 100644
index 0000000..87eb147
--- /dev/null
+++ b/sample/src/main/java/org/imaginativeworld/whynotimagecarousel/sample/SampleFragment.java
@@ -0,0 +1,194 @@
+package org.imaginativeworld.whynotimagecarousel.sample;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.core.content.ContextCompat;
+import androidx.fragment.app.Fragment;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.viewbinding.ViewBinding;
+
+import com.google.android.material.button.MaterialButton;
+
+import org.imaginativeworld.whynotimagecarousel.listener.CarouselListener;
+import org.imaginativeworld.whynotimagecarousel.listener.CarouselOnScrollListener;
+import org.imaginativeworld.whynotimagecarousel.model.CarouselGravity;
+import org.imaginativeworld.whynotimagecarousel.model.CarouselItem;
+import org.imaginativeworld.whynotimagecarousel.model.CarouselType;
+import org.imaginativeworld.whynotimagecarousel.sample.databinding.FragmentSampleBinding;
+import org.imaginativeworld.whynotimagecarousel.utils.Utils;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import me.relex.circleindicator.CircleIndicator2;
+
+public class SampleFragment extends Fragment {
+
+ private FragmentSampleBinding binding;
+
+ private Context context;
+
+ private boolean isStarted = false;
+
+ public SampleFragment() {
+ }
+
+ @Nullable
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ binding = FragmentSampleBinding.inflate(getLayoutInflater(), container, false);
+ return binding.getRoot();
+ }
+
+ @Override
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ context = requireContext();
+
+ binding.carousel.registerLifecycle(getViewLifecycleOwner());
+
+ binding.carousel.setShowTopShadow(false);
+ binding.carousel.setTopShadowAlpha(0.6f); // 0 to 1, 1 means 100%
+ binding.carousel.setTopShadowHeight(Utils.dpToPx(32, context)); // px value of dp
+
+ binding.carousel.setShowBottomShadow(true);
+ binding.carousel.setBottomShadowAlpha(0.7f); // 0 to 1, 1 means 100%
+ binding.carousel.setBottomShadowHeight(Utils.dpToPx(48, context)); // px value of dp
+
+ binding.carousel.setShowCaption(true);
+ binding.carousel.setCaptionMargin(Utils.dpToPx(8, context)); // px value of dp
+ binding.carousel.setCaptionTextSize(Utils.spToPx(16, context)); // px value of sp
+
+ binding.carousel.setShowIndicator(false);
+ binding.carousel.setIndicatorMargin(Utils.dpToPx(0, context)); // px value of dp
+
+ binding.carousel.setImageScaleType(ImageView.ScaleType.CENTER_CROP);
+
+ binding.carousel.setCarouselBackground(new ColorDrawable(Color.parseColor("#333333")));
+ binding.carousel.setImagePlaceholder(ContextCompat.getDrawable(
+ context,
+ R.drawable.ic_wb_cloudy_with_padding
+ ));
+
+ binding.carousel.setCarouselPadding(Utils.dpToPx(0, context));
+ binding.carousel.setCarouselPaddingStart(Utils.dpToPx(0, context));
+ binding.carousel.setCarouselPaddingTop(Utils.dpToPx(0, context));
+ binding.carousel.setCarouselPaddingEnd(Utils.dpToPx(0, context));
+ binding.carousel.setCarouselPaddingBottom(Utils.dpToPx(0, context));
+
+ binding.carousel.setShowNavigationButtons(false);
+ binding.carousel.setPreviousButtonLayout(R.layout.custom_previous_button_layout);
+ binding.carousel.setPreviousButtonId(R.id.custom_btn_previous);
+ binding.carousel.setPreviousButtonMargin(Utils.dpToPx(8, context)); // px value of dp
+ binding.carousel.setNextButtonLayout(R.layout.custom_next_button_layout);
+ binding.carousel.setNextButtonId(R.id.custom_btn_next);
+ binding.carousel.setNextButtonMargin(Utils.dpToPx(8, context)); // px value of dp
+
+ binding.carousel.setCarouselType(CarouselType.SHOWCASE);
+
+ binding.carousel.setCarouselGravity(CarouselGravity.CENTER);
+
+ binding.carousel.setScaleOnScroll(false);
+ binding.carousel.setScalingFactor(.15f);
+ binding.carousel.setAutoWidthFixing(true);
+ binding.carousel.setAutoPlay(false);
+ binding.carousel.setAutoPlayDelay(3000); // Milliseconds
+ binding.carousel.setInfiniteCarousel(true);
+ binding.carousel.setTouchToPause(true);
+
+ binding.carousel.setOnScrollListener(new CarouselOnScrollListener() {
+ @Override
+ public void onScrolled(@NotNull RecyclerView recyclerView, int dx, int dy, int position, @org.jetbrains.annotations.Nullable CarouselItem carouselItem) {
+ // ...
+ }
+
+ @Override
+ public void onScrollStateChanged(@NotNull RecyclerView recyclerView, int newState, int position, @org.jetbrains.annotations.Nullable CarouselItem carouselItem) {
+ // ...
+ }
+ });
+
+ binding.carousel.setCarouselListener(new CarouselListener() {
+ @org.jetbrains.annotations.Nullable
+ @Override
+ public ViewBinding onCreateViewHolder(@NotNull LayoutInflater layoutInflater, @NotNull ViewGroup parent) {
+ // ...
+ return null;
+ }
+
+ @Override
+ public void onBindViewHolder(@NotNull ViewBinding binding, @NotNull CarouselItem item, int position) {
+ // ...
+ }
+
+ @Override
+ public void onLongClick(int position, @NotNull CarouselItem carouselItem) {
+ // ...
+ }
+
+ @Override
+ public void onClick(int position, @NotNull CarouselItem carouselItem) {
+ // ...
+ }
+ });
+
+ CircleIndicator2 indicator = binding.customIndicator;
+ binding.carousel.setIndicator(indicator);
+
+ MaterialButton previousBtn = binding.btnGotoPrevious;
+ previousBtn.setOnClickListener(v -> binding.carousel.previous());
+
+ MaterialButton nextBtn = binding.btnGotoNext;
+ nextBtn.setOnClickListener(v -> binding.carousel.next());
+
+ List list = new ArrayList<>();
+
+ // Dummy header
+ Map headers = new HashMap<>();
+ headers.put("header_key", "header_value");
+
+ int index = 1;
+ for (String item : DataSet.INSTANCE.getOne()) {
+ list.add(
+ new CarouselItem(
+ item,
+ "Image " + index++ + " of " + DataSet.INSTANCE.getOne().size(),
+ headers
+ )
+ );
+ }
+
+ binding.carousel.setData(list);
+
+ // ----------------------------------------------------------------
+
+ binding.fabPlay.setOnClickListener(v -> {
+ if (isStarted) {
+
+ isStarted = false;
+ binding.carousel.stop();
+
+ binding.fabPlay.setText("Start");
+
+ } else {
+
+ isStarted = true;
+ binding.carousel.start();
+
+ binding.fabPlay.setText("Stop");
+
+ }
+ });
+ }
+}
\ No newline at end of file
diff --git a/sample/src/main/res/layout/activity_java.xml b/sample/src/main/res/layout/activity_java.xml
index e0324fc..4f532ff 100644
--- a/sample/src/main/res/layout/activity_java.xml
+++ b/sample/src/main/res/layout/activity_java.xml
@@ -1,110 +1,15 @@
-
+ android:layout_height="match_parent"
+ tools:layout="@layout/fragment_sample" />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+
diff --git a/sample/src/main/res/layout/fragment_sample.xml b/sample/src/main/res/layout/fragment_sample.xml
new file mode 100644
index 0000000..5563b96
--- /dev/null
+++ b/sample/src/main/res/layout/fragment_sample.xml
@@ -0,0 +1,114 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sample/src/main/res/values/styles.xml b/sample/src/main/res/values/styles.xml
index ef5923c..7235824 100644
--- a/sample/src/main/res/values/styles.xml
+++ b/sample/src/main/res/values/styles.xml
@@ -20,4 +20,9 @@
- textStart
+
+
diff --git a/whynotimagecarousel/src/main/java/org/imaginativeworld/whynotimagecarousel/ImageCarousel.kt b/whynotimagecarousel/src/main/java/org/imaginativeworld/whynotimagecarousel/ImageCarousel.kt
index 4910a48..956eb36 100644
--- a/whynotimagecarousel/src/main/java/org/imaginativeworld/whynotimagecarousel/ImageCarousel.kt
+++ b/whynotimagecarousel/src/main/java/org/imaginativeworld/whynotimagecarousel/ImageCarousel.kt
@@ -22,6 +22,7 @@ import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver
+import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.OnLifecycleEvent
import androidx.recyclerview.widget.*
import me.relex.circleindicator.CircleIndicator2
@@ -1114,6 +1115,17 @@ class ImageCarousel(
lifecycle.addObserver(this)
}
+ /**
+ * It receives lifecycle owner as a parameter, especially for fragments.
+ *
+ * @see [registerLifecycle] for details.
+ *
+ * @param lifecycleOwner A [androidx.lifecycle.LifecycleOwner]
+ */
+ fun registerLifecycle(lifecycleOwner: LifecycleOwner) {
+ lifecycleOwner.lifecycle.addObserver(this)
+ }
+
// ----------------------------------------------------------------
/**