{"id":13611507,"url":"https://github.com/siralam/LoopingViewPager","last_synced_at":"2025-04-13T04:34:49.545Z","repository":{"id":27677418,"uuid":"114742656","full_name":"siralam/LoopingViewPager","owner":"siralam","description":"A ViewPager and PagerAdapter combination that support auto scroll, infinite loop and page indicators.","archived":false,"fork":false,"pushed_at":"2022-06-30T08:51:37.000Z","size":4775,"stargazers_count":531,"open_issues_count":9,"forks_count":63,"subscribers_count":13,"default_branch":"master","last_synced_at":"2025-04-07T18:45:06.626Z","etag":null,"topics":["android","auto-scroll","autoscrolling","autoscrollviewpager","indicator","infinite","infinite-scroll","loop","looping","loopingviewpager","pageindicator","pageindicatorview","pageradapter","viewpager"],"latest_commit_sha":null,"homepage":null,"language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/siralam.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-12-19T09:01:42.000Z","updated_at":"2025-03-23T15:01:03.000Z","dependencies_parsed_at":"2022-09-10T12:21:47.760Z","dependency_job_id":null,"html_url":"https://github.com/siralam/LoopingViewPager","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/siralam%2FLoopingViewPager","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/siralam%2FLoopingViewPager/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/siralam%2FLoopingViewPager/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/siralam%2FLoopingViewPager/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/siralam","download_url":"https://codeload.github.com/siralam/LoopingViewPager/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248665157,"owners_count":21142118,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","auto-scroll","autoscrolling","autoscrollviewpager","indicator","infinite","infinite-scroll","loop","looping","loopingviewpager","pageindicator","pageindicatorview","pageradapter","viewpager"],"created_at":"2024-08-01T19:01:56.616Z","updated_at":"2025-04-13T04:34:49.022Z","avatar_url":"https://github.com/siralam.png","language":"Kotlin","funding_links":[],"categories":["Kotlin"],"sub_categories":[],"readme":"# Deprecated (Temp)\n\nI think I am not maintaining version 1.x.x anymore, and if I have time and interested in the future, I might re-write it using Compose.\n\nWith that said, I do think v1.4.1 is stable enough to use with ViewPager (Not ViewPager2). In case it is having issue with new versions of Kotlin / Android libraries, I wish you can folk it and use it with simple fixes. Thank you!\n\n# LoopingViewPager\n\nA ViewPager and a PagerAdapter that can:\n\n1. AutoScroll (On/Off able)\n2. Infinite Loop (On/Off able)\n3. Adjustable auto scroll interval\n4. Won't scroll nor loop if there is only 1 item\n5. Works well with notifyDataSetChanged()\n6. Supports page indicators\n7. Supports different view types\n7. Support peeking adjacent items (But first and last item will appear only after scroll state is idle)\n\n## Demo Effect\n\n\u003cp\u003e\n\u003cimg src=\"readme_images/loopingViewPager_auto.gif\" width=\"250\" vspace=\"20\" hspace=\"5\" alt=\"Auto Scroll and Infinite Loop\" /\u003e\n\u003cimg src=\"readme_images/loopingViewPagerDemo_2.gif\" width=\"250\" vspace=\"20\" hspace=\"5\" alt=\"Manual Scroll and Infinite Loop\" /\u003e\n\u003cimg src=\"readme_images/loopingViewPagerDemo_3.gif\" width=\"250\" vspace=\"20\" hspace=\"5\" alt=\"Page skipping\" /\u003e\n\u003c/p\u003e\n\n## Why this library\n\nAlthough there are already quite a number of similar libraries out there,  \nI cannot find one that fits all of the below requirements:  \n\n1. Sufficient documentation\n2. Last updated in less than 3 years\n3. Good infinite looping effect \n4. Configurable auto-scroll\n5. Good support with Page Indicators\n\nEspecially for 5, even some of them supports, they provide built-in indicators only; or does not tell user how to implement their own indicator.  \nI wrote this library to tackle all of these problems I faced after trying a whole day with other libraries.\n\n## Usage\n\n### Add to Project\n\nFirst make sure `mavenCentral()` is included as a repository in your **project**'s build.gradle:  \n\n```groovy\nallprojects {\n    repositories {\n        mavenCentral()\n    }\n}\n```\n\nAnd then add the below to your app's build.gradle:  \n\n```groovy\n    implementation 'com.asksira.android:loopingviewpager:1.4.1'\n```\n\n### Step 1: Create LoopingViewPager in XML\n\n```xml\n    \u003ccom.asksira.loopingviewpager.LoopingViewPager\n        android:id=\"@+id/viewpager\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"0dp\"\n        app:isInfinite=\"true\"\n        app:autoScroll=\"true\"\n        app:scrollInterval=\"5000\"\n        app:layout_constraintDimensionRatio=\"1.78\"/\u003e\n```\n\n(The above xml example is placed inside a ConstraintLayout.)\n\n| Attribute Name           | Default | Allowed Values                |\n|:-------------------------|:--------|:------------------------------|\n| isInfinite               | false   | true / false                  |\n| autoScroll               | false   | true / false                  |\n| scrollInterval           | 5000    | any integer (represents ms)   | \n\nPlease note that the height of `LoopingViewPager` should be decided by its parent, like all other Views.  \nIf you want it to have a specific aspect ratio, you can place it inside a `ConstraintLayout` and give it the attribute `layout_constraintDimensionRatio`.\n\n(The old versions of this library uses an internal attribute to determine its height, which is completely wrong and can lead to bugs!)\n\nNote: 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)\n\n### Step 2: Create your PagerAdapter that extends LoopingPagerAdapter\n\nYou should\n1. Specify the data type in the generic (`\u003cDataType\u003e`)\n2. Create your own constructor according to this `DataType`\n3. override `inflateView()` and `bindView()`\n4. DO NOT override getCount(). Look at `LoopingPagerAdapter`. getCount() has special implementation.\n\n```kotlin\nclass DemoInfiniteAdapter(\n    itemList: ArrayList\u003cYourObject\u003e,\n    isInfinite: Boolean\n) : LoopingPagerAdapter\u003cYourObject\u003e(itemList, isInfinite) {\n\n    //This method will be triggered if the item View has not been inflated before.\n    override fun inflateView(\n        viewType: Int,\n        container: ViewGroup,\n        listPosition: Int\n    ): View {\n        return LayoutInflater.from(container.context).inflate(R.layout.item_pager, container, false)\n    }\n\n    //Bind your data with your item View here.\n    //Below is just an example in the demo app.\n    //You can assume convertView will not be null here.\n    //You may also consider using a ViewHolder pattern.\n    override fun bindView(\n        convertView: View,\n        listPosition: Int,\n        viewType: Int\n    ) {\n        convertView.findViewById\u003cView\u003e(R.id.image).setBackgroundColor(convertView.context.resources.getColor(getBackgroundColor(listPosition)))\n        val description = convertView.findViewById\u003cTextView\u003e(R.id.description)\n        description.text = itemList?.get(listPosition).toString()\n    }\n}\n```\n\n### Step 3: Bind LoopingViewPager with your Adapter\n\n```kotlin\n        adapter = DemoInfiniteAdapter(dataItems, true)\n        loopingViewPager.setAdapter(adapter)\n```\n\n### Step 4: Resume and Pause autoScroll in your Activity (If you need autoScroll)\n\n```kotlin\n    override fun onResume() {\n        super.onResume()\n        loopingViewPager.resumeAutoScroll()\n    }\n\n    override fun onPause() {\n        loopingViewPager.pauseAutoScroll()\n        super.onPause()\n    }\n```\n\n### Handling dataSet change\n\nIf you have new data to update to your adapter, simply call:\n\n```kotlin\nadapter.setItemList(newItemList)\nviewPager.reset() //In order to reset the current page position\n```\n\n## How do I implement different View types?\n\nSimple! Override one more method in your Adapter:\n\n```kotlin\n    override fun getItemViewType(listPosition: Int): Int {\n        return if (itemList?.get(listPosition) == 0) VIEW_TYPE_SPECIAL else VIEW_TYPE_NORMAL\n    }\n```\n\nAnd then, of course, according to the `viewtype` parameter passed to you in `inflateView()` and `bindView()`, differentiate what you need to inflate or bind.\n\nYou may also refer to the demo app for a complete example.\n\n## How do I integrate a Page Indicator?\n\nI don't officially provide a built-in page indicator because:\n1. ViewPager and Indicator are logically separated\n2. I want to make this library adaptable to all page indicators\n\nWith that said, I have created a simple `CustomShapePagerIndicator` included in this library.  \nIt is simple but very flexible, because you need to / you can provide your own implementation of how to inflate the unselected and selected indicators.\n\nI assume for any indicator libraries you use, they should provide a method for you to call so that you can simply redirect `onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int)` of `ViewPager.OnPageChangeListener` to the indicator library,  \nAnd then the indicator library will then be able to handle the transitions for you, which is also the case in `CustomShapePagerIndicator`.\n\nSo, the job of `LoopingViewPager` is simply to mask the infinite behavior into a `onPageScrolled` behavior which looks like it is not infinite.  \nIn other words, when you scroll from last page to first page, it will be converted to directing jumping from last page back to first page;  \nWhen you scroll from first page backward to last page, it will be converted to directing jumping from first page to last page.  \nIf you do not accept this assumption, I am sorry but you probably need to find something else.\n\nSo, instead of adding another `onPageChangeListener`, you simply do this:  \n(Below example is using built in `CustomShapePagerIndicator`)\n\n```kotlin\nloopingViewPager.onIndicatorProgress = { selectingPosition, progress -\u003e \n    indicatorView.onPageScrolled(selectingPosition, progress)\n}\n```\n\nNote that this is a brand new implementation of how `LoopingViewPager` in v1.3.0, after I realized how wrong I was 2 years ago.  \nIf you need to stick with the old implementation, please use v1.2.0 and checkout the README.md at the commit before this version.\n\n### If you want to use CustomShapePagerIndicator, here is how\n\n(You can always refer to the demo app.)\n\nFirst, add `CustomShapePagerIndicator` to your XML, use wrap_content for width and height,  \nAnd specify the spacing between unselected indicators (`app:indicator_spacing=\"?dp\"`):\n\n```xml\n    \u003ccom.asksira.android.customshapepagerindicator.CustomShapePagerIndicator\n        android:id=\"@+id/indicator\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        app:layout_constraintBottom_toBottomOf=\"@id/viewpager\"\n        app:layout_constraintLeft_toLeftOf=\"parent\"\n        app:layout_constraintRight_toRightOf=\"parent\"\n        android:layout_marginBottom=\"8dp\"\n        app:indicator_spacing=\"4dp\"/\u003e\n```\n\nThen, tell the indicator how to inflate your unselected of highlighter indicators:\n```kotlin\n        customShapePagerIndicator.highlighterViewDelegate = {\n            val highlighter = View(this)\n            highlighter.layoutParams = FrameLayout.LayoutParams(16.dp(), 2.dp())\n            highlighter.setBackgroundColor(getColorCompat(R.color.white))\n            highlighter\n        }\n        customShapePagerIndicator.unselectedViewDelegate = {\n            val unselected = View(this)\n            unselected.layoutParams = LinearLayout.LayoutParams(16.dp(), 2.dp())\n            unselected.setBackgroundColor(getColorCompat(R.color.white))\n            unselected.alpha = 0.4f\n            unselected\n        }\n```\n\nNote that you must provide a fixed width and height for your indicators.  \nBecause `CustomShapePagerIndicator` use margins internally to handle indicator spacing, please do not specify your own margin when providing your own views.\n\nFinally, for the first time and whenever you need to update your indicator counts:\n\n```kotlin\ncustomShapePagerIndicator.updateIndicatorCounts(loopingViewPager.indicatorCount)\n```\n\n## Release notes\n\nv1.4.1\n- Removed setting aspect ratio inside LoopingViewPager. Let its parent to decide how to layout it (i.e. its height).\n- Same as above, removed itemAspectRatio as well. You can actually simply set it through padding and `clipToPadding=false`.\n- Removed unnecessary context as a param in LoopingPagerAdapter's constructor.  \n- Migrated from JCenter() to MavenCentral().\n\nv1.3.2\n- Fixed crash due to getChildAt() returns null\n\nv1.3.1\n- Converted everything to Kotlin\n- Revamp the whole logic of pager indicator handling\n- Added built-in `CustomShapePagerIndicator`\n\nv.1.2.0\n- Added requirement mentioned in #17.\n\nv1.1.4\n- Merged #11.\n\nv1.1.3\n- Merged #15 which includes AndroidX support and `resetAutoScroll()` which is equivalent to `pauseAutoScroll()` and then `resumeAutoScroll()`.\n\nv1.1.2\n- Added `ViewGroup container` as an argument to `inflateView()`. You should now use it as the parent of when you inflate your view.  \n- Updated gradle version and support library version.\n\nv1.1.0\n- Added support for view type. But therefore changed parameters needed in `inflateView()` and `bindView()`.\n\nv1.0.5\n- Added asepct ratio attribute for `LoopingViewPager`  \n- Rewrote the way of caching Views in `LoopingPagerAdapter`, and therefore separated inflation and data binding  \n- Rewrote the way of implementing ViewPager wrap_content\n\nv1.0.4\n- Indicator now works with page skipping as well (By calling `selectCurrentItem()`)\n- Leviated indicator fluctuating phenomenon when using `onIndicatorProgress()` callback\n- Added option for smart or non-smart indicators\n\n\nv1.0.1  \n- Fixed a bug where getSelectingIndicatorPosition() is returning incorrect value.\n- Updated README.md according to PageIndicatorView v1.0.0 update.\n\n## License\n\n```\nCopyright 2017 Sira Lam\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and \nassociated documentation files (the LoopingViewPager), to deal in the Software without restriction,\nincluding without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,\nand/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or \nsubstantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\nINCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE\nAND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\nDAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsiralam%2FLoopingViewPager","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsiralam%2FLoopingViewPager","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsiralam%2FLoopingViewPager/lists"}