-
-
-
\ No newline at end of file
diff --git a/.idea/markdown-navigator-enh.xml b/.idea/markdown-navigator-enh.xml
deleted file mode 100644
index 12fb99d..0000000
--- a/.idea/markdown-navigator-enh.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/markdown-navigator.xml b/.idea/markdown-navigator.xml
deleted file mode 100644
index 4463382..0000000
--- a/.idea/markdown-navigator.xml
+++ /dev/null
@@ -1,55 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
deleted file mode 100644
index e0d5b93..0000000
--- a/.idea/misc.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
deleted file mode 100644
index 03f44ac..0000000
--- a/.idea/modules.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml
deleted file mode 100644
index 7f68460..0000000
--- a/.idea/runConfigurations.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
deleted file mode 100644
index 35eb1dd..0000000
--- a/.idea/vcs.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/README.md b/README.md
index 7845930..8e6b8c0 100644
--- a/README.md
+++ b/README.md
@@ -4,13 +4,12 @@ A ViewPager and a PagerAdapter that can:
1. AutoScroll (On/Off able)
2. Infinite Loop (On/Off able)
-3. ViewPager's height can be wrap_content / an aspect ratio
-4. Adjustable auto scroll interval
-5. Won't scroll nor loop if there is only 1 item
-6. Works well with notifyDataSetChanged()
-7. Supports page indicators
-8. Supports different view types
-9. **(New! 1.2.0)** Support peeking adjacent items (But first and last item will appear only after scroll state is idle)
+3. Adjustable auto scroll interval
+4. Won't scroll nor loop if there is only 1 item
+5. Works well with notifyDataSetChanged()
+6. Supports page indicators
+7. Supports different view types
+7. Support peeking adjacent items (But first and last item will appear only after scroll state is idle)
## Demo Effect
@@ -29,22 +28,21 @@ I cannot find one that fits all of the below requirements:
2. Last updated in less than 3 years
3. Good infinite looping effect
4. Configurable auto-scroll
-5. ViewPager that supports fixed aspect ratio
-6. Good support with Page Indicators
+5. Good support with Page Indicators
-Especially for 6, even some of them supports, they provide built-in indicators only; or does not tell user how to implement their own indicator.
+Especially for 5, even some of them supports, they provide built-in indicators only; or does not tell user how to implement their own indicator.
I wrote this library to tackle all of these problems I faced after trying a whole day with other libraries.
## Usage
### Add to Project
-First make sure `jcenter()` is included as a repository in your **project**'s build.gradle:
+First make sure `mavenCentral()` is included as a repository in your **project**'s build.gradle:
```groovy
allprojects {
repositories {
- jcenter()
+ mavenCentral()
}
}
```
@@ -52,7 +50,7 @@ allprojects {
And then add the below to your app's build.gradle:
```groovy
- implementation 'com.asksira.android:loopingviewpager:1.3.1'
+ implementation 'com.asksira.android:loopingviewpager:1.4.1'
```
### Step 1: Create LoopingViewPager in XML
@@ -60,37 +58,28 @@ And then add the below to your app's build.gradle:
```xml
+ app:layout_constraintDimensionRatio="1.78"/>
```
+(The above xml example is placed inside a ConstraintLayout.)
+
| Attribute Name | Default | Allowed Values |
|:-------------------------|:--------|:------------------------------|
| isInfinite | false | true / false |
| autoScroll | false | true / false |
-| viewpagerAspectRatio | 0 | any float (width / height) |
-| wrap_content(deprecated) | true | true / false |
| scrollInterval | 5000 | any integer (represents ms) |
-| itemAspectRatio | 0 | any float (width / height) |
-
-viewpagerAspectRatio 0 means does not apply aspectRatio.
-That means, default LoopingViewPager has no aspect ratio and wrap_content is true.
-Once aspect ratio is set, wrap_content will be overridden (meaningless).
-In most cases, you should set an aspect ratio.
+Please note that the height of `LoopingViewPager` should be decided by its parent, like all other Views.
+If you want it to have a specific aspect ratio, you can place it inside a `ConstraintLayout` and give it the attribute `layout_constraintDimensionRatio`.
-`itemAspectRatio` is the aspectRatio of the the item. So, if itemAspectRatio is higher than viewpagerAspectRatio, you can use `clipToPadding="false"` to create a peek item effect.
-You can refer to [#17](https://github.com/siralam/LoopingViewPager/issues/17).
+(The old versions of this library uses an internal attribute to determine its height, which is completely wrong and can lead to bugs!)
-If you wonder why you need to set `app:wrap_content="true"`, take a look at [this Stackoverflow post](https://stackoverflow.com/questions/8394681/android-i-am-unable-to-have-viewpager-wrap-content).
-
-**wrap_content is deprecated in v1.1.3**. It is still available but I think there can be unknown problems. I am not going to debug issues related to setting wrap_content to true as well.
+Note: If you want the ViewPager to be able to peek adjacent items, make use of `clipToPadding=false` and set padding to the ViewPager. (`itemAspectRatio` has been removed in v1.4.1)
### Step 2: Create your PagerAdapter that extends LoopingPagerAdapter
@@ -102,10 +91,9 @@ You should
```kotlin
class DemoInfiniteAdapter(
- context: Context,
itemList: ArrayList,
isInfinite: Boolean
-) : LoopingPagerAdapter(context, itemList, isInfinite) {
+) : LoopingPagerAdapter(itemList, isInfinite) {
//This method will be triggered if the item View has not been inflated before.
override fun inflateView(
@@ -113,7 +101,7 @@ class DemoInfiniteAdapter(
container: ViewGroup,
listPosition: Int
): View {
- return LayoutInflater.from(context).inflate(R.layout.item_pager, container, false)
+ return LayoutInflater.from(container.context).inflate(R.layout.item_pager, container, false)
}
//Bind your data with your item View here.
@@ -125,7 +113,7 @@ class DemoInfiniteAdapter(
listPosition: Int,
viewType: Int
) {
- convertView.findViewById(R.id.image).setBackgroundColor(context.resources.getColor(getBackgroundColor(listPosition)))
+ convertView.findViewById(R.id.image).setBackgroundColor(convertView.context.resources.getColor(getBackgroundColor(listPosition)))
val description = convertView.findViewById(R.id.description)
description.text = itemList?.get(listPosition).toString()
}
@@ -135,7 +123,7 @@ class DemoInfiniteAdapter(
### Step 3: Bind LoopingViewPager with your Adapter
```kotlin
- adapter = DemoInfiniteAdapter(context, dataItems, true)
+ adapter = DemoInfiniteAdapter(dataItems, true)
loopingViewPager.setAdapter(adapter)
```
@@ -252,6 +240,12 @@ customShapePagerIndicator.updateIndicatorCounts(loopingViewPager.indicatorCount)
## Release notes
+v1.4.1
+- Removed setting aspect ratio inside LoopingViewPager. Let its parent to decide how to layout it (i.e. its height).
+- Same as above, removed itemAspectRatio as well. You can actually simply set it through padding and `clipToPadding=false`.
+- Removed unnecessary context as a param in LoopingPagerAdapter's constructor.
+- Migrated from JCenter() to MavenCentral().
+
v1.3.2
- Fixed crash due to getChildAt() returns null
diff --git a/app/build.gradle b/app/build.gradle
index f8ae5aa..b2d02c2 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,14 +1,13 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
-apply plugin: 'kotlin-android-extensions'
android {
- compileSdkVersion 29
+ compileSdkVersion 30
defaultConfig {
applicationId "com.asksira.loopingviewpagerdemo"
minSdkVersion 16
- targetSdkVersion 29
+ targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
@@ -22,13 +21,10 @@ android {
}
dependencies {
- implementation fileTree(include: ['*.jar'], dir: 'libs')
- implementation 'androidx.appcompat:appcompat:1.1.0'
- implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
+ implementation 'androidx.appcompat:appcompat:1.2.0'
+ implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation project(':loopingviewpager')
- implementation "androidx.core:core-ktx:+"
+// implementation 'com.asksira.android:loopingviewpager:1.4.1'
+ implementation "androidx.core:core-ktx:1.3.2"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
}
-repositories {
- mavenCentral()
-}
diff --git a/app/src/main/java/com/asksira/loopingviewpagerdemo/DemoInfiniteAdapter.kt b/app/src/main/java/com/asksira/loopingviewpagerdemo/DemoInfiniteAdapter.kt
index 18584f1..ec2d629 100644
--- a/app/src/main/java/com/asksira/loopingviewpagerdemo/DemoInfiniteAdapter.kt
+++ b/app/src/main/java/com/asksira/loopingviewpagerdemo/DemoInfiniteAdapter.kt
@@ -1,6 +1,5 @@
package com.asksira.loopingviewpagerdemo
-import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@@ -9,10 +8,9 @@ import com.asksira.loopingviewpager.LoopingPagerAdapter
import java.util.*
class DemoInfiniteAdapter(
- context: Context,
itemList: ArrayList,
isInfinite: Boolean
-) : LoopingPagerAdapter(context, itemList, isInfinite) {
+) : LoopingPagerAdapter(itemList, isInfinite) {
override fun getItemViewType(listPosition: Int): Int {
return if (itemList?.get(listPosition) == 0) VIEW_TYPE_SPECIAL else VIEW_TYPE_NORMAL
@@ -24,8 +22,8 @@ class DemoInfiniteAdapter(
listPosition: Int
): View {
return if (viewType == VIEW_TYPE_SPECIAL) LayoutInflater.from(
- context
- ).inflate(R.layout.item_special, container, false) else LayoutInflater.from(context)
+ container.context
+ ).inflate(R.layout.item_special, container, false) else LayoutInflater.from(container.context)
.inflate(R.layout.item_pager, container, false)
}
@@ -36,7 +34,7 @@ class DemoInfiniteAdapter(
) {
if (viewType == VIEW_TYPE_SPECIAL) return
convertView.findViewById(R.id.image)
- .setBackgroundColor(context.resources.getColor(getBackgroundColor(listPosition)))
+ .setBackgroundColor(convertView.context.resources.getColor(getBackgroundColor(listPosition)))
val description = convertView.findViewById(R.id.description)
description.text = itemList?.get(listPosition).toString()
}
diff --git a/app/src/main/java/com/asksira/loopingviewpagerdemo/MainActivity.kt b/app/src/main/java/com/asksira/loopingviewpagerdemo/MainActivity.kt
index 881b1b3..3a6bc8d 100644
--- a/app/src/main/java/com/asksira/loopingviewpagerdemo/MainActivity.kt
+++ b/app/src/main/java/com/asksira/loopingviewpagerdemo/MainActivity.kt
@@ -39,7 +39,8 @@ class MainActivity : AppCompatActivity() {
page4 = findViewById(R.id.page4)
page5 = findViewById(R.id.page5)
page6 = findViewById(R.id.page6)
- adapter = DemoInfiniteAdapter(this, createDummyItems(), true)
+
+ adapter = DemoInfiniteAdapter(createDummyItems(), true)
viewPager.adapter = adapter
//Custom bind indicator
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index c7c8ba1..fa20a17 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -9,15 +9,16 @@
(
- protected var context: Context,
itemList: List,
isInfinite: Boolean
) : PagerAdapter() {
diff --git a/loopingviewpager/src/main/java/com/asksira/loopingviewpager/LoopingViewPager.kt b/loopingviewpager/src/main/java/com/asksira/loopingviewpager/LoopingViewPager.kt
index 04b3d0a..6322220 100644
--- a/loopingviewpager/src/main/java/com/asksira/loopingviewpager/LoopingViewPager.kt
+++ b/loopingviewpager/src/main/java/com/asksira/loopingviewpager/LoopingViewPager.kt
@@ -2,11 +2,10 @@ package com.asksira.loopingviewpager
import android.content.Context
import android.os.Handler
+import android.os.Looper
import android.util.AttributeSet
import androidx.viewpager.widget.PagerAdapter
import androidx.viewpager.widget.ViewPager
-import kotlin.math.floor
-import kotlin.math.roundToInt
/**
* A ViewPager that auto-scrolls, and supports infinite scroll.
@@ -16,14 +15,12 @@ class LoopingViewPager : ViewPager {
protected var isInfinite = true
protected var isAutoScroll = false
protected var wrapContent = true
- protected var aspectRatio = 0f
- protected var itemAspectRatio = 0f
//AutoScroll
private var interval = 5000
private var currentPagePosition = 0
private var isAutoScrollResumed = false
- private val autoScrollHandler = Handler()
+ private val autoScrollHandler = Handler(Looper.getMainLooper())
private val autoScrollRunnable = Runnable {
if (adapter == null || !isAutoScroll || adapter?.count ?: 0 < 2) return@Runnable
if (!isInfinite && adapter?.count ?: 0 - 1 == currentPagePosition) {
@@ -54,8 +51,6 @@ class LoopingViewPager : ViewPager {
isAutoScroll = a.getBoolean(R.styleable.LoopingViewPager_autoScroll, false)
wrapContent = a.getBoolean(R.styleable.LoopingViewPager_wrap_content, true)
interval = a.getInt(R.styleable.LoopingViewPager_scrollInterval, 5000)
- aspectRatio = a.getFloat(R.styleable.LoopingViewPager_viewpagerAspectRatio, 0f)
- itemAspectRatio = a.getFloat(R.styleable.LoopingViewPager_itemAspectRatio, 0f)
isAutoScrollResumed = isAutoScroll
} finally {
a.recycle()
@@ -63,96 +58,6 @@ class LoopingViewPager : ViewPager {
init()
}
- override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
- var heightMeasureSpec = heightMeasureSpec
- val width = MeasureSpec.getSize(widthMeasureSpec)
- if (aspectRatio > 0) {
- val height =
- (MeasureSpec.getSize(widthMeasureSpec).toFloat() / aspectRatio).roundToInt()
- val finalWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY)
- val finalHeightMeasureSpec =
- MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)
-
- /*
- * If child items can scale, fit inside their parent by increasing left/right padding.
- * https://github.com/siralam/LoopingViewPager/issues/17
- */if (itemAspectRatio > 0 && itemAspectRatio != aspectRatio) {
- // super has to be called in the beginning so the child views can be initialized.
- super.onMeasure(widthMeasureSpec, heightMeasureSpec)
- // Remove padding from width
- var childWidthSize = width - paddingLeft - paddingRight
- // Make child width MeasureSpec
- var childWidthMeasureSpec =
- MeasureSpec.makeMeasureSpec(childWidthSize, MeasureSpec.EXACTLY)
- var i = 0
- while (i < childCount) {
- val child = getChildAt(i)
- child.measure(
- childWidthMeasureSpec,
- MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)
- )
- val w = child.measuredWidth
- val h = child.measuredHeight
- if (h > 0 && h > height) {
- val ratio = w.toFloat() / h
- // Round down largest width that fits.
- val optimalWidth =
- floor(height * ratio.toDouble())
- // Round up new padding size.
- val newPadding =
- ((width - optimalWidth) / 2).roundToInt()
- // Set new padding values
- setPadding(newPadding, paddingTop, newPadding, paddingBottom)
- // Remove padding from width
- childWidthSize = width - paddingLeft - paddingRight
- // Make child width MeasureSpec
- childWidthMeasureSpec =
- MeasureSpec.makeMeasureSpec(childWidthSize, MeasureSpec.EXACTLY)
- child.measure(
- childWidthMeasureSpec,
- MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)
- )
- } else {
- i++
- }
- }
- }
- super.onMeasure(finalWidthMeasureSpec, finalHeightMeasureSpec)
- } else {
- //https://stackoverflow.com/a/24666987/7870874
- if (wrapContent) {
- val mode = MeasureSpec.getMode(heightMeasureSpec)
- // Unspecified means that the ViewPager is in a ScrollView WRAP_CONTENT.
- // At Most means that the ViewPager is not in a ScrollView WRAP_CONTENT.
- if (mode == MeasureSpec.UNSPECIFIED || mode == MeasureSpec.AT_MOST) {
- // super has to be called in the beginning so the child views can be initialized.
- super.onMeasure(widthMeasureSpec, heightMeasureSpec)
- var height = 0
- // Remove padding from width
- val childWidthSize = width - paddingLeft - paddingRight
- // Make child width MeasureSpec
- val childWidthMeasureSpec =
- MeasureSpec.makeMeasureSpec(childWidthSize, MeasureSpec.EXACTLY)
- for (i in 0 until childCount) {
- val child = getChildAt(i)
- child.measure(
- childWidthMeasureSpec,
- MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)
- )
- val h = child.measuredHeight
- if (h > height) {
- height = h
- }
- }
- // Add padding back to child height
- height += paddingTop + paddingBottom
- heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)
- }
- }
- super.onMeasure(widthMeasureSpec, heightMeasureSpec)
- }
- }
-
protected fun init() {
addOnPageChangeListener(object : OnPageChangeListener {
override fun onPageScrolled(