Full Code of youth5201314/banner for AI

master 777c7dbfaa0a cached
118 files
219.4 KB
57.3k tokens
385 symbols
1 requests
Download .txt
Showing preview only (250K chars total). Download the full file or copy to clipboard to get everything.
Repository: youth5201314/banner
Branch: master
Commit: 777c7dbfaa0a
Files: 118
Total size: 219.4 KB

Directory structure:
gitextract_a7zjbpp5/

├── .gitignore
├── BannerExample.iml
├── LICENSE
├── README.md
├── app/
│   ├── .gitignore
│   ├── build.gradle
│   ├── proguard-rules.pro
│   └── src/
│       └── main/
│           ├── AndroidManifest.xml
│           ├── java/
│           │   └── com/
│           │       └── test/
│           │           └── banner/
│           │               ├── MainActivity.java
│           │               ├── adapter/
│           │               │   ├── ImageAdapter.java
│           │               │   ├── ImageNetAdapter.java
│           │               │   ├── ImageTitleAdapter.java
│           │               │   ├── ImageTitleNumAdapter.java
│           │               │   ├── MultipleTypesAdapter.java
│           │               │   ├── MyRecyclerViewAdapter.java
│           │               │   └── TopLineAdapter.java
│           │               ├── bean/
│           │               │   └── DataBean.java
│           │               ├── indicator/
│           │               │   └── NumIndicator.java
│           │               ├── ui/
│           │               │   ├── BannerFragment.java
│           │               │   ├── BannerListFragment.java
│           │               │   ├── BlankFragment.java
│           │               │   ├── ConstraintLayoutBannerActivity.java
│           │               │   ├── GalleryActivity.java
│           │               │   ├── RecyclerViewBannerActivity.java
│           │               │   ├── TVActivity.java
│           │               │   ├── TouTiaoActivity.java
│           │               │   ├── VideoActivity.java
│           │               │   └── Vp2FragmentRecyclerviewActivity.java
│           │               ├── util/
│           │               │   ├── ParentRecyclerView.java
│           │               │   └── TabLayoutMediator.java
│           │               └── viewholder/
│           │                   ├── ImageHolder.java
│           │                   ├── ImageTitleHolder.java
│           │                   ├── TitleHolder.java
│           │                   └── VideoHolder.java
│           └── res/
│               ├── drawable/
│               │   ├── background.xml
│               │   ├── default_selecter.xml
│               │   ├── green.xml
│               │   ├── selected_radius.xml
│               │   ├── unselected_radius.xml
│               │   └── white.xml
│               ├── layout/
│               │   ├── activity_constraint_layout_banner.xml
│               │   ├── activity_gallery.xml
│               │   ├── activity_main.xml
│               │   ├── activity_recyclerview_banner.xml
│               │   ├── activity_t_v.xml
│               │   ├── activity_tou_tiao.xml
│               │   ├── activity_video.xml
│               │   ├── activity_vp2_fragment_recyclerview.xml
│               │   ├── banner.xml
│               │   ├── banner_image.xml
│               │   ├── banner_image_title.xml
│               │   ├── banner_image_title_num.xml
│               │   ├── banner_title.xml
│               │   ├── banner_video.xml
│               │   ├── item.xml
│               │   ├── test.xml
│               │   └── top_line_item2.xml
│               ├── values/
│               │   ├── arrays.xml
│               │   ├── colors.xml
│               │   ├── dimens.xml
│               │   ├── strings.xml
│               │   └── styles.xml
│               └── values-w820dp/
│                   └── dimens.xml
├── banner/
│   ├── .gitignore
│   ├── build.gradle
│   ├── proguard-rules.pro
│   └── src/
│       └── main/
│           ├── AndroidManifest.xml
│           ├── java/
│           │   └── com/
│           │       └── youth/
│           │           └── banner/
│           │               ├── Banner.java
│           │               ├── adapter/
│           │               │   ├── BannerAdapter.java
│           │               │   └── BannerImageAdapter.java
│           │               ├── config/
│           │               │   ├── BannerConfig.java
│           │               │   └── IndicatorConfig.java
│           │               ├── holder/
│           │               │   ├── BannerImageHolder.java
│           │               │   └── IViewHolder.java
│           │               ├── indicator/
│           │               │   ├── BaseIndicator.java
│           │               │   ├── CircleIndicator.java
│           │               │   ├── DrawableIndicator.java
│           │               │   ├── Indicator.java
│           │               │   ├── RectangleIndicator.java
│           │               │   └── RoundLinesIndicator.java
│           │               ├── itemdecoration/
│           │               │   └── MarginDecoration.java
│           │               ├── listener/
│           │               │   ├── OnBannerListener.java
│           │               │   └── OnPageChangeListener.java
│           │               ├── transformer/
│           │               │   ├── AlphaPageTransformer.java
│           │               │   ├── BasePageTransformer.java
│           │               │   ├── DepthPageTransformer.java
│           │               │   ├── MZScaleInTransformer.java
│           │               │   ├── RotateDownPageTransformer.java
│           │               │   ├── RotateUpPageTransformer.java
│           │               │   ├── RotateYTransformer.java
│           │               │   ├── ScaleInTransformer.java
│           │               │   └── ZoomOutPageTransformer.java
│           │               └── util/
│           │                   ├── BannerLifecycleObserver.java
│           │                   ├── BannerLifecycleObserverAdapter.java
│           │                   ├── BannerUtils.java
│           │                   ├── LogUtils.java
│           │                   └── ScrollSpeedManger.java
│           └── res/
│               └── values/
│                   ├── attr.xml
│                   ├── ids.xml
│                   └── strings.xml
├── build.gradle
├── gradle/
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── settings.gradle
├── update_message.md
└── usekotlin/
    ├── .gitignore
    ├── build.gradle
    ├── consumer-rules.pro
    ├── proguard-rules.pro
    └── src/
        ├── androidTest/
        │   └── java/
        │       └── com/
        │           └── spring/
        │               └── usekotlin/
        │                   └── ExampleInstrumentedTest.kt
        ├── main/
        │   ├── AndroidManifest.xml
        │   ├── java/
        │   │   └── com/
        │   │       └── spring/
        │   │           └── usekotlin/
        │   │               ├── ImageAdapter.kt
        │   │               └── MainActivity.kt
        │   └── res/
        │       ├── layout/
        │       │   └── activity_main.xml
        │       └── values/
        │           ├── colors.xml
        │           ├── strings.xml
        │           └── styles.xml
        └── test/
            └── java/
                └── com/
                    └── spring/
                        └── usekotlin/
                            └── ExampleUnitTest.kt

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
# Built application files
*.apk
*.ap_

# Files for the Dalvik VM
*.dex

# Java class files
*.class

# Generated files
bin/
gen/

# Gradle files
.gradle/
build/

# Local configuration file (sdk path, etc)
local.properties

# Proguard folder generated by Eclipse
proguard/

# Log Files
*.log

# Android Studio Navigation editor temp files
.navigation/

# Android Studio captures folder
captures/
.idea
/banner.iml
/gradlew
/gradlew.bat
/gradle.properties


================================================
FILE: BannerExample.iml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id="BannerExample" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" external.system.module.group="" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
  <component name="FacetManager">
    <facet type="java-gradle" name="Java-Gradle">
      <configuration>
        <option name="BUILD_FOLDER_PATH" value="$MODULE_DIR$/build" />
        <option name="BUILDABLE" value="false" />
      </configuration>
    </facet>
  </component>
  <component name="NewModuleRootManager" inherit-compiler-output="true">
    <exclude-output />
    <content url="file://$MODULE_DIR$">
      <excludeFolder url="file://$MODULE_DIR$/.gradle" />
      <excludeFolder url="file://$MODULE_DIR$/build" />
    </content>
    <orderEntry type="inheritedJdk" />
    <orderEntry type="sourceFolder" forTests="false" />
  </component>
</module>

================================================
FILE: LICENSE
================================================
                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "{}"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright {yyyy} {name of copyright owner}

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.


================================================
FILE: README.md
================================================

## Banner 2.0 全新升级
> 只做一个可以自定义的轮播容器,不侵入UI ———— Banner 2.0

```
> 各位老铁反馈的问题我都有看,不是不解决,有时真的很难复现,
> 如果能在提交问题时,有条件提供个demo发到我邮箱,方便定位问题,毕竟大家的场景和使用方式都有差异,
> 我自己也在使用,在多个千万级APP上一直稳定运行,如果真有严重问题肯定第一时间就修复了
```

<a href="https://github.com/youth5201314/banner/tree/release-1.4.10" target="_blank">Banner 1.4.10(还想看老版本的可以点击这里)</a>

### 阔别已久,从新回归

* 首先我声明几点:
    * 这只是一个开源库,如果满意你可以使用、可以借鉴修改,希望对你们有所帮助。
    * 如果不满意请友好的提出,注明错误的详细信息或者修改建议,好的想法和自定义的东西亦可以直接提交,大家都能来一起完善。
    * 如果你觉得实在是没用,也请你做一个有自我修养的人。
   
### 主要改进功能介绍
最开始是想上传以前基于viewpager更新好的版本,但是看着viewpager2正式版已经出来了,就上新的吧,viewpager2确实比viewpager性能好很多。

- [x] 使用了ViewPager2为基础控件  <a href="https://developer.android.google.cn/jetpack/androidx/releases/viewpager2" target="_blank">ViewPager2介绍</a>
- [x] 支持了androidx兼容包
- [x] 方便了UI、Indicator自定义
- [x] 支持画廊效果、魅族效果
- [x] 兼容了水平和垂直轮播,也可以实现类似淘宝头条的效果
- [x] 依赖包目前只需要导入了ViewPager2



### 效果图
更多效果运行demo查看

![默认](images/banner_example.gif)

![画廊](images/banner_example2.gif)

![魅族](images/banner_example1.gif)

![头条](images/banner_example3.gif)

##### 内置了多种PageTransformer效果

![DepthPageTransformer](images/DepthPageTransformer.gif)
![ZoomOutPageTransformer](images/ZoomOutPageTransformer.gif)

|内置的PageTransformer|
|---|
|AlphaPageTransformer|
|DepthPageTransformer|
|RotateDownPageTransformer|
|RotateUpPageTransformer|
|RotateYTransformer|
|ScaleInTransformer|
|ZoomOutPageTransformer|
 也可以组合使用效果更佳

## 方法
更多方法以实际使用为准,下面不一定全部列出了

|方法名|返回类型|描述|
|---|---|---|
|getAdapter()|extends BannerAdapter|获取你设置的BannerAdapter
|getViewPager2()|ViewPager2|获取ViewPager2
|getIndicator()|Indicator|获取你设置的指示器(没有设置直接获取会抛异常哦)
|getIndicatorConfig()|IndicatorConfig|获取你设置的指示器配置信息(没有设置直接获取会抛异常哦)
|getRealCount()|int|返回banner真实总数
|setUserInputEnabled(boolean)|this|禁止手动滑动Banner;true 允许,false 禁止
|setDatas(List<T>)|this|重新设置banner数据
|isAutoLoop(boolean)|this|是否允许自动轮播
|setLoopTime(long)|this|设置轮播间隔时间(默认3000毫秒)
|setScrollTime(long)|this|设置轮播滑动的时间(默认800毫秒)
|start()|this|开始轮播(主要配合生命周期使用),或者你手动暂停再次启动
|stop()|this|停止轮播(主要配合生命周期使用),或者你需要手动暂停
|setAdapter(T extends BannerAdapter)|this|设置banner的适配器
|setAdapter(T extends BannerAdapter,boolean)|this|设置banner的适配器,是否支持无限循环
|setOrientation(@Orientation)|this|设置banner轮播方向(垂直or水平)
|setOnBannerListener(this)|this|设置点击事件,下标是从0开始
|addOnPageChangeListener(this)|this|添加viewpager2的滑动监听
|setPageTransformer(PageTransformer)|this|设置viewpager的切换效果
|addPageTransformer(PageTransformer)|this|添加viewpager的切换效果(可以设置多个)
|setIndicator(Indicator)|this|设置banner轮播指示器(提供有base和接口,可以自定义)
|setIndicator(Indicator,boolean)|this|设置指示器(传false代表不将指示器添加到banner上,配合布局文件,可以自我发挥)
|setIndicatorSelectedColor(@ColorInt)|this|设置指示器选中颜色
|setIndicatorSelectedColorRes(@ColorRes)|this|设置指示器选中颜色
|setIndicatorNormalColor(@ColorInt)|this|设置指示器默认颜色
|setIndicatorNormalColorRes(@ColorRes)|this|设置指示器默认颜色
|setIndicatorGravity(@IndicatorConfig.Direction)|this|设置指示器位置(左,中,右)
|setIndicatorSpace(int)|this|设置指示器之间的间距
|setIndicatorMargins(IndicatorConfig.Margins)|this|设置指示器的Margins
|setIndicatorWidth(int,int)|this|设置指示器选中和未选中的宽度,直接影响绘制指示器的大小
|setIndicatorNormalWidth(int)|this|设置指示器未选中的宽度
|setIndicatorSelectedWidth(int)|this|设置指示器选中的宽度
|setIndicatorRadius(int)|this|设置指示器圆角,不要圆角可以设置为0
|setIndicatorHeight(int)|this|设置指示器高度
|setBannerRound(float)|this|设置banner圆角(还有一种setBannerRound2方法,需要5.0以上)
|setBannerGalleryEffect(int,int,float)|this|画廊效果
|setBannerGalleryMZ(int,float)|this|魅族效果
|setStartPosition(int)|this|设置开始的位置 (需要在setAdapter或者setDatas之前调用才有效哦)
|setIndicatorPageChange()|this|设置指示器改变监听 (一般是为了配合数据操作使用,看情况自己发挥)
|setCurrentItem()|this|设置当前位置,和原生使用效果一样
|addBannerLifecycleObserver()|this|给banner添加生命周期观察者,内部自动管理banner的生命周期


## Attributes属性
>在banner布局文件中调用,如果你自定义了indicator请做好兼容处理。
下面的属性并不是每个指示器都用得到,所以使用时要注意!

|Attributes|format|describe
|---|---|---|
|banner_loop_time|integer|轮播间隔时间,默认3000
|banner_auto_loop|boolean|是否自动轮播,默认true
|banner_infinite_loop|boolean|是否支持无限循环(即首尾直接过渡),默认true
|banner_orientation|enum|轮播方向:horizontal(默认) or vertical
|banner_radius|dimension|banner圆角半径,默认0(不绘制圆角)
|banner_indicator_normal_width|dimension|指示器默认的宽度,默认5dp (对RoundLinesIndicator无效)
|banner_indicator_selected_width|dimension|指示器选中的宽度,默认7dp 
|banner_indicator_normal_color|color|指示器默认颜色,默认0x88ffffff
|banner_indicator_selected_color|color|指示器选中颜色,默认0x88000000
|banner_indicator_space|dimension|指示器之间的间距,默认5dp (对RoundLinesIndicator无效)
|banner_indicator_gravity|dimension|指示器位置,默认center
|banner_indicator_margin|dimension|指示器的margin,默认5dp,不能和下面的同时使用
|banner_indicator_marginLeft|dimension|指示器左边的margin
|banner_indicator_marginTop|dimension|指示器上边的margin
|banner_indicator_marginRight|dimension|指示器右边的margin
|banner_indicator_marginBottom|dimension|指示器下边的margin
|banner_indicator_height|dimension|指示器高度(对CircleIndicator无效)
|banner_indicator_radius|dimension|指示器圆角(对CircleIndicator无效)
|banner_round_top_left|boolean|设置要绘制的banner圆角方向(如果都不设置默认全部)
|banner_round_top_right|boolean|设置要绘制的banner圆角方向(如果都不设置默认全部)
|banner_round_bottom_left|boolean|设置要绘制的banner圆角方向(如果都不设置默认全部)
|banner_round_bottom_right|boolean|设置要绘制的banner圆角方向(如果都不设置默认全部)



## 使用步骤
>以下提供的是最简单的步骤,需要复杂的样式自己可以自定义

#### Step 1.依赖banner
Gradle 
```groovy

repositories {
    maven { url "https://s01.oss.sonatype.org/content/groups/public" }
}

dependencies{
    //2.1.0以前jcenter的依赖
    //implementation 'com.youth.banner:banner:2.1.0'
    //现在Maven Central
    implementation 'io.github.youth5201314:banner:2.2.3'

}
```

#### Step 2.添加权限到你的 AndroidManifest.xml
```xml
<!-- if you want to load images from the internet -->
<uses-permission android:name="android.permission.INTERNET" /> 

```

#### Step 3.在布局文件中添加Banner,可以设置自定义属性
!!!此步骤可以省略,可以直接在Activity或者Fragment中new Banner();
```xml
<com.youth.banner.Banner
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/banner"
    android:layout_width="match_parent"
    android:layout_height="高度自己设置" />
```

#### Step 4.继承BannerAdapter,和RecyclerView的Adapter一样(如果你只是图片轮播也可以使用默认的)
!!!此步骤可以省略,图片轮播提供有默认适配器,其他的没有提供是因为大家的可变性要求不确定,所以直接自定义的比较好。
```java

/**
 * 自定义布局,下面是常见的图片样式,更多实现可以看demo,可以自己随意发挥
 */
public class ImageAdapter extends BannerAdapter<DataBean, ImageAdapter.BannerViewHolder> {

    public ImageAdapter(List<DataBean> mDatas) {
        //设置数据,也可以调用banner提供的方法,或者自己在adapter中实现
        super(mDatas);
    }

    //创建ViewHolder,可以用viewType这个字段来区分不同的ViewHolder
    @Override
    public BannerViewHolder onCreateHolder(ViewGroup parent, int viewType) {
        ImageView imageView = new ImageView(parent.getContext());
        //注意,必须设置为match_parent,这个是viewpager2强制要求的
        imageView.setLayoutParams(new ViewGroup.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT));
        imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
        return new BannerViewHolder(imageView);
    }

    @Override
    public void onBindView(BannerViewHolder holder, DataBean data, int position, int size) {
        holder.imageView.setImageResource(data.imageRes);
    }

    class BannerViewHolder extends RecyclerView.ViewHolder {
        ImageView imageView;

        public BannerViewHolder(@NonNull ImageView view) {
            super(view);
            this.imageView = view;
        }
    }
}

```

#### Step 5.Banner具体方法调用 

```java
public class BannerActivity extends AppCompatActivity {
    public void useBanner() {
        //--------------------------简单使用-------------------------------
        banner.addBannerLifecycleObserver(this)//添加生命周期观察者
                .setAdapter(new BannerExampleAdapter(DataBean.getTestData()))
                .setIndicator(new CircleIndicator(this));
        
        //—————————————————————————如果你想偷懒,而又只是图片轮播————————————————————————
         banner.setAdapter(new BannerImageAdapter<DataBean>(DataBean.getTestData3()) {
                    @Override
                    public void onBindView(BannerImageHolder holder, DataBean data, int position, int size) {
                        //图片加载自己实现
                        Glide.with(holder.itemView)
                             .load(data.imageUrl)
                             .apply(RequestOptions.bitmapTransform(new RoundedCorners(30)))
                             .into(holder.imageView);
                    }
                })
                .addBannerLifecycleObserver(this)//添加生命周期观察者
                .setIndicator(new CircleIndicator(this));
        //更多使用方法仔细阅读文档,或者查看demo
    }
}
```

## Banner使用中优化体验
**如果你需要考虑更好的体验,可以看看下面的代码**
#### Step 1.(可选)生命周期改变时
```java
public class BannerActivity {
  
    //方法一:自己控制banner的生命周期
    
    @Override
    protected void onStart() {
        super.onStart();
        //开始轮播
        banner.start();
    }
    
    @Override
    protected void onStop() {
        super.onStop();
        //停止轮播
        banner.stop();
    }
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        //销毁
        banner.destroy();
    }
    
    //方法二:调用banner的addBannerLifecycleObserver()方法,让banner自己控制
   
    protected void onCreate(Bundle savedInstanceState) {
         //添加生命周期观察者
        banner.addBannerLifecycleObserver(this);
    }
}
```


## 常见问题(收录被反复询问的问题)

* 网络图片加载不出来?

  `banner本身不提供图片加载功能,首先确认banner本身使用是否正确,具体参考demo,
  然后请检查你的图片加载框架或者网络请求框架,服务端也可能加了https安全认证,是看下是否报有证书相关错误`
  
* 怎么实现视频轮播?

  `demo中有实现类似淘宝商品详情的效果,第一个放视频,后面的放的是图片,并且可以设置首尾不能滑动。
  因为大家使用的播放器不一样业务环境也不同,具体情况自己把握,demo就是给一个思路哈!可以参考和修改`

* 我想指定轮播开始的位置?

  `现在提供了setStartPosition()方法,在sheAdapter和setDatas直接调用一次就行了,当然setAdapter后通过setCurrentItem设置也行`

* 父控件滑动时,banner切换会获取焦点,然后自动全部显示。不想让banner获取焦点可以给父控件加上:

    ```
        //banner也一定要用最新版哦!
        android:focusable="true"
        android:focusableInTouchMode="true"
    ```
* 怎么设置圆角?
  1、调用提供的方法或者自定义属性进行设置,这里设置的是banner本身的圆角,不是轮播内view的圆角
  2、在adapter中对自定义的view进行自己实现,就拿图片举例:可以自己定义一个圆角的ImageView控件,或者使用glide渲染都行。请举一反三,view都自定义了还有什么不能改的?
  
    
## Thanks

- [MZBannerView](https://github.com/pinguo-zhouwei/MZBannerView)
- [MagicViewPager](https://github.com/hongyangAndroid/MagicViewPager)
- [zguop的viewpager2的滑动时间解决方案](https://github.com/zguop/banner/blob/master/pager2banner/src/main/java/com/to/aboomy/pager2banner/Banner.java)


### 联系方式  <a target="_blank" href="http://mail.qq.com/cgi-bin/qm_share?t=qm_mailme&email=KBkYGhAfGhEYEB5oWVkGS0dF" style="text-decoration:none;"><img src="images/mailme.png"/></a>
* 我的个人微博:https://weibo.com/u/3013494003 有兴趣的也可以关注,大家一起交流
* 有问题可以加群大家一起交流,如果你觉得对你有帮助可以扫描下面支付宝二维码随意打赏下哦!

<img src="images/qq.png" width="220"/> <img src="images/pay.jpg" width="220"/>


## 更新说明
[更新说明](update_message.md)



================================================
FILE: app/.gitignore
================================================
/build


================================================
FILE: app/build.gradle
================================================
apply plugin: 'com.android.application'

android {
    compileSdk 33

    defaultConfig {
        applicationId "com.test.banner"
        minSdk 21
        targetSdk 33
        versionCode 1
        versionName "1.0"
        consumerProguardFiles 'proguard-rules.pro'
    }
    buildTypes {
        debug {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
        release {
            minifyEnabled true
            shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.recyclerview:recyclerview:1.2.0'
    implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    implementation 'androidx.viewpager2:viewpager2:1.1.0-alpha01'
    implementation 'androidx.viewpager:viewpager:1.0.0'
    implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:3.0.2'
    implementation 'androidx.cardview:cardview:1.0.0'
    implementation 'com.github.bumptech.glide:glide:4.12.0'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
    implementation 'com.google.android.material:material:1.2.0-alpha06'
    implementation 'com.jakewharton:butterknife:10.2.3'
    annotationProcessor 'com.jakewharton:butterknife-compiler:10.2.3'

    implementation 'com.shuyu:GSYVideoPlayer:7.1.3'


    implementation project(':banner')
//    implementation 'io.github.youth5201314:banner:2.2.1'
}


================================================
FILE: app/proguard-rules.pro
================================================
#指定代码的压缩级别
-optimizationpasses 5
#包明不混合大小写
-dontusemixedcaseclassnames
#不去忽略非公共的库类
-dontskipnonpubliclibraryclasses
#优化  不优化输入的类文件
-dontoptimize
#预校验
-dontpreverify
#混淆时是否记录日志
-verbose
# 混淆时所采用的算法
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
#保护注解
-keepattributes *Annotation*
# 保持哪些类不被混淆
-keep public class * extends android.app.Fragment
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class com.android.vending.licensing.ILicensingService

#glide
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public class * extends com.bumptech.glide.module.AppGlideModule
-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
  **[] $VALUES;
  public *;
}

#butterknife
-keep public class * implements butterknife.Unbinder { public <init>(**, android.view.View); }
-keep class butterknife.*
-keepclasseswithmembernames class * { @butterknife.* <methods>; }
-keepclasseswithmembernames class * { @butterknife.* <fields>; }
-keepclassmembers class * { @butterknife.* <methods>; }
-keepclassmembers class * { @butterknife.* <fields>; }

#gsyvideoplayer
-keep class com.shuyu.gsyvideoplayer.video.** { *; }
-dontwarn com.shuyu.gsyvideoplayer.video.**
-keep class com.shuyu.gsyvideoplayer.video.base.** { *; }
-dontwarn com.shuyu.gsyvideoplayer.video.base.**
-keep class com.shuyu.gsyvideoplayer.utils.** { *; }
-dontwarn com.shuyu.gsyvideoplayer.utils.**
-keep class tv.danmaku.ijk.** { *; }
-dontwarn tv.danmaku.ijk.**
-keep public class * extends android.view.View{
    *** get*();
    void set*(***);
    public <init>(android.content.Context);
    public <init>(android.content.Context, android.util.AttributeSet);
    public <init>(android.content.Context, android.util.AttributeSet, int);
}

-dontwarn com.google.android.exoplayer.**
-keep class com.google.android.exoplayer.**{*;}






================================================
FILE: app/src/main/AndroidManifest.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.test.banner">

    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme">
        <activity android:name=".ui.GalleryActivity" />
        <activity android:name=".ui.TouTiaoActivity" />
        <activity android:name=".ui.TVActivity" />
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".ui.RecyclerViewBannerActivity" />
        <activity android:name=".ui.ConstraintLayoutBannerActivity" />
        <activity android:name=".ui.VideoActivity" />
        <activity
            android:name=".ui.Vp2FragmentRecyclerviewActivity"
            android:theme="@style/Theme.AppCompat.Light.NoActionBar" />
    </application>

</manifest>

================================================
FILE: app/src/main/java/com/test/banner/MainActivity.java
================================================
package com.test.banner;

import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;

import com.bumptech.glide.Glide;
import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
import com.bumptech.glide.request.RequestOptions;
import com.google.android.material.snackbar.Snackbar;
import com.test.banner.adapter.ImageAdapter;
import com.test.banner.adapter.ImageTitleAdapter;
import com.test.banner.adapter.ImageTitleNumAdapter;
import com.test.banner.adapter.MultipleTypesAdapter;
import com.test.banner.bean.DataBean;
import com.youth.banner.indicator.DrawableIndicator;
import com.test.banner.ui.ConstraintLayoutBannerActivity;
import com.test.banner.ui.GalleryActivity;
import com.test.banner.ui.RecyclerViewBannerActivity;
import com.test.banner.ui.TVActivity;
import com.test.banner.ui.TouTiaoActivity;
import com.test.banner.ui.VideoActivity;
import com.test.banner.ui.Vp2FragmentRecyclerviewActivity;
import com.youth.banner.Banner;
import com.youth.banner.adapter.BannerImageAdapter;
import com.youth.banner.holder.BannerImageHolder;
import com.youth.banner.config.BannerConfig;
import com.youth.banner.config.IndicatorConfig;
import com.youth.banner.indicator.CircleIndicator;
import com.youth.banner.indicator.RoundLinesIndicator;
import com.youth.banner.listener.OnPageChangeListener;
import com.youth.banner.util.BannerUtils;
import com.youth.banner.util.LogUtils;

import androidx.appcompat.app.AppCompatActivity;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;

import java.util.List;

import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;

public class MainActivity extends AppCompatActivity {
    @BindView(R.id.banner)
    Banner banner;
    @BindView(R.id.indicator)
    RoundLinesIndicator indicator;
    @BindView(R.id.swipeRefresh)
    SwipeRefreshLayout refresh;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);

        List<DataBean> datas =  DataBean.getTestData2();

        //自定义的图片适配器,也可以使用默认的BannerImageAdapter
        ImageAdapter adapter = new ImageAdapter(datas);

        banner.setAdapter(adapter)
//              .setCurrentItem(0,false)
                //添加生命周期观察者
                .addBannerLifecycleObserver(this)
                //设置指示器
                .setIndicator(new CircleIndicator(this))
                .setOnBannerListener((data, position) -> {
                    Snackbar.make(banner, ((DataBean) data).title, Snackbar.LENGTH_SHORT).show();
                    LogUtils.d("position:" + position);
                });

        //添加item之间切换时的间距(如果使用了画廊效果就不要添加间距了,因为内部已经添加过了)
//        banner.addPageTransformer(new MarginPageTransformer( BannerUtils.dp2px(10)));

        //和下拉刷新配套使用
        refresh.setOnRefreshListener(() -> {
            //模拟网络请求需要3秒,请求完成,设置setRefreshing 为false
            new Handler().postDelayed(() -> {
                refresh.setRefreshing(false);

                //给banner重新设置数据(完全覆盖)
                banner.setDatas(DataBean.getTestData());

                //模拟请求成功(原数据减少) 刷新banner
//                datas.remove(0);
//                adapter.notifyDataSetChanged();

                //对setDatas()方法不满意?你可以自己在adapter控制数据,参考setDatas()的实现修改
//                adapter.updateData(DataBean.getTestData());
//                banner.setCurrentItem(banner.getStartPosition(), false);
//                banner.setIndicatorPageChange();

            }, 2000);
        });

    }


    @OnClick({R.id.style_image, R.id.style_image_title, R.id.style_image_title_num, R.id.style_multiple,
            R.id.style_net_image, R.id.change_indicator, R.id.rv_banner, R.id.cl_banner, R.id.vp_banner,
            R.id.banner_video, R.id.banner_tv, R.id.gallery, R.id.topLine})
    public void click(View view) {
        indicator.setVisibility(View.GONE);
        switch (view.getId()) {
            case R.id.style_image:
                refresh.setEnabled(true);
                banner.setAdapter(new ImageAdapter(DataBean.getTestData()));
                banner.setIndicator(new CircleIndicator(this));
                banner.setIndicatorGravity(IndicatorConfig.Direction.CENTER);
                break;
            case R.id.style_image_title:
                refresh.setEnabled(true);
                banner.setAdapter(new ImageTitleAdapter(DataBean.getTestData()));
                banner.setIndicator(new CircleIndicator(this));
                banner.setIndicatorGravity(IndicatorConfig.Direction.RIGHT);
                banner.setIndicatorMargins(new IndicatorConfig.Margins(0, 0,
                        BannerConfig.INDICATOR_MARGIN, BannerUtils.dp2px(12)));
                break;
            case R.id.style_image_title_num:
                refresh.setEnabled(true);
                //这里是将数字指示器和title都放在adapter中的,如果不想这样你也可以直接设置自定义的数字指示器
                banner.setAdapter(new ImageTitleNumAdapter(DataBean.getTestData()));
                banner.removeIndicator();
                break;
            case R.id.style_multiple:
                refresh.setEnabled(true);
                banner.setIndicator(new CircleIndicator(this));
                banner.setAdapter(new MultipleTypesAdapter(this, DataBean.getTestData()));
                break;
            case R.id.style_net_image:
                refresh.setEnabled(false);
                //方法一:使用自定义图片适配器
//                banner.setAdapter(new ImageNetAdapter(DataBean.getTestData3()));

                //方法二:使用自带的图片适配器
                banner.setAdapter(new BannerImageAdapter<DataBean>(DataBean.getTestData3()) {
                    @Override
                    public void onBindView(BannerImageHolder holder, DataBean data, int position, int size) {
                        //图片加载自己实现
                        Glide.with(holder.itemView)
                                .load(data.imageUrl)
                                .thumbnail(Glide.with(holder.itemView).load(R.drawable.loading))
                                .apply(RequestOptions.bitmapTransform(new RoundedCorners(30)))
                                .into(holder.imageView);
                    }
                });
                banner.setIndicator(new RoundLinesIndicator(this));
                banner.setIndicatorSelectedWidth(BannerUtils.dp2px(15));
                break;
            case R.id.change_indicator:
                indicator.setVisibility(View.VISIBLE);
                //在布局文件中使用指示器,这样更灵活
                banner.setIndicator(indicator, false);
                banner.setIndicatorSelectedWidth(BannerUtils.dp2px(15));
                break;
            case R.id.gallery:
                startActivity(new Intent(this, GalleryActivity.class));
                break;
            case R.id.rv_banner:
                startActivity(new Intent(this, RecyclerViewBannerActivity.class));
                break;
            case R.id.cl_banner:
                startActivity(new Intent(this, ConstraintLayoutBannerActivity.class));
                break;
            case R.id.vp_banner:
                startActivity(new Intent(this, Vp2FragmentRecyclerviewActivity.class));
                break;
            case R.id.banner_video:
                startActivity(new Intent(this, VideoActivity.class));
                break;
            case R.id.banner_tv:
                startActivity(new Intent(this, TVActivity.class));
                break;
            case R.id.topLine:
                startActivity(new Intent(this, TouTiaoActivity.class));
                break;
            default:
                throw new IllegalStateException("Unexpected value: " + view.getId());
        }
    }
}


================================================
FILE: app/src/main/java/com/test/banner/adapter/ImageAdapter.java
================================================
package com.test.banner.adapter;

import android.view.ViewGroup;
import android.widget.ImageView;

import com.test.banner.bean.DataBean;
import com.test.banner.viewholder.ImageHolder;
import com.youth.banner.adapter.BannerAdapter;

import java.util.List;

/**
 * 自定义布局,图片
 */
public class ImageAdapter extends BannerAdapter<DataBean, ImageHolder> {

    public ImageAdapter(List<DataBean> mDatas) {
        //设置数据,也可以调用banner提供的方法,或者自己在adapter中实现
        super(mDatas);
    }

    //更新数据
    public void updateData(List<DataBean> data) {
        //这里的代码自己发挥,比如如下的写法等等
        mDatas.clear();
        mDatas.addAll(data);
        notifyDataSetChanged();
    }


    //创建ViewHolder,可以用viewType这个字段来区分不同的ViewHolder
    @Override
    public ImageHolder onCreateHolder(ViewGroup parent, int viewType) {
        ImageView imageView = new ImageView(parent.getContext());
        //注意,必须设置为match_parent,这个是viewpager2强制要求的
        ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT);
        imageView.setLayoutParams(params);
        imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
        return new ImageHolder(imageView);
    }

    @Override
    public void onBindView(ImageHolder holder, DataBean data, int position, int size) {
        holder.imageView.setImageResource(data.imageRes);
    }

}


================================================
FILE: app/src/main/java/com/test/banner/adapter/ImageNetAdapter.java
================================================
package com.test.banner.adapter;

import android.graphics.Bitmap;
import android.graphics.Outline;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewOutlineProvider;
import android.widget.ImageView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;

import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.request.target.BitmapImageViewTarget;
import com.bumptech.glide.request.target.SimpleTarget;
import com.bumptech.glide.request.transition.Transition;
import com.test.banner.R;
import com.test.banner.bean.DataBean;
import com.test.banner.viewholder.ImageHolder;
import com.youth.banner.adapter.BannerAdapter;
import com.youth.banner.util.BannerUtils;

import java.util.List;

/**
 * 自定义布局,网络图片
 */
public class ImageNetAdapter extends BannerAdapter<DataBean, ImageHolder> {

    public ImageNetAdapter(List<DataBean> mDatas) {
        super(mDatas);
    }

    @Override
    public ImageHolder onCreateHolder(ViewGroup parent, int viewType) {
        ImageView imageView = (ImageView) BannerUtils.getView(parent, R.layout.banner_image);
        //通过裁剪实现圆角
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            BannerUtils.setBannerRound(imageView, 20);
        }
        return new ImageHolder(imageView);
    }

    @Override
    public void onBindView(ImageHolder holder, DataBean data, int position, int size) {
        //通过图片加载器实现圆角,你也可以自己使用圆角的imageview,实现圆角的方法很多,自己尝试哈
        Glide.with(holder.itemView)
             .load(data.imageUrl)
             .thumbnail(Glide.with(holder.itemView).load(R.drawable.loading))
             .skipMemoryCache(true)
             .diskCacheStrategy(DiskCacheStrategy.NONE)
//                .apply(RequestOptions.bitmapTransform(new RoundedCorners(30)))
             .into(holder.imageView);
    }

}


================================================
FILE: app/src/main/java/com/test/banner/adapter/ImageTitleAdapter.java
================================================
package com.test.banner.adapter;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.test.banner.bean.DataBean;
import com.test.banner.R;
import com.test.banner.viewholder.ImageTitleHolder;
import com.youth.banner.adapter.BannerAdapter;
import com.youth.banner.util.BannerUtils;

import java.util.List;

/**
 * 自定义布局,图片+标题
 */

public class ImageTitleAdapter extends BannerAdapter<DataBean, ImageTitleHolder> {

    public ImageTitleAdapter(List<DataBean> mDatas) {
        super(mDatas);
    }

    @Override
    public ImageTitleHolder onCreateHolder(ViewGroup parent, int viewType) {
        return new ImageTitleHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.banner_image_title, parent, false));
    }

    @Override
    public void onBindView(ImageTitleHolder holder, DataBean data, int position, int size) {
        holder.imageView.setImageResource(data.imageRes);
        holder.title.setText(data.title);
    }

}


================================================
FILE: app/src/main/java/com/test/banner/adapter/ImageTitleNumAdapter.java
================================================
package com.test.banner.adapter;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import com.test.banner.bean.DataBean;
import com.test.banner.R;
import com.youth.banner.adapter.BannerAdapter;

import java.util.List;

/**
 * 自定义布局,图片+标题+数字指示器
 */
public class ImageTitleNumAdapter extends BannerAdapter<DataBean, ImageTitleNumAdapter.BannerViewHolder> {

    public ImageTitleNumAdapter(List<DataBean> mDatas) {
        //设置数据,也可以调用banner提供的方法
        super(mDatas);
    }

    //创建ViewHolder,可以用viewType这个字段来区分不同的ViewHolder
    @Override
    public BannerViewHolder onCreateHolder(ViewGroup parent, int viewType) {
        //注意布局文件,item布局文件要设置为match_parent,这个是viewpager2强制要求的
        //或者调用BannerUtils.getView(parent,R.layout.banner_image_title_num);
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.banner_image_title_num, parent, false);
        return new BannerViewHolder(view);
    }

    //绑定数据
    @Override
    public void onBindView(BannerViewHolder holder, DataBean data, int position, int size) {
        holder.imageView.setImageResource(data.imageRes);
        holder.title.setText(data.title);
        //可以在布局文件中自己实现指示器,亦可以使用banner提供的方法自定义指示器,目前样式较少,后面补充
        holder.numIndicator.setText((position + 1) + "/" + size);
    }


    class BannerViewHolder extends RecyclerView.ViewHolder {
        ImageView imageView;
        TextView title;
        TextView numIndicator;

        public BannerViewHolder(@NonNull View view) {
            super(view);
            imageView = view.findViewById(R.id.image);
            title = view.findViewById(R.id.bannerTitle);
            numIndicator = view.findViewById(R.id.numIndicator);
        }
    }

}


================================================
FILE: app/src/main/java/com/test/banner/adapter/MultipleTypesAdapter.java
================================================
package com.test.banner.adapter;

import android.content.Context;
import android.graphics.Color;
import android.util.SparseArray;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;

import androidx.recyclerview.widget.RecyclerView;

import com.test.banner.R;
import com.test.banner.bean.DataBean;
import com.test.banner.viewholder.ImageHolder;
import com.test.banner.viewholder.TitleHolder;
import com.test.banner.viewholder.VideoHolder;
import com.youth.banner.adapter.BannerAdapter;
import com.youth.banner.util.BannerUtils;

import java.util.List;

/**
 * 自定义布局,多个不同UI切换
 */
public class MultipleTypesAdapter extends BannerAdapter<DataBean, RecyclerView.ViewHolder> {
    private Context context;
    private SparseArray<RecyclerView.ViewHolder> mVHMap = new SparseArray<>();

    public MultipleTypesAdapter(Context context, List<DataBean> mDatas) {
        super(mDatas);
        this.context = context;
    }

    @Override
    public RecyclerView.ViewHolder onCreateHolder(ViewGroup parent, int viewType) {
        switch (viewType) {
            case 1:
                return new ImageHolder(BannerUtils.getView(parent, R.layout.banner_image));
            case 2:
                return new VideoHolder(BannerUtils.getView(parent, R.layout.banner_video));
            case 3:
                return new TitleHolder(BannerUtils.getView(parent, R.layout.banner_title));
        }
        return new ImageHolder(BannerUtils.getView(parent, R.layout.banner_image));
    }

    @Override
    public int getItemViewType(int position) {
        //先取得真实的position,在获取实体
//        return getData(getRealPosition(position)).viewType;
        //直接获取真实的实体
        return getRealData(position).viewType;
        //或者自己直接去操作集合
//        return mDatas.get(getRealPosition(position)).viewType;
    }

    @Override
    public void onBindView(RecyclerView.ViewHolder holder, DataBean data, int position, int size) {
        int viewType = holder.getItemViewType();
        switch (viewType) {
            case 1:
                ImageHolder imageHolder = (ImageHolder) holder;
                mVHMap.append(position,imageHolder);
                imageHolder.imageView.setImageResource(data.imageRes);
                break;
            case 2:
                VideoHolder videoHolder = (VideoHolder) holder;
                mVHMap.append(position,videoHolder);
                videoHolder.player.setUp(data.imageUrl, true, null);
                videoHolder.player.getBackButton().setVisibility(View.GONE);
                //增加封面
                ImageView imageView = new ImageView(context);
                imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
                imageView.setImageResource(R.drawable.image4);
                videoHolder.player.setThumbImageView(imageView);
//                videoHolder.player.startPlayLogic();
                break;
            case 3:
                TitleHolder titleHolder = (TitleHolder) holder;
                mVHMap.append(position,titleHolder);
                titleHolder.title.setText(data.title);
                titleHolder.title.setBackgroundColor(Color.parseColor(DataBean.getRandColor()));
                break;
        }
    }

    public SparseArray<RecyclerView.ViewHolder> getVHMap() {
        return mVHMap;
    }


}


================================================
FILE: app/src/main/java/com/test/banner/adapter/MyRecyclerViewAdapter.java
================================================
package com.test.banner.adapter;

import android.content.Context;
import android.graphics.Color;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.cardview.widget.CardView;
import androidx.recyclerview.widget.RecyclerView;

import com.test.banner.R;
import com.test.banner.bean.DataBean;
import com.youth.banner.Banner;
import com.youth.banner.indicator.RoundLinesIndicator;
import com.youth.banner.util.BannerUtils;

public class MyRecyclerViewAdapter extends RecyclerView.Adapter {
    private Context context;

    public MyRecyclerViewAdapter(Context context) {
        this.context = context;
    }

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        if (viewType==R.layout.item) {
            return new MyViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false));
        }else{
            return new MyBannerViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.banner, parent, false));
        }
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
        if (holder instanceof MyViewHolder) {
            ((MyViewHolder) holder).cardView.setBackgroundColor(Color.parseColor(DataBean.getRandColor()));
        }else if (holder instanceof MyBannerViewHolder){
            Banner banner=((MyBannerViewHolder) holder).banner;
            banner.setAdapter(new ImageNetAdapter(DataBean.getTestData3()));
            banner.setBannerRound(BannerUtils.dp2px(5));
            banner.setIndicator(new RoundLinesIndicator(context));
            banner.setIndicatorSelectedWidth((int) BannerUtils.dp2px(15));
        }

    }

    @Override
    public int getItemViewType(int position) {
        if (position%2==0){
            return R.layout.item;
        }else{
            return R.layout.banner;
        }
    }

    @Override
    public int getItemCount() {
        return 10;
    }


    //banner 内部已实现
//    @Override
//    public void onViewDetachedFromWindow(@NonNull RecyclerView.ViewHolder holder) {
//        super.onViewDetachedFromWindow(holder);
//        Log.e("banner_log", "onViewDetachedFromWindow:" + holder.getAdapterPosition());
//        //定位你的位置
//        if (holder.getAdapterPosition()%2!=0) {
//            if (holder instanceof MyBannerViewHolder) {
//                ((MyBannerViewHolder) holder).banner.stop();
//            }
//        }
//    }
//
//    @Override
//    public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) {
//        super.onViewAttachedToWindow(holder);
//        Log.e("banner_log", "onViewAttachedToWindow:" + holder.getAdapterPosition());
//        if (holder.getAdapterPosition()%2!=0) {
//            if (holder instanceof MyBannerViewHolder) {
//                ((MyBannerViewHolder) holder).banner.start();
//            }
//        }
//    }

    class MyViewHolder extends RecyclerView.ViewHolder {
        public CardView cardView;

        public MyViewHolder(@NonNull View itemView) {
            super(itemView);
            cardView = itemView.findViewById(R.id.card_view);
        }
    }

    class MyBannerViewHolder extends RecyclerView.ViewHolder {
        public Banner banner;

        public MyBannerViewHolder(@NonNull View itemView) {
            super(itemView);
            banner = itemView.findViewById(R.id.banner);
        }
    }
}

================================================
FILE: app/src/main/java/com/test/banner/adapter/TopLineAdapter.java
================================================
package com.test.banner.adapter;

import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import com.test.banner.bean.DataBean;
import com.test.banner.R;
import com.youth.banner.adapter.BannerAdapter;
import com.youth.banner.util.BannerUtils;

import java.util.List;

/**
 * 自定义布局,实现类似1号店、淘宝头条的滚动效果
 */
public class TopLineAdapter extends BannerAdapter<DataBean, TopLineAdapter.TopLineHolder> {

    public TopLineAdapter(List<DataBean> mDatas) {
        super(mDatas);
    }

    @Override
    public TopLineHolder onCreateHolder(ViewGroup parent, int viewType) {
        return new TopLineHolder(BannerUtils.getView(parent,R.layout.top_line_item2));
    }

    @Override
    public void onBindView(TopLineHolder holder, DataBean data, int position, int size) {
        holder.message.setText(data.title);
        if (data.viewType==1) {
            holder.source.setText("1号店");
        }else if (data.viewType==2) {
            holder.source.setText("淘宝头条");
        }else if (data.viewType==3) {
            holder.source.setText("京东快报");
        }
    }

    class TopLineHolder extends RecyclerView.ViewHolder {
        public TextView message;
        public TextView source;

        public TopLineHolder(@NonNull View view) {
            super(view);
            message=view.findViewById(R.id.message);
            source=view.findViewById(R.id.source);
        }
    }
}


================================================
FILE: app/src/main/java/com/test/banner/bean/DataBean.java
================================================
package com.test.banner.bean;

import com.test.banner.R;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class DataBean {
    public Integer imageRes;
    public String imageUrl;
    public String title;
    public int viewType;

    public DataBean(Integer imageRes, String title, int viewType) {
        this.imageRes = imageRes;
        this.title = title;
        this.viewType = viewType;
    }

    public DataBean(String imageUrl, String title, int viewType) {
        this.imageUrl = imageUrl;
        this.title = title;
        this.viewType = viewType;
    }

    public static List<DataBean> getTestData() {
        List<DataBean> list = new ArrayList<>();
        list.add(new DataBean(R.drawable.image1, "相信自己,你努力的样子真的很美", 1));
        list.add(new DataBean(R.drawable.image2, "极致简约,梦幻小屋", 3));
        list.add(new DataBean(R.drawable.image3, "超级卖梦人", 3));
        list.add(new DataBean(R.drawable.image4, "夏季新搭配", 1));
        list.add(new DataBean(R.drawable.image5, "绝美风格搭配", 1));
        list.add(new DataBean(R.drawable.image6, "微微一笑 很倾城", 3));
        return list;
    }

    public static List<DataBean> getTestData2() {
        List<DataBean> list = new ArrayList<>();
        list.add(new DataBean(R.drawable.image7, "听风.赏雨", 3));
        list.add(new DataBean(R.drawable.image8, "迪丽热巴.迪力木拉提", 1));
        list.add(new DataBean(R.drawable.image9, "爱美.人间有之", 3));
        list.add(new DataBean(R.drawable.image10, "洋洋洋.气质篇", 1));
        list.add(new DataBean(R.drawable.image11, "生活的态度", 3));
        return list;
    }

    /**
     * 仿淘宝商品详情第一个是视频
     * @return
     */
    public static List<DataBean> getTestDataVideo() {
        List<DataBean> list = new ArrayList<>();
        list.add(new DataBean("http://vfx.mtime.cn/Video/2019/03/09/mp4/190309153658147087.mp4", "第一个放视频", 2));
        list.add(new DataBean(R.drawable.image7, "听风.赏雨", 1));
        list.add(new DataBean(R.drawable.image8, "迪丽热巴.迪力木拉提", 1));
        list.add(new DataBean(R.drawable.image9, "爱美.人间有之", 1));
        list.add(new DataBean(R.drawable.image10, "洋洋洋.气质篇", 1));
        list.add(new DataBean(R.drawable.image11, "生活的态度", 1));
        return list;
    }

    public static List<DataBean> getTestData3() {
        List<DataBean> list = new ArrayList<>();
        list.add(new DataBean("https://img.zcool.cn/community/013de756fb63036ac7257948747896.jpg", null, 1));
        list.add(new DataBean("https://img.zcool.cn/community/01639a56fb62ff6ac725794891960d.jpg", null, 1));
        list.add(new DataBean("https://img.zcool.cn/community/01270156fb62fd6ac72579485aa893.jpg", null, 1));
        list.add(new DataBean("https://img.zcool.cn/community/01233056fb62fe32f875a9447400e1.jpg", null, 1));
        list.add(new DataBean("https://img.zcool.cn/community/016a2256fb63006ac7257948f83349.jpg", null, 1));
        return list;
    }

    public static List<DataBean> getVideos() {
        List<DataBean> list = new ArrayList<>();
        list.add(new DataBean("http://vfx.mtime.cn/Video/2019/03/21/mp4/190321153853126488.mp4", null, 0));
        list.add(new DataBean("http://vfx.mtime.cn/Video/2019/03/18/mp4/190318231014076505.mp4", null, 0));
        list.add(new DataBean("http://vfx.mtime.cn/Video/2019/03/18/mp4/190318214226685784.mp4", null, 0));
        list.add(new DataBean("http://vfx.mtime.cn/Video/2019/03/19/mp4/190319125415785691.mp4", null, 0));
        list.add(new DataBean("http://vfx.mtime.cn/Video/2019/03/14/mp4/190314223540373995.mp4", null, 0));
        list.add(new DataBean("http://vfx.mtime.cn/Video/2019/03/14/mp4/190314102306987969.mp4", null, 0));
        return list;
    }


    public static List<String> getColors(int size) {
        List<String> list = new ArrayList<>();
        for(int i = 0; i < size; i++) {
            list.add(getRandColor());
        }
        return list;
    }

    /**
     * 获取十六进制的颜色代码.例如  "#5A6677"
     * 分别取R、G、B的随机值,然后加起来即可
     *
     * @return String
     */
    public static String getRandColor() {
        String R, G, B;
        Random random = new Random();
        R = Integer.toHexString(random.nextInt(256)).toUpperCase();
        G = Integer.toHexString(random.nextInt(256)).toUpperCase();
        B = Integer.toHexString(random.nextInt(256)).toUpperCase();

        R = R.length() == 1 ? "0" + R : R;
        G = G.length() == 1 ? "0" + G : G;
        B = B.length() == 1 ? "0" + B : B;

        return "#" + R + G + B;
    }
}


================================================
FILE: app/src/main/java/com/test/banner/indicator/NumIndicator.java
================================================
package com.test.banner.indicator;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;

import com.youth.banner.indicator.BaseIndicator;
import com.youth.banner.util.BannerUtils;

/**
 * 自定义数字指示器demo,比较简单,具体的自己发挥
 *
 * 这里没有用的自定义属性的参数,可以考虑加上
 */
public class NumIndicator extends BaseIndicator {
    private int width;
    private int height;
    private int radius;

    public NumIndicator(Context context) {
        this(context, null);
    }

    public NumIndicator(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public NumIndicator(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mPaint.setTextSize(BannerUtils.dp2px(10));
        mPaint.setTextAlign(Paint.Align.CENTER);
        width = (int) BannerUtils.dp2px(30);
        height = (int) BannerUtils.dp2px(15);
        radius = (int) BannerUtils.dp2px(20);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int count = config.getIndicatorSize();
        if (count <= 1) {
            return;
        }
        setMeasuredDimension(width, height);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int count = config.getIndicatorSize();
        if (count <= 1) {
            return;
        }

        RectF rectF = new RectF(0, 0, width, height);
        mPaint.setColor(Color.parseColor("#70000000"));
        canvas.drawRoundRect(rectF, radius, radius, mPaint);

        String text = config.getCurrentPosition() + 1 + "/" + count;
        mPaint.setColor(Color.WHITE);
        canvas.drawText(text, width / 2, (float) (height * 0.7), mPaint);

    }

}


================================================
FILE: app/src/main/java/com/test/banner/ui/BannerFragment.java
================================================
package com.test.banner.ui;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;

import com.test.banner.R;
import com.test.banner.adapter.ImageNetAdapter;
import com.test.banner.bean.DataBean;
import com.youth.banner.Banner;
import com.youth.banner.indicator.RectangleIndicator;
import com.youth.banner.util.BannerUtils;

import butterknife.BindView;
import butterknife.ButterKnife;

public class BannerFragment extends Fragment {

    @BindView(R.id.banner)
    Banner banner;

    public static Fragment newInstance() {
        return new BannerFragment();
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.banner, container, false);
        ButterKnife.bind(this, view);
        return view;
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        banner.setAdapter(new ImageNetAdapter(DataBean.getTestData3()));
        banner.setIndicator(new RectangleIndicator(getActivity()));
        banner.setIndicatorSpace((int) BannerUtils.dp2px(4));
        banner.setIndicatorRadius(0);
    }

    @Override
    public void onStart() {
        super.onStart();
        banner.start();
    }

    @Override
    public void onStop() {
        super.onStop();
        banner.stop();
    }
}


================================================
FILE: app/src/main/java/com/test/banner/ui/BannerListFragment.java
================================================
package com.test.banner.ui;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.test.banner.R;
import com.test.banner.adapter.MyRecyclerViewAdapter;
import com.test.banner.util.ParentRecyclerView;

import butterknife.BindView;
import butterknife.ButterKnife;

public class BannerListFragment extends Fragment {
    private static int index;
    @BindView(R.id.net_rv)
    RecyclerView recyclerView;
    @BindView(R.id.text)
    TextView text;

    public static Fragment newInstance(int i) {
        index = i;
        return new BannerListFragment();
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.activity_recyclerview_banner, container, false);
        ButterKnife.bind(this,view);
        return view;
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        text.setText("当前页:"+index);
        recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
        recyclerView.setAdapter(new MyRecyclerViewAdapter(getActivity()));
    }

}


================================================
FILE: app/src/main/java/com/test/banner/ui/BlankFragment.java
================================================
package com.test.banner.ui;

import android.os.Bundle;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.RecyclerView;

import com.test.banner.R;
import com.test.banner.adapter.ImageNetAdapter;
import com.test.banner.adapter.MyRecyclerViewAdapter;
import com.test.banner.bean.DataBean;
import com.test.banner.indicator.NumIndicator;
import com.youth.banner.Banner;
import com.youth.banner.config.IndicatorConfig;
import com.youth.banner.indicator.CircleIndicator;
import com.youth.banner.util.BannerUtils;

import butterknife.BindView;
import butterknife.ButterKnife;

public class BlankFragment extends Fragment {

    public static Fragment newInstance() {
        return new BlankFragment();
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.test,null);
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        LinearLayout linearLayout = getView().findViewById(R.id.ll_view);

        //通过new的方式创建banner
        Banner banner = new Banner(getActivity());
        banner.setAdapter(new ImageNetAdapter(DataBean.getTestData3()));
        banner.addBannerLifecycleObserver(this);
        banner.setIndicator(new CircleIndicator(getActivity()));

        //将banner加入到父容器中,实际使用不一定一样
        linearLayout.addView(banner, LinearLayout.LayoutParams.MATCH_PARENT, (int) BannerUtils.dp2px(120));
    }
}


================================================
FILE: app/src/main/java/com/test/banner/ui/ConstraintLayoutBannerActivity.java
================================================
package com.test.banner.ui;

import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;

import androidx.appcompat.app.AppCompatActivity;

import com.test.banner.R;
import com.test.banner.adapter.ImageAdapter;
import com.test.banner.adapter.ImageNetAdapter;
import com.test.banner.adapter.ImageTitleAdapter;
import com.test.banner.bean.DataBean;
import com.youth.banner.Banner;
import com.youth.banner.config.BannerConfig;
import com.youth.banner.config.IndicatorConfig;
import com.youth.banner.indicator.CircleIndicator;
import com.youth.banner.util.BannerUtils;

import butterknife.BindView;
import butterknife.ButterKnife;

public class ConstraintLayoutBannerActivity extends AppCompatActivity {
    private static final String TAG = "banner_log";
    @BindView(R.id.banner)
    Banner banner;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_constraint_layout_banner);
        ButterKnife.bind(this);
        banner.setAdapter(new ImageTitleAdapter(DataBean.getTestData()));
        banner.setIndicator(new CircleIndicator(this));
        banner.setIndicatorSelectedColorRes(R.color.main_color);
        banner.setIndicatorGravity(IndicatorConfig.Direction.RIGHT);
        banner.setIndicatorMargins(new IndicatorConfig.Margins(0, 0,
                BannerConfig.INDICATOR_MARGIN, (int) BannerUtils.dp2px(12)));
        banner.addBannerLifecycleObserver(this);
    }

}


================================================
FILE: app/src/main/java/com/test/banner/ui/GalleryActivity.java
================================================
package com.test.banner.ui;

import android.os.Bundle;
import android.view.View;

import com.test.banner.R;
import com.test.banner.adapter.ImageAdapter;
import com.test.banner.adapter.ImageNetAdapter;
import com.test.banner.bean.DataBean;
import com.youth.banner.Banner;
import com.youth.banner.indicator.CircleIndicator;
import com.youth.banner.indicator.DrawableIndicator;
import com.youth.banner.transformer.AlphaPageTransformer;

import androidx.appcompat.app.AppCompatActivity;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;

public class GalleryActivity extends AppCompatActivity {

    @BindView(R.id.banner1)
    Banner mBanner1;
    @BindView(R.id.banner2)
    Banner mBanner2;
    @BindView(R.id.indicator)
    DrawableIndicator indicator;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_gallery);
        ButterKnife.bind(this);

        /**
         * 画廊效果
         */
        mBanner1.setAdapter(new ImageAdapter(DataBean.getTestData2()));
        mBanner1.setIndicator(new CircleIndicator(this));
        //添加画廊效果
        mBanner1.setBannerGalleryEffect(50, 10);
        //(可以和其他PageTransformer组合使用,比如AlphaPageTransformer,注意但和其他带有缩放的PageTransformer会显示冲突)
        //添加透明效果(画廊配合透明效果更棒)
        //mBanner1.addPageTransformer(new AlphaPageTransformer());


        /**
         * 魅族效果
         */
        mBanner2.setAdapter(new ImageAdapter(DataBean.getTestData()));
        mBanner2.setIndicator(indicator,false);
        //添加魅族效果
        mBanner2.setBannerGalleryMZ(20);



    }


}

================================================
FILE: app/src/main/java/com/test/banner/ui/RecyclerViewBannerActivity.java
================================================
package com.test.banner.ui;

import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.test.banner.R;
import com.test.banner.adapter.MyRecyclerViewAdapter;

import butterknife.BindView;
import butterknife.ButterKnife;

public class RecyclerViewBannerActivity extends AppCompatActivity {
    @BindView(R.id.net_rv)
    RecyclerView recyclerView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_recyclerview_banner);
        ButterKnife.bind(this);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        recyclerView.setAdapter(new MyRecyclerViewAdapter(this));
    }

}


================================================
FILE: app/src/main/java/com/test/banner/ui/TVActivity.java
================================================
package com.test.banner.ui;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;

import com.test.banner.R;
import com.test.banner.adapter.ImageAdapter;
import com.test.banner.bean.DataBean;
import com.youth.banner.Banner;
import com.youth.banner.indicator.CircleIndicator;
import com.youth.banner.util.BannerUtils;

import butterknife.BindView;
import butterknife.ButterKnife;

public class TVActivity extends AppCompatActivity {

    private static final String TAG = "banner_log";
    @BindView(R.id.banner)
    Banner banner;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_t_v);
        ButterKnife.bind(this);
        banner.setAdapter(new ImageAdapter(DataBean.getTestData()));
        banner.setIndicator(new CircleIndicator(this));
        banner.isAutoLoop(false);
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        int count = banner.getItemCount();
        switch (keyCode) {
            case KeyEvent.KEYCODE_DPAD_LEFT:
                Log.d(TAG, "向左");
                int prev = (banner.getCurrentItem() - 1) % count;
                if (prev == 0) {
                    prev = banner.getRealCount();
                } else if (prev == count - 1) {
                    prev = 1;
                }
                banner.setCurrentItem(prev, false);
                break;
            case KeyEvent.KEYCODE_DPAD_RIGHT:
                Log.d(TAG, "向右");
                int next = (banner.getCurrentItem() + 1) % count;
                if (next == 0) {
                    next = banner.getRealCount();
                } else if (next == count - 1) {
                    next = 1;
                }
                banner.setCurrentItem(next, false);
                break;
        }
        //如果没有设置指示器,就不用执行下面两行
        int real = BannerUtils.getRealPosition(banner.isInfiniteLoop(), banner.getCurrentItem(), banner.getRealCount());
        banner.getIndicator().onPageSelected(real);
        return super.onKeyDown(keyCode, event);
    }

}


================================================
FILE: app/src/main/java/com/test/banner/ui/TouTiaoActivity.java
================================================
package com.test.banner.ui;

import androidx.appcompat.app.AppCompatActivity;
import butterknife.BindView;
import butterknife.ButterKnife;

import android.os.Bundle;

import com.google.android.material.snackbar.Snackbar;
import com.test.banner.R;
import com.test.banner.adapter.TopLineAdapter;
import com.test.banner.bean.DataBean;
import com.youth.banner.Banner;
import com.youth.banner.transformer.ZoomOutPageTransformer;
import com.youth.banner.util.LogUtils;

public class TouTiaoActivity extends AppCompatActivity {
    @BindView(R.id.banner)
    Banner banner;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_tou_tiao);
        ButterKnife.bind(this);

        //实现1号店和淘宝头条类似的效果
        banner.setAdapter(new TopLineAdapter(DataBean.getTestData2()))
               .setOrientation(Banner.VERTICAL)
               .setPageTransformer(new ZoomOutPageTransformer())
               .setOnBannerListener((data, position) -> {
                   Snackbar.make(banner, ((DataBean) data).title, Snackbar.LENGTH_SHORT).show();
                   LogUtils.d("position:" + position);
               });

    }
}

================================================
FILE: app/src/main/java/com/test/banner/ui/VideoActivity.java
================================================
package com.test.banner.ui;

import android.os.Bundle;
import android.util.Log;

import com.shuyu.gsyvideoplayer.GSYVideoManager;
import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer;
import com.test.banner.R;
import com.test.banner.adapter.MultipleTypesAdapter;
import com.test.banner.bean.DataBean;
import com.test.banner.indicator.NumIndicator;
import com.test.banner.viewholder.VideoHolder;
import com.youth.banner.Banner;
import com.youth.banner.config.IndicatorConfig;
import com.youth.banner.listener.OnPageChangeListener;

import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.RecyclerView;
import butterknife.BindView;
import butterknife.ButterKnife;

/**
 * 仿淘宝商品详情,banner第一个放视频,然后首尾不能自己滑动,加上自定义数字指示器
 */
public class VideoActivity extends AppCompatActivity {
    @BindView(R.id.banner)
    Banner banner;
    StandardGSYVideoPlayer player;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_video);
        ButterKnife.bind(this);

        banner.addBannerLifecycleObserver(this)
                .setAdapter(new MultipleTypesAdapter(this, DataBean.getTestDataVideo()))
                .setIndicator(new NumIndicator(this))
                .setIndicatorGravity(IndicatorConfig.Direction.RIGHT)
                .addOnPageChangeListener(new OnPageChangeListener() {
                    @Override
                    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                        stopVideo(position);
                    }

                    @Override
                    public void onPageSelected(int position) {
                        Log.e("--","position:"+position);
                        stopVideo(position);
                    }

                    @Override
                    public void onPageScrollStateChanged(int state) {

                    }
                });
    }

    private void stopVideo(int position) {
        if (player == null) {
            RecyclerView.ViewHolder viewHolder = banner.getAdapter().getViewHolder();
            if (viewHolder instanceof VideoHolder) {
                VideoHolder holder = (VideoHolder) viewHolder;
                player = holder.player;
                if (position != 0) {
                    player.onVideoPause();
                }
            }
        }else {
            if (position != 0) {
                player.onVideoPause();
            }
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (player != null)
            player.onVideoPause();
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (player != null)
            player.onVideoResume();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        GSYVideoManager.releaseAllVideos();
    }

    @Override
    public void onBackPressed() {
        //释放所有
        if (player != null)
            player.setVideoAllCallBack(null);
        super.onBackPressed();
    }

}


================================================
FILE: app/src/main/java/com/test/banner/ui/Vp2FragmentRecyclerviewActivity.java
================================================
package com.test.banner.ui;

import android.os.Bundle;

import com.google.android.material.tabs.TabLayout;
import com.test.banner.R;
import com.test.banner.adapter.ImageAdapter;
import com.test.banner.bean.DataBean;
import com.test.banner.util.TabLayoutMediator;
import com.youth.banner.Banner;
import com.youth.banner.indicator.CircleIndicator;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import androidx.viewpager2.widget.ViewPager2;
import butterknife.BindView;
import butterknife.ButterKnife;

public class Vp2FragmentRecyclerviewActivity extends AppCompatActivity {

    @BindView(R.id.vp2)
    ViewPager2 viewPager2;
    @BindView(R.id.tab_layout)
    TabLayout mTabLayout;
    @BindView(R.id.banner)
    Banner mBanner;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_vp2_fragment_recyclerview);
        ButterKnife.bind(this);

        viewPager2.setAdapter(new FragmentStateAdapter(this) {
            @NonNull
            @Override
            public Fragment createFragment(int position) {
                if (position == 0) {
                    return BannerListFragment.newInstance(position);
                } else if (position == 1) {
                    return BlankFragment.newInstance();
                } else {
                    return BannerFragment.newInstance();
                }
            }

            @Override
            public int getItemCount() {
                return 3;
            }
        });

        new TabLayoutMediator(mTabLayout, viewPager2, (tab, position) -> {
            tab.setText("页面" + position);
        }).attach();


        mBanner.addBannerLifecycleObserver(this)
               .setAdapter(new ImageAdapter(DataBean.getTestData()))
               .setIntercept(false)
               .setIndicator(new CircleIndicator(this));
    }
}


================================================
FILE: app/src/main/java/com/test/banner/util/ParentRecyclerView.java
================================================
package com.test.banner.util;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;

public class ParentRecyclerView extends RecyclerView {
    public ParentRecyclerView(@NonNull Context context) {
        super(context);
    }

    public ParentRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public ParentRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    private float mStartX, mStartY;

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mStartX = ev.getX();
                mStartY = ev.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                float endX = ev.getX();
                float endY = ev.getY();
                float distanceX = Math.abs(endX - mStartX);
                float distanceY = Math.abs(endY - mStartY);
                getParent().requestDisallowInterceptTouchEvent(!(distanceX > 4 && distanceX > distanceY));
                break;
        }
        return super.dispatchTouchEvent(ev);
    }
}


================================================
FILE: app/src/main/java/com/test/banner/util/TabLayoutMediator.java
================================================
package com.test.banner.util;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.recyclerview.widget.RecyclerView;
import androidx.viewpager2.widget.ViewPager2;

import com.google.android.material.tabs.TabLayout;

import java.lang.ref.WeakReference;
import java.lang.reflect.Method;

import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
import static androidx.viewpager2.widget.ViewPager2.SCROLL_STATE_DRAGGING;
import static androidx.viewpager2.widget.ViewPager2.SCROLL_STATE_IDLE;
import static androidx.viewpager2.widget.ViewPager2.SCROLL_STATE_SETTLING;

/**
 * A mediator to link a TabLayout with a ViewPager2. The mediator will synchronize the ViewPager2's
 * position with the selected tab when a tab is selected, and the TabLayout's scroll position when
 * the user drags the ViewPager2.
 *
 * Establish the link by creating an instance of this class, make sure the ViewPager2 has an adapter
 * and then call {@link #attach()} on it. When creating an instance of this class, you must supply
 * an implementation of {@link OnConfigureTabCallback} in which you set the text of the tab, and/or
 * perform any styling of the tabs that you require.
 *
 * @hide
 */
@RestrictTo(LIBRARY_GROUP)
public final class TabLayoutMediator {
    private final @NonNull TabLayout mTabLayout;
    private final @NonNull ViewPager2 mViewPager;
    private final boolean mAutoRefresh;
    private final OnConfigureTabCallback mOnConfigureTabCallback;
    private RecyclerView.Adapter mAdapter;
    private boolean mAttached;

    private TabLayoutOnPageChangeCallback mOnPageChangeCallback;
    private TabLayout.OnTabSelectedListener mOnTabSelectedListener;
    private RecyclerView.AdapterDataObserver mPagerAdapterObserver;

    /**
     * A callback interface that must be implemented to set the text and styling of newly created
     * tabs.
     */
    public interface OnConfigureTabCallback {
        /**
         * Called to configure the tab for the page at the specified position. Typically calls
         * {@link TabLayout.Tab#setText(CharSequence)}, but any form of styling can be applied.
         *
         * @param tab The Tab which should be configured to represent the title of the item at the
         *        given position in the data set.
         * @param position The position of the item within the adapter's data set.
         */
        void onConfigureTab(@NonNull TabLayout.Tab tab, int position);
    }

    /**
     * Creates a TabLayoutMediator to synchronize a TabLayout and a ViewPager2 together. It will
     * update the tabs automatically when the data set of the view pager's adapter changes. The link
     * will be established after {@link #attach()} is called.
     *
     * @param tabLayout The tab bar to link
     * @param viewPager The view pager to link
     */
    public TabLayoutMediator(@NonNull TabLayout tabLayout, @NonNull ViewPager2 viewPager,
                             @NonNull OnConfigureTabCallback onConfigureTabCallback) {
        this(tabLayout, viewPager, true, onConfigureTabCallback);
    }

    /**
     * Creates a TabLayoutMediator to synchronize a TabLayout and a ViewPager2 together. If {@code
     * autoRefresh} is true, it will update the tabs automatically when the data set of the view
     * pager's adapter changes. The link will be established after {@link #attach()} is called.
     *
     * @param tabLayout The tab bar to link
     * @param viewPager The view pager to link
     * @param autoRefresh If {@code true}, will recreate all tabs when the data set of the view
     *                   pager's adapter changes.
     */
    public TabLayoutMediator(@NonNull TabLayout tabLayout, @NonNull ViewPager2 viewPager,
                             boolean autoRefresh, @NonNull OnConfigureTabCallback onConfigureTabCallback) {
        mTabLayout = tabLayout;
        mViewPager = viewPager;
        mAutoRefresh = autoRefresh;
        mOnConfigureTabCallback = onConfigureTabCallback;
    }

    /**
     * Link the TabLayout and the ViewPager2 together.
     * @throws IllegalStateException If the mediator is already attached, or the ViewPager2 has no
     *         adapter.
     */
    public void attach() {
        if (mAttached) {
            throw new IllegalStateException("TabLayoutMediator is already attached");
        }
        mAdapter = mViewPager.getAdapter();
        if (mAdapter == null) {
            throw new IllegalStateException("TabLayoutMediator attached before ViewPager2 has an "
                    + "adapter");
        }
        mAttached = true;

        // Add our custom OnPageChangeCallback to the ViewPager
        mOnPageChangeCallback = new TabLayoutOnPageChangeCallback(mTabLayout);
        mViewPager.registerOnPageChangeCallback(mOnPageChangeCallback);

        // Now we'll add a tab selected listener to set ViewPager's current item
        mOnTabSelectedListener = new ViewPagerOnTabSelectedListener(mViewPager);
        mTabLayout.addOnTabSelectedListener(mOnTabSelectedListener);

        // Now we'll populate ourselves from the pager adapter, adding an observer if
        // autoRefresh is enabled
        if (mAutoRefresh) {
            // Register our observer on the new adapter
            mPagerAdapterObserver = new PagerAdapterObserver();
            mAdapter.registerAdapterDataObserver(mPagerAdapterObserver);
        }

        populateTabsFromPagerAdapter();

        // Now update the scroll position to match the ViewPager's current item
        mTabLayout.setScrollPosition(mViewPager.getCurrentItem(), 0f, true);
    }

    /**
     * Unlink the TabLayout and the ViewPager
     */
    public void detach() {
        mAdapter.unregisterAdapterDataObserver(mPagerAdapterObserver);
        mTabLayout.removeOnTabSelectedListener(mOnTabSelectedListener);
        mViewPager.unregisterOnPageChangeCallback(mOnPageChangeCallback);
        mPagerAdapterObserver = null;
        mOnTabSelectedListener = null;
        mOnPageChangeCallback = null;
        mAttached = false;
    }

    @SuppressWarnings("WeakerAccess")
    void populateTabsFromPagerAdapter() {
        mTabLayout.removeAllTabs();

        if (mAdapter != null) {
            int adapterCount = mAdapter.getItemCount();
            for (int i = 0; i < adapterCount; i++) {
                TabLayout.Tab tab = mTabLayout.newTab();
                mOnConfigureTabCallback.onConfigureTab(tab, i);
                mTabLayout.addTab(tab, false);
            }

            // Make sure we reflect the currently set ViewPager item
            if (adapterCount > 0) {
                int currItem = mViewPager.getCurrentItem();
                if (currItem != mTabLayout.getSelectedTabPosition()) {
                    mTabLayout.getTabAt(currItem).select();
                }
            }
        }
    }

    /**
     * A {@link ViewPager2.OnPageChangeCallback} class which contains the necessary calls back to
     * the provided {@link TabLayout} so that the tab position is kept in sync.
     *
     * <p>This class stores the provided TabLayout weakly, meaning that you can use {@link
     * ViewPager2#registerOnPageChangeCallback(ViewPager2.OnPageChangeCallback)} without removing
     * the callback and not cause a leak.
     */
    private static class TabLayoutOnPageChangeCallback extends ViewPager2.OnPageChangeCallback {
        private final WeakReference<TabLayout> mTabLayoutRef;
        private int mPreviousScrollState;
        private int mScrollState;

        TabLayoutOnPageChangeCallback(TabLayout tabLayout) {
            mTabLayoutRef = new WeakReference<>(tabLayout);
            reset();
        }

        @Override
        public void onPageScrollStateChanged(final int state) {
            mPreviousScrollState = mScrollState;
            mScrollState = state;
        }

        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
            TabLayout tabLayout = mTabLayoutRef.get();
            if (tabLayout != null) {
                // Only update the text selection if we're not settling, or we are settling after
                // being dragged
                boolean updateText = mScrollState != SCROLL_STATE_SETTLING
                        || mPreviousScrollState == SCROLL_STATE_DRAGGING;
                // Update the indicator if we're not settling after being idle. This is caused
                // from a setCurrentItem() call and will be handled by an animation from
                // onPageSelected() instead.
                boolean updateIndicator = !(mScrollState == SCROLL_STATE_SETTLING
                        && mPreviousScrollState == SCROLL_STATE_IDLE);
                setScrollPosition(tabLayout, position, positionOffset, updateText, updateIndicator);
            }
        }

        @Override
        public void onPageSelected(final int position) {
            TabLayout tabLayout = mTabLayoutRef.get();
            if (tabLayout != null
                    && tabLayout.getSelectedTabPosition() != position
                    && position < tabLayout.getTabCount()) {
                // Select the tab, only updating the indicator if we're not being dragged/settled
                // (since onPageScrolled will handle that).
                boolean updateIndicator = mScrollState == SCROLL_STATE_IDLE
                        || (mScrollState == SCROLL_STATE_SETTLING
                        && mPreviousScrollState == SCROLL_STATE_IDLE);
                selectTab(tabLayout, tabLayout.getTabAt(position), updateIndicator);
            }
        }

        void reset() {
            mPreviousScrollState = mScrollState = SCROLL_STATE_IDLE;
        }
    }

    // region Reflective calls

    // Temporarily call methods TabLayout.setScrollPosition(int, float, boolean, boolean) and
    // TabLayout.selectTab(TabLayout.Tab, boolean) through reflection, until they have been made
    // public in the Material Design Components library.

    private static Method sSetScrollPosition;
    private static Method sSelectTab;
    private static final String SET_SCROLL_POSITION_NAME = "TabLayout.setScrollPosition(int, float,"
            + " boolean, boolean)";
    private static final String SELECT_TAB_NAME = "TabLayout.selectTab(TabLayout.Tab, boolean)";

    static {
        try {
            sSetScrollPosition = TabLayout.class.getDeclaredMethod("setScrollPosition", int.class,
                    float.class, boolean.class, boolean.class);
            sSetScrollPosition.setAccessible(true);

            sSelectTab = TabLayout.class.getDeclaredMethod("selectTab", TabLayout.Tab.class,
                    boolean.class);
            sSelectTab.setAccessible(true);
        } catch (NoSuchMethodException e) {
            throw new IllegalStateException("Can't reflect into method TabLayout"
                    + ".setScrollPosition(int, float, boolean, boolean)");
        }
    }

    @SuppressWarnings("WeakerAccess")
    static void setScrollPosition(TabLayout tabLayout, int position, float positionOffset,
                                  boolean updateSelectedText, boolean updateIndicatorPosition) {
        try {
            if (sSetScrollPosition != null) {
                sSetScrollPosition.invoke(tabLayout, position, positionOffset, updateSelectedText,
                        updateIndicatorPosition);
            } else {
                throwMethodNotFound(SET_SCROLL_POSITION_NAME);
            }
        } catch (Exception e) {
            throwInvokeFailed(SET_SCROLL_POSITION_NAME);
        }
    }

    @SuppressWarnings("WeakerAccess")
    static void selectTab(TabLayout tabLayout, TabLayout.Tab tab, boolean updateIndicator) {
        try {
            if (sSelectTab != null) {
                sSelectTab.invoke(tabLayout, tab, updateIndicator);
            } else {
                throwMethodNotFound(SELECT_TAB_NAME);
            }
        } catch (Exception e) {
            throwInvokeFailed(SELECT_TAB_NAME);
        }
    }

    private static void throwMethodNotFound(String method) {
        throw new IllegalStateException("Method " + method + " not found");
    }

    private static void throwInvokeFailed(String method) {
        throw new IllegalStateException("Couldn't invoke method " + method);
    }

    // endregion

    /**
     * A {@link TabLayout.OnTabSelectedListener} class which contains the necessary calls back to
     * the provided {@link ViewPager2} so that the tab position is kept in sync.
     */
    private static class ViewPagerOnTabSelectedListener implements TabLayout.OnTabSelectedListener {
        private final ViewPager2 mViewPager;

        ViewPagerOnTabSelectedListener(ViewPager2 viewPager) {
            this.mViewPager = viewPager;
        }

        @Override
        public void onTabSelected(TabLayout.Tab tab) {
            mViewPager.setCurrentItem(tab.getPosition(), true);
        }

        @Override
        public void onTabUnselected(TabLayout.Tab tab) {
            // No-op
        }

        @Override
        public void onTabReselected(TabLayout.Tab tab) {
            // No-op
        }
    }

    private class PagerAdapterObserver extends RecyclerView.AdapterDataObserver {
        PagerAdapterObserver() {}

        @Override
        public void onChanged() {
            populateTabsFromPagerAdapter();
        }

        @Override
        public void onItemRangeChanged(int positionStart, int itemCount) {
            populateTabsFromPagerAdapter();
        }

        @Override
        public void onItemRangeChanged(int positionStart, int itemCount, @Nullable Object payload) {
            populateTabsFromPagerAdapter();
        }

        @Override
        public void onItemRangeInserted(int positionStart, int itemCount) {
            populateTabsFromPagerAdapter();
        }

        @Override
        public void onItemRangeRemoved(int positionStart, int itemCount) {
            populateTabsFromPagerAdapter();
        }

        @Override
        public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
            populateTabsFromPagerAdapter();
        }
    }
}



================================================
FILE: app/src/main/java/com/test/banner/viewholder/ImageHolder.java
================================================
package com.test.banner.viewholder;

import android.view.View;
import android.widget.ImageView;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

public class ImageHolder extends RecyclerView.ViewHolder {
    public ImageView imageView;

    public ImageHolder(@NonNull View view) {
        super(view);
        this.imageView = (ImageView) view;
    }
}

================================================
FILE: app/src/main/java/com/test/banner/viewholder/ImageTitleHolder.java
================================================
package com.test.banner.viewholder;

import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import com.test.banner.R;

public class ImageTitleHolder extends RecyclerView.ViewHolder {
    public ImageView imageView;
    public TextView title;

    public ImageTitleHolder(@NonNull View view) {
        super(view);
        imageView = view.findViewById(R.id.image);
        title = view.findViewById(R.id.bannerTitle);
    }
}


================================================
FILE: app/src/main/java/com/test/banner/viewholder/TitleHolder.java
================================================
package com.test.banner.viewholder;

import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import com.test.banner.R;

public class TitleHolder extends RecyclerView.ViewHolder {
    public TextView title;

    public TitleHolder(@NonNull View view) {
        super(view);
        title = view.findViewById(R.id.bannerTitle);
    }
}


================================================
FILE: app/src/main/java/com/test/banner/viewholder/VideoHolder.java
================================================
package com.test.banner.viewholder;

import android.view.View;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer;
import com.test.banner.R;

public class VideoHolder extends RecyclerView.ViewHolder {
    public StandardGSYVideoPlayer player;

    public VideoHolder(@NonNull View view) {
        super(view);
        player = view.findViewById(R.id.player);
    }
}


================================================
FILE: app/src/main/res/drawable/background.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <gradient
    android:startColor="#09000000"
    android:endColor="#aa000000"
    android:angle="270" />

</shape>

================================================
FILE: app/src/main/res/drawable/default_selecter.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@color/main_color" android:state_pressed="true"/>
    <item android:drawable="@color/main_color" android:state_selected="true"/>
    <item android:drawable="@android:color/transparent"/>
</selector>

================================================
FILE: app/src/main/res/drawable/green.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <corners android:radius="5dp" />
    <padding
        android:bottom="2dp"
        android:left="6dp"
        android:right="6dp"
        android:top="2dp" />
    <stroke android:color="@color/main_color" android:width="0.5dp"/>
</shape>

================================================
FILE: app/src/main/res/drawable/selected_radius.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval">
    <solid android:color="@color/main_color" />
    <corners android:radius="5dp" />
</shape>

================================================
FILE: app/src/main/res/drawable/unselected_radius.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval">
    <solid android:color="#ffffff" />
    <corners android:radius="5dp" />
</shape>

================================================
FILE: app/src/main/res/drawable/white.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <solid android:color="#55ffffff" />
</shape>

================================================
FILE: app/src/main/res/layout/activity_constraint_layout_banner.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ui.ConstraintLayoutBannerActivity">


    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="15dp"
        android:text="ConstraintLayout嵌套banner"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <com.youth.banner.Banner
        android:id="@+id/banner"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintDimensionRatio="2:1"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/textView" />
</androidx.constraintlayout.widget.ConstraintLayout>

================================================
FILE: app/src/main/res/layout/activity_gallery.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:banner="http://schemas.android.com/apk/res-auto"    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <com.youth.banner.Banner
        android:id="@+id/banner1"
        android:layout_width="match_parent"
        android:layout_height="140dp"
        android:layout_margin="10dp"
        banner:banner_radius="5dp"
        banner:banner_indicator_normal_color="@android:color/white"
        banner:banner_indicator_selected_color="@color/colorPrimary" />

    <com.youth.banner.Banner
        android:id="@+id/banner2"
        android:layout_width="match_parent"
        android:layout_height="140dp"
        android:layout_margin="10dp"
        banner:banner_radius="5dp"
        banner:banner_indicator_normal_color="@android:color/white"
        banner:banner_indicator_selected_color="@color/colorPrimary" />

    <com.youth.banner.indicator.DrawableIndicator
        android:id="@+id/indicator"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        banner:normal_drawable="@drawable/indicator_normal"
        banner:selected_drawable="@drawable/indicator_selected"/>
</LinearLayout>

================================================
FILE: app/src/main/res/layout/activity_main.xml
================================================
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:banner="http://schemas.android.com/apk/res-auto"
    android:id="@+id/swipeRefresh"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#f5f5f5">

        <com.youth.banner.Banner
            android:id="@+id/banner"
            android:layout_width="match_parent"
            android:layout_height="180dp"
            android:layout_margin="10dp"
            banner:banner_indicator_normal_color="@android:color/white"
            banner:banner_indicator_selected_color="@color/colorPrimary"
            banner:banner_radius="5dp"/>

        <com.youth.banner.indicator.RoundLinesIndicator
            android:id="@+id/indicator"
            android:layout_width="wrap_content"
            android:layout_height="20dp"
            android:layout_below="@+id/banner"
            android:layout_centerHorizontal="true"
            android:visibility="gone" />

        <androidx.core.widget.NestedScrollView
            android:id="@+id/scroll"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_below="@+id/banner"
            android:layout_marginTop="20dp">

            <RelativeLayout
                android:id="@+id/rl_main"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="#f5f5f5"
                android:scrollbars="none">

                <Button
                    android:id="@+id/style_image"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="图片" />

                <Button
                    android:id="@+id/style_image_title"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_toRightOf="@id/style_image"
                    android:text="图片+标题+指示器" />

                <Button
                    android:id="@+id/style_image_title_num"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_toRightOf="@+id/style_image_title"
                    android:text="图片+标题+数字" />

                <Button
                    android:id="@+id/style_multiple"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_below="@+id/style_image"
                    android:text="多类型UI"
                    android:textAllCaps="false" />

                <Button
                    android:id="@+id/style_net_image"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_below="@+id/style_image"
                    android:layout_toRightOf="@+id/style_multiple"
                    android:text="网络图片" />

                <Button
                    android:id="@+id/change_indicator"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_toRightOf="@+id/style_net_image"
                    android:layout_below="@+id/style_image_title_num"
                    android:text="外部指示器" />


                <Button
                    android:id="@+id/gallery"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_below="@+id/change_indicator"
                    android:text="画廊,魅族效果,Drawable指示器"
                    android:textAllCaps="false" />

                <Button
                    android:id="@+id/topLine"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_below="@+id/gallery"
                    android:text="用banner实现类似淘宝头条的效果"
                    android:textAllCaps="false" />

                <Button
                    android:id="@+id/rv_banner"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_below="@+id/topLine"
                    android:text="RecyclerView嵌套banner"
                    android:textAllCaps="false" />

                <Button
                    android:id="@+id/cl_banner"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_below="@+id/rv_banner"
                    android:text="ConstraintLayout嵌套banner"
                    android:textAllCaps="false" />

                <Button
                    android:id="@+id/vp_banner"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_below="@+id/cl_banner"
                    android:text="viewpaer2+fragment+RecyclerView嵌套banner"
                    android:textAllCaps="false" />

                <Button
                    android:id="@+id/banner_video"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_below="@+id/vp_banner"
                    android:text="仿淘宝商品详情banner"
                    android:textAllCaps="false" />

                <Button
                    android:id="@+id/banner_tv"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_below="@+id/banner_video"
                    android:text="测试在tv中,遥控切换banner"
                    android:textAllCaps="false" />
            </RelativeLayout>
        </androidx.core.widget.NestedScrollView>
    </RelativeLayout>

</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

================================================
FILE: app/src/main/res/layout/activity_recyclerview_banner.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <TextView
        android:id="@+id/text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="RecyclerView+banner"
        android:padding="10dp"
        android:gravity="center"/>

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/net_rv"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />


</LinearLayout>

================================================
FILE: app/src/main/res/layout/activity_t_v.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ui.TVActivity">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="15dp"
        android:text="TV中遥控控制banner切换,因为没有真机测试,所以不确定有没有问题,有测试环境的朋友可以多多反馈,或者修改哈"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <com.youth.banner.Banner
        android:id="@+id/banner"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:banner_indicator_selected_color="@color/colorPrimary"
        app:layout_constraintDimensionRatio="2:1"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/textView" />
</androidx.constraintlayout.widget.ConstraintLayout>

================================================
FILE: app/src/main/res/layout/activity_tou_tiao.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ui.TouTiaoActivity">
    <RelativeLayout
        android:id="@+id/topLine"
        android:layout_width="match_parent"
        android:layout_height="65dp"
        android:layout_below="@+id/tip2"
        android:background="#ffffff"
        android:layout_margin="5dp"
        android:paddingTop="10dp"
        android:paddingBottom="10dp"
        android:orientation="horizontal"
        tools:ignore="MissingConstraints">

        <ImageView
            android:id="@+id/image_top"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/home_hotpoint"
            android:layout_marginLeft="10dp"
            android:layout_marginRight="10dp"
            android:layout_centerVertical="true"/>

        <com.youth.banner.Banner
            android:id="@+id/banner"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_toRightOf="@+id/image_top"
            android:layout_toLeftOf="@+id/image_right"
            android:layout_centerVertical="true"/>
        <ImageView
            android:id="@+id/image_right"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/home_right_arrow"
            android:layout_marginLeft="10dp"
            android:layout_marginRight="10dp"
            android:layout_alignParentRight="true"
            android:layout_centerVertical="true"/>
    </RelativeLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

================================================
FILE: app/src/main/res/layout/activity_video.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ui.VideoActivity">

    <com.youth.banner.Banner
        android:id="@+id/banner"
        android:layout_width="match_parent"
        android:layout_height="200dp"
        app:banner_infinite_loop="false"
        app:layout_constraintTop_toTopOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

================================================
FILE: app/src/main/res/layout/activity_vp2_fragment_recyclerview.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/vp2"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />


    <com.google.android.material.appbar.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <com.google.android.material.appbar.CollapsingToolbarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layout_scrollFlags="scroll|exitUntilCollapsed"
            app:titleEnabled="false">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="180dp"
                android:orientation="vertical">

                <com.youth.banner.Banner
                    android:id="@+id/banner"
                    android:layout_width="match_parent"
                    android:layout_height="180dp"/>

            </LinearLayout>

            <androidx.appcompat.widget.Toolbar
                android:layout_width="match_parent"
                android:layout_height="40dp"
                app:layout_collapseMode="pin">

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="match_parent"
                    android:layout_centerVertical="true"
                    android:layout_gravity="center_vertical|center_horizontal"
                    android:gravity="center_vertical"
                    android:text="Banner"
                    android:textColor="#fff"
                    android:textStyle="bold"
                    android:textSize="20sp" />
            </androidx.appcompat.widget.Toolbar>
        </com.google.android.material.appbar.CollapsingToolbarLayout>

        <com.google.android.material.tabs.TabLayout
            android:id="@+id/tab_layout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="#fff"
            app:tabSelectedTextColor="@color/colorPrimary"
            app:tabIndicatorColor="@color/colorPrimary"/>
    </com.google.android.material.appbar.AppBarLayout>

</androidx.coordinatorlayout.widget.CoordinatorLayout>

================================================
FILE: app/src/main/res/layout/banner.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <com.youth.banner.Banner
        android:id="@+id/banner"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:layout_margin="10dp"/>
</LinearLayout>


================================================
FILE: app/src/main/res/layout/banner_image.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/image"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:scaleType="centerCrop"/>

================================================
FILE: app/src/main/res/layout/banner_image_title.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/image"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="centerCrop" />

    <TextView
        android:id="@+id/bannerTitle"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#66000000"
        android:ellipsize="marquee"
        android:focusable="true"
        android:focusableInTouchMode="true"
        android:gravity="center_vertical"
        android:padding="10dp"
        android:singleLine="true"
        android:textColor="#ffffff"
        android:layout_alignParentBottom="true"/>
</RelativeLayout>

================================================
FILE: app/src/main/res/layout/banner_image_title_num.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/image"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="centerCrop" />

    <LinearLayout
        android:id="@+id/titleView"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:layout_alignParentBottom="true"
        android:background="#44000000"
        android:orientation="horizontal"
        android:padding="5dp">

        <TextView
            android:id="@+id/bannerTitle"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_weight="1000"
            android:ellipsize="marquee"
            android:focusable="true"
            android:focusableInTouchMode="true"
            android:gravity="center_vertical"
            android:paddingLeft="10dp"
            android:singleLine="true"
            android:textColor="#ffffff" />

        <TextView
            android:id="@+id/numIndicator"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:gravity="center_vertical"
            android:text="1/1"
            android:textColor="#ffffff" />
    </LinearLayout>
</RelativeLayout>

================================================
FILE: app/src/main/res/layout/banner_title.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <TextView
        android:id="@+id/bannerTitle"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:textColor="#ffffff"
        android:textSize="25dp"
        android:gravity="center"
        android:background="#5CB85C" />
</RelativeLayout>

================================================
FILE: app/src/main/res/layout/banner_video.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer
        android:id="@+id/player"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</FrameLayout>

================================================
FILE: app/src/main/res/layout/item.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:id="@+id/card_view"
    android:layout_width="match_parent"
    android:layout_height="120dp"
    android:layout_gravity="center"
    android:layout_marginLeft="5dp"
    android:layout_marginRight="5dp"
    android:foreground="?android:attr/selectableItemBackground"
    card_view:cardCornerRadius="4dp"
    card_view:cardElevation="2dp"
    card_view:cardUseCompatPadding="true"
    card_view:cardBackgroundColor="@color/main_color">

</androidx.cardview.widget.CardView>

================================================
FILE: app/src/main/res/layout/test.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/ll_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="10dp">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="测试"
        android:textColor="@color/colorPrimary"
        android:textSize="20dp" />

</LinearLayout>


================================================
FILE: app/src/main/res/layout/top_line_item2.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:id="@+id/message"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:lines="1"
        android:text="实现1号店热点效果"
        android:textColor="#444444"
        android:layout_marginBottom="10dp"
        android:textSize="14sp" />
    <TextView
        android:id="@+id/source"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:lines="1"
        android:layout_below="@id/message"
        android:layout_marginRight="10dp"
        android:textColor="@color/main_color"
        android:background="@drawable/green"
        android:textSize="10dp"
        android:text="1号店"/>
    <TextView
        android:id="@+id/time"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:lines="1"
        android:textSize="13sp"
        android:layout_toRightOf="@id/source"
        android:layout_below="@id/message"
        android:text="2020年1月23日"/>
</RelativeLayout>


================================================
FILE: app/src/main/res/values/arrays.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <array name="url">
        <item>http://ww4.sinaimg.cn/large/006uZZy8jw1faic1xjab4j30ci08cjrv.jpg</item>
        <item>http://ww4.sinaimg.cn/large/006uZZy8jw1faic21363tj30ci08ct96.jpg</item>
        <item>http://ww4.sinaimg.cn/large/006uZZy8jw1faic259ohaj30ci08c74r.jpg</item>
        <item>http://ww4.sinaimg.cn/large/006uZZy8jw1faic2b16zuj30ci08cwf4.jpg</item>
        <item>http://ww4.sinaimg.cn/large/006uZZy8jw1faic2e7vsaj30ci08cglz.jpg</item>
    </array>

    <array name="url1">
        <item>http://img.zcool.cn/community/01700557a7f42f0000018c1bd6eb23.jpg</item>
    </array>
    <array name="url2">
        <item>http://img.zcool.cn/community/01d28457d621800000018c1bb7877e.jpg</item>
        <item>http://img.zcool.cn/community/01ae5656e1427f6ac72531cb72bac5.jpg</item>
    </array>
    <array name="url4">
        <item>http://img.zcool.cn/community/01b72057a7e0790000018c1bf4fce0.png</item>
        <item>http://img.zcool.cn/community/01fca557a7f5f90000012e7e9feea8.jpg</item>
        <item>http://img.zcool.cn/community/01996b57a7f6020000018c1bedef97.jpg</item>
        <item>http://img.zcool.cn/community/01700557a7f42f0000018c1bd6eb23.jpg</item>
    </array>
    <!-- http://588ku.com/image/daitengmandelitizi.html -->
    <array name="test_num_url">
        <item>http://bpic.588ku.com/element_origin_min_pic/00/00/05/115732f19cc0079.jpg</item>
        <item>http://bpic.588ku.com/element_origin_min_pic/00/00/05/115732f1ac12d1d.jpg</item>
        <item>http://bpic.588ku.com/element_origin_min_pic/00/00/05/115732f1bad97d1.jpg</item>
        <item>http://bpic.588ku.com/element_origin_min_pic/00/00/05/115732f1c83c228.jpg</item>
        <item>http://bpic.588ku.com/element_origin_min_pic/00/00/05/115732f1d53e3dd.jpg</item>
        <item>http://bpic.588ku.com/element_origin_min_pic/00/00/05/115732f1e37fea9.jpg</item>
        <item>http://bpic.588ku.com/element_origin_min_pic/00/00/05/115732f1ef4d709.jpg</item>
        <item>http://bpic.588ku.com/element_origin_min_pic/00/00/05/115732f20b3ea10.jpg</item>
        <item>http://bpic.588ku.com/element_origin_min_pic/00/00/05/115732f21927f8d.jpg</item>
    </array>
    <array name="title">
        <item>51巅峰钜惠</item>
        <item>十大星级品牌联盟,全场2折起</item>
        <item>生命不是要超越别人,而是要超越自己。</item>
        <item>己所不欲,勿施于人。——孔子</item>
        <item>嗨购5折不要停</item>
    </array>
    <array name="demo_list">
        <item>banner动画预览</item>
        <item>banner内置样式预览</item>
        <item>banner指示器位置设置预览</item>
        <item>banner一些自定义样式方法预览</item>
        <item>banner加载本地图片</item>
        <item>banner自定义布局文件(这里通过修改ViewPager举一反三吧)</item>
        <item>!!banner更多用法请看文档,这里就不一一列举了!</item>
    </array>
    <array name="anim">
        <item>Default</item>
        <item>Accordion</item>
        <item>BackgroundToForeground</item>
        <item>ForegroundToBackground</item>
        <item>CubeIn</item>
        <item>CubeOut</item>
        <item>DepthPage</item>
        <item>FlipHorizontal</item>
        <item>FlipVertical</item>
        <item>RotateDown</item>
        <item>RotateUp</item>
        <item>ScaleInOut</item>
        <item>Stack</item>
        <item>Tablet</item>
        <item>ZoomIn</item>
        <item>ZoomOut</item>
        <item>ZoomOutSlide</item>
    </array>
    <string-array name="style">
        <item>NOT_INDICATOR</item>
        <item>CIRCLE_INDICATOR</item>
        <item>NUM_INDICATOR</item>
        <item>NUM_INDICATOR_TITLE</item>
        <item>CIRCLE_INDICATOR_TITLE</item>
        <item>CIRCLE_INDICATOR_TITLE_INSIDE</item>
    </string-array>
    <string-array name="indicator">
        <item>LEFT</item>
        <item>CENTER</item>
        <item>RIGHT</item>
    </string-array>
</resources>

================================================
FILE: app/src/main/res/values/colors.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">@color/main_color</color>
    <color name="colorPrimaryDark">@color/main_color</color>
    <color name="colorAccent">@color/main_color</color>

    <color name="textColor">#BDBDBD</color>

    <color name="main_color">#5CB85C</color>

</resources>


================================================
FILE: app/src/main/res/values/dimens.xml
================================================
<resources>
    <!-- Default screen margins, per the Android Design guidelines. -->
    <dimen name="activity_horizontal_margin">16dp</dimen>
    <dimen name="activity_vertical_margin">16dp</dimen>
</resources>


================================================
FILE: app/src/main/res/values/strings.xml
================================================
<resources>
    <string name="app_name">Banner</string>

</resources>


================================================
FILE: app/src/main/res/values/styles.xml
================================================
<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

</resources>


================================================
FILE: app/src/main/res/values-w820dp/dimens.xml
================================================
<resources>
    <!-- Example customization of dimensions originally defined in res/values/dimens.xml
         (such as screen margins) for screens with more than 820dp of available width. This
         would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
    <dimen name="activity_horizontal_margin">64dp</dimen>
</resources>


================================================
FILE: banner/.gitignore
================================================
/build


================================================
FILE: banner/build.gradle
================================================
apply plugin: 'com.android.library'
apply plugin: 'maven-publish'
apply plugin: 'signing'

version = '2.2.3'

android {
    compileSdk 33

    defaultConfig {
        minSdk 14
        targetSdk 33
        versionCode 202003
        versionName version
        consumerProguardFiles 'proguard-rules.pro'
    }

    lintOptions {
        abortOnError false
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {
    implementation "androidx.viewpager2:viewpager2:1.1.0-beta02"
}

task androidSourcesJar(type: Jar) {
    archiveClassifier.set("sources")
    from android.sourceSets.main.java.source
    exclude "**/R.class"
    exclude "**/BuildConfig.class"
}

publishing {
    publications {
        release(MavenPublication) {
            // group id,发布后引用的依赖的 group id
            groupId 'io.github.youth5201314'
            // 发布后引用的依赖的 artifact id
            artifactId 'banner'
            // 发布的版本
            version version
            // 发布的 arr 的文件和源码文件
            artifact("$buildDir/outputs/aar/${project.getName()}-release.aar")
            artifact androidSourcesJar
            pom {
                // 构件名称,可以自定义
                name = 'banner'
                // 构件描述
                description = 'Android Banner 2.0 全新轮播控件,采用viewpager2为基础控件,支持AndroidX'
                // 构件主页
                url = 'https://github.com/youth5201314/banner'
                // 许可证名称和地址
                licenses {
                    license {
                        name = 'The Apache License, Version 2.0'
                        url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
                    }
                }
                // 开发者信息
                developers {
                    developer {
                        name = '春'
                        email = '1028729086@qq.com'
                    }
                }
                // 版本控制仓库地址
                scm {
                    url = 'https://github.com/youth5201314/banner'
                    connection = 'scm:git:github.com/youth5201314/banner.git'
                    developerConnection = 'scm:git:ssh://git@github.com/youth5201314/banner.git'
                }
            }
        }
    }
    repositories {
        maven {
            // 发布的位置,这里根据发布的版本区分了 SNAPSHOT 和最终版本两种情况
            def releasesRepoUrl = "https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/"
            def snapshotsRepoUrl = "https://s01.oss.sonatype.org/content/repositories/snapshots/"
            url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
            credentials {
                // 这里就是之前在 issues.sonatype.org 注册的账号
                username sonatypeUsername
                password sonatypePassword
            }
        }
    }
}

signing {
    sign publishing.publications
}



================================================
FILE: banner/proguard-rules.pro
================================================
-dontwarn androidx.viewpager2.**
-keep class androidx.viewpager2.** {*;}
-dontwarn androidx.recyclerview.widget.RecyclerView
-keep class androidx.recyclerview.widget.RecyclerView{*;}
-dontwarn com.youth.banner.**
-keep class com.youth.banner.** {*;}



================================================
FILE: banner/src/main/AndroidManifest.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.youth.banner">



</manifest>


================================================
FILE: banner/src/main/java/com/youth/banner/Banner.java
================================================
package com.youth.banner;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.os.Build;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.FrameLayout;

import androidx.annotation.ColorInt;
import androidx.annotation.ColorRes;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.core.content.ContextCompat;
import androidx.lifecycle.LifecycleOwner;
import androidx.recyclerview.widget.RecyclerView;
import androidx.viewpager.widget.ViewPager;
import androidx.viewpager2.widget.CompositePageTransformer;
import androidx.viewpager2.widget.MarginPageTransformer;
import androidx.viewpager2.widget.ViewPager2;

import com.youth.banner.adapter.BannerAdapter;
import com.youth.banner.config.BannerConfig;
import com.youth.banner.config.IndicatorConfig;
import com.youth.banner.indicator.Indicator;
import com.youth.banner.listener.OnBannerListener;
import com.youth.banner.listener.OnPageChangeListener;
import com.youth.banner.transformer.MZScaleInTransformer;
import com.youth.banner.transformer.ScaleInTransformer;
import com.youth.banner.util.BannerLifecycleObserverAdapter;
import com.youth.banner.util.BannerUtils;
import com.youth.banner.util.BannerLifecycleObserver;
import com.youth.banner.util.LogUtils;
import com.youth.banner.util.ScrollSpeedManger;

import java.lang.annotation.Retention;
import java.lang.ref.WeakReference;
import java.util.List;

import static java.lang.annotation.RetentionPolicy.SOURCE;


public class Banner<T, BA extends BannerAdapter<T, ? extends RecyclerView.ViewHolder>> extends FrameLayout implements BannerLifecycleObserver {
    public static final int INVALID_VALUE = -1;
    private ViewPager2 mViewPager2;
    private AutoLoopTask mLoopTask;
    private OnPageChangeListener mOnPageChangeListener;
    private BA mAdapter;
    private Indicator mIndicator;
    private CompositePageTransformer mCompositePageTransformer;
    private BannerOnPageChangeCallback mPageChangeCallback;

    // 是否允许无限轮播(即首尾直接切换)
    private boolean mIsInfiniteLoop = BannerConfig.IS_INFINITE_LOOP;
    // 是否自动轮播
    private boolean mIsAutoLoop = BannerConfig.IS_AUTO_LOOP;
    // 轮播切换间隔时间
    private long mLoopTime = BannerConfig.LOOP_TIME;
    // 轮播切换时间
    private int mScrollTime = BannerConfig.SCROLL_TIME;
    // 轮播开始位置
    private int mStartPosition = 1;
    // banner圆角半径,默认没有圆角
    private float mBannerRadius = 0;
    // banner圆角方向,如果一个都不设置,默认四个角全部圆角
    private boolean mRoundTopLeft, mRoundTopRight, mRoundBottomLeft, mRoundBottomRight;

    // 指示器相关配置
    private int normalWidth = BannerConfig.INDICATOR_NORMAL_WIDTH;
    private int selectedWidth = BannerConfig.INDICATOR_SELECTED_WIDTH;
    private int normalColor = BannerConfig.INDICATOR_NORMAL_COLOR;
    private int selectedColor = BannerConfig.INDICATOR_SELECTED_COLOR;
    private int indicatorGravity = IndicatorConfig.Direction.CENTER;
    private int indicatorSpace;
    private int indicatorMargin;
    private int indicatorMarginLeft;
    private int indicatorMarginTop;
    private int indicatorMarginRight;
    private int indicatorMarginBottom;
    private int indicatorHeight = BannerConfig.INDICATOR_HEIGHT;
    private int indicatorRadius = BannerConfig.INDICATOR_RADIUS;

    public static final int HORIZONTAL = 0;
    public static final int VERTICAL = 1;
    private int mOrientation = HORIZONTAL;

    // 滑动距离范围
    private int mTouchSlop;
    // 记录触摸的位置(主要用于解决事件冲突问题)
    private float mStartX, mStartY;
    // 记录viewpager2是否被拖动
    private boolean mIsViewPager2Drag;
    // 是否要拦截事件
    private boolean isIntercept = true;

    //绘制圆角视图
    private Paint mRoundPaint;
    private Paint mImagePaint;

    @Retention(SOURCE)
    @IntDef( {HORIZONTAL, VERTICAL})
    public @interface Orientation {
    }

    public Banner(Context context) {
        this(context, null);
    }

    public Banner(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public Banner(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
        initTypedArray(context, attrs);
    }

    private void init(Context context) {
        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop() / 2;
        mCompositePageTransformer = new CompositePageTransformer();
        mPageChangeCallback = new BannerOnPageChangeCallback();
        mLoopTask = new AutoLoopTask(this);
        mViewPager2 = new ViewPager2(context);
        mViewPager2.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
        mViewPager2.setOffscreenPageLimit(2);
        mViewPager2.registerOnPageChangeCallback(mPageChangeCallback);
        mViewPager2.setPageTransformer(mCompositePageTransformer);
        ScrollSpeedManger.reflectLayoutManager(this);
        addView(mViewPager2);

        mRoundPaint = new Paint();
        mRoundPaint.setColor(Color.WHITE);
        mRoundPaint.setAntiAlias(true);
        mRoundPaint.setStyle(Paint.Style.FILL);
        mRoundPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
        mImagePaint = new Paint();
        mImagePaint.setXfermode(null);
    }

    private void initTypedArray(Context context, AttributeSet attrs) {
        if (attrs != null) {
            TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Banner);
            mBannerRadius = a.getDimensionPixelSize(R.styleable.Banner_banner_radius, 0);
            mLoopTime = a.getInt(R.styleable.Banner_banner_loop_time, BannerConfig.LOOP_TIME);
            mIsAutoLoop = a.getBoolean(R.styleable.Banner_banner_auto_loop, BannerConfig.IS_AUTO_LOOP);
            mIsInfiniteLoop = a.getBoolean(R.styleable.Banner_banner_infinite_loop, BannerConfig.IS_INFINITE_LOOP);
            normalWidth = a.getDimensionPixelSize(R.styleable.Banner_banner_indicator_normal_width, BannerConfig.INDICATOR_NORMAL_WIDTH);
            selectedWidth = a.getDimensionPixelSize(R.styleable.Banner_banner_indicator_selected_width, BannerConfig.INDICATOR_SELECTED_WIDTH);
            normalColor = a.getColor(R.styleable.Banner_banner_indicator_normal_color, BannerConfig.INDICATOR_NORMAL_COLOR);
            selectedColor = a.getColor(R.styleable.Banner_banner_indicator_selected_color, BannerConfig.INDICATOR_SELECTED_COLOR);
            indicatorGravity = a.getInt(R.styleable.Banner_banner_indicator_gravity, IndicatorConfig.Direction.CENTER);
            indicatorSpace = a.getDimensionPixelSize(R.styleable.Banner_banner_indicator_space, 0);
            indicatorMargin = a.getDimensionPixelSize(R.styleable.Banner_banner_indicator_margin, 0);
            indicatorMarginLeft = a.getDimensionPixelSize(R.styleable.Banner_banner_indicator_marginLeft, 0);
            indicatorMarginTop = a.getDimensionPixelSize(R.styleable.Banner_banner_indicator_marginTop, 0);
            indicatorMarginRight = a.getDimensionPixelSize(R.styleable.Banner_banner_indicator_marginRight, 0);
            indicatorMarginBottom = a.getDimensionPixelSize(R.styleable.Banner_banner_indicator_marginBottom, 0);
            indicatorHeight = a.getDimensionPixelSize(R.styleable.Banner_banner_indicator_height, BannerConfig.INDICATOR_HEIGHT);
            indicatorRadius = a.getDimensionPixelSize(R.styleable.Banner_banner_indicator_radius, BannerConfig.INDICATOR_RADIUS);
            mOrientation = a.getInt(R.styleable.Banner_banner_orientation, HORIZONTAL);
            mRoundTopLeft = a.getBoolean(R.styleable.Banner_banner_round_top_left, false);
            mRoundTopRight = a.getBoolean(R.styleable.Banner_banner_round_top_right, false);
            mRoundBottomLeft = a.getBoolean(R.styleable.Banner_banner_round_bottom_left, false);
            mRoundBottomRight = a.getBoolean(R.styleable.Banner_banner_round_bottom_right, false);
            a.recycle();
        }
        setOrientation(mOrientation);
        setInfiniteLoop();
    }

    private void initIndicatorAttr() {
        if (indicatorMargin != 0) {
            setIndicatorMargins(new IndicatorConfig.Margins(indicatorMargin));
        } else if (indicatorMarginLeft != 0
                || indicatorMarginTop != 0
                || indicatorMarginRight != 0
                || indicatorMarginBottom != 0) {
            setIndicatorMargins(new IndicatorConfig.Margins(
                    indicatorMarginLeft,
                    indicatorMarginTop,
                    indicatorMarginRight,
                    indicatorMarginBottom));
        }
        if (indicatorSpace > 0) {
            setIndicatorSpace(indicatorSpace);
        }
        if (indicatorGravity != IndicatorConfig.Direction.CENTER) {
            setIndicatorGravity(indicatorGravity);
        }
        if (normalWidth > 0) {
            setIndicatorNormalWidth(normalWidth);
        }
        if (selectedWidth > 0) {
            setIndicatorSelectedWidth(selectedWidth);
        }

        if (indicatorHeight > 0) {
            setIndicatorHeight(indicatorHeight);
        }
        if (indicatorRadius > 0) {
            setIndicatorRadius(indicatorRadius);
        }
        setIndicatorNormalColor(normalColor);
        setIndicatorSelectedColor(selectedColor);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (!getViewPager2().isUserInputEnabled()) {
            return super.dispatchTouchEvent(ev);
        }

        int action = ev.getActionMasked();
        if (action == MotionEvent.ACTION_UP
                || action == MotionEvent.ACTION_CANCEL
                || action == MotionEvent.ACTION_OUTSIDE) {
            start();
        } else if (action == MotionEvent.ACTION_DOWN) {
            stop();
        }
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        if (!getViewPager2().isUserInputEnabled() || !isIntercept) {
            return super.onInterceptTouchEvent(event);
        }
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mStartX = event.getX();
                mStartY = event.getY();
                getParent().requestDisallowInterceptTouchEvent(true);
                break;
            case MotionEvent.ACTION_MOVE:
                float endX = event.getX();
                float endY = event.getY();
                float distanceX = Math.abs(endX - mStartX);
                float distanceY = Math.abs(endY - mStartY);
                if (getViewPager2().getOrientation() == HORIZONTAL) {
                    mIsViewPager2Drag = distanceX > mTouchSlop && distanceX > distanceY;
                } else {
                    mIsViewPager2Drag = distanceY > mTouchSlop && distanceY > distanceX;
                }
                getParent().requestDisallowInterceptTouchEvent(mIsViewPager2Drag);
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                getParent().requestDisallowInterceptTouchEvent(false);
                break;
        }
        return super.onInterceptTouchEvent(event);
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        if (mBannerRadius > 0) {
            canvas.saveLayer(new RectF(0, 0, canvas.getWidth(), canvas.getHeight()), mImagePaint, Canvas.ALL_SAVE_FLAG);
            super.dispatchDraw(canvas);
            //绘制外圆环边框圆环
            //默认四个角都设置
            if (!mRoundTopRight && !mRoundTopLeft && !mRoundBottomRight && !mRoundBottomLeft) {
                drawTopLeft(canvas);
                drawTopRight(canvas);
                drawBottomLeft(canvas);
                drawBottomRight(canvas);
                canvas.restore();
                return;
            }
            if (mRoundTopLeft) {
                drawTopLeft(canvas);
            }
            if (mRoundTopRight) {
                drawTopRight(canvas);
            }
            if (mRoundBottomLeft) {
                drawBottomLeft(canvas);
            }
            if (mRoundBottomRight) {
                drawBottomRight(canvas);
            }
            canvas.restore();
        } else {
            super.dispatchDraw(canvas);
        }
    }

    private void drawTopLeft(Canvas canvas) {
        Path path = new Path();
        path.moveTo(0, mBannerRadius);
        path.lineTo(0, 0);
        path.lineTo(mBannerRadius, 0);
        path.arcTo(new RectF(0, 0, mBannerRadius * 2, mBannerRadius * 2), -90, -90);
        path.close();
        canvas.drawPath(path, mRoundPaint);
    }

    private void drawTopRight(Canvas canvas) {
        int width = getWidth();
        Path path = new Path();
        path.moveTo(width - mBannerRadius, 0);
        path.lineTo(width, 0);
        path.lineTo(width, mBannerRadius);
        path.arcTo(new RectF(width - 2 * mBannerRadius, 0, width, mBannerRadius * 2), 0, -90);
        path.close();
        canvas.drawPath(path, mRoundPaint);
    }

    private void drawBottomLeft(Canvas canvas) {
        int height = getHeight();
        Path path = new Path();
        path.moveTo(0, height - mBannerRadius);
        path.lineTo(0, height);
        path.lineTo(mBannerRadius, height);
        path.arcTo(new RectF(0, height - 2 * mBannerRadius, mBannerRadius * 2, height), 90, 90);
        path.close();
        canvas.drawPath(path, mRoundPaint);
    }

    private void drawBottomRight(Canvas canvas) {
        int height = getHeight();
        int width = getWidth();
        Path path = new Path();
        path.moveTo(width - mBannerRadius, height);
        path.lineTo(width, height);
        path.lineTo(width, height - mBannerRadius);
        path.arcTo(new RectF(width - 2 * mBannerRadius, height - 2 * mBannerRadius, width, height), 0, 90);
        path.close();
        canvas.drawPath(path, mRoundPaint);
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        start();
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        stop();
    }

    class BannerOnPageChangeCallback extends ViewPager2.OnPageChangeCallback {
        private int mTempPosition = INVALID_VALUE;
        private boolean isScrolled;

        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
            int realPosition = BannerUtils.getRealPosition(isInfiniteLoop(), position, getRealCount());
            if (mOnPageChangeListener != null && realPosition == getCurrentItem() - 1) {
                mOnPageChangeListener.onPageScrolled(realPosition, positionOffset, positionOffsetPixels);
            }
            if (getIndicator() != null && realPosition == getCurrentItem() - 1) {
                getIndicator().onPageScrolled(realPosition, positionOffset, positionOffsetPixels);
            }
        }

        @Override
        public void onPageSelected(int position) {
            if (isScrolled) {
                mTempPosition = position;
                int realPosition = BannerUtils.getRealPosition(isInfiniteLoop(), position, getRealCount());
                if (mOnPageChangeListener != null) {
                    mOnPageChangeListener.onPageSelected(realPosition);
                }
                if (getIndicator() != null) {
                    getIndicator().onPageSelected(realPosition);
                }
            }
        }

        @Override
        public void onPageScrollStateChanged(int state) {
            //手势滑动中,代码执行滑动中
            if (state == ViewPager2.SCROLL_STATE_DRAGGING || state == ViewPager2.SCROLL_STATE_SETTLING) {
                isScrolled = true;
            } else if (state == ViewPager2.SCROLL_STATE_IDLE) {
                //滑动闲置或滑动结束
                isScrolled = false;
                if (mTempPosition != INVALID_VALUE && mIsInfiniteLoop) {
                    if (mTempPosition == 0) {
                        setCurrentItem(getRealCount(), false);
                    } else if (mTempPosition == getItemCount() - 1) {
                        setCurrentItem(1, false);
                    }
                }
            }
            if (mOnPageChangeListener != null) {
                mOnPageChangeListener.onPageScrollStateChanged(state);
            }
            if (getIndicator() != null) {
                getIndicator().onPageScrollStateChanged(state);
            }
        }

    }

    static class AutoLoopTask implements Runnable {
        private final WeakReference<Banner> reference;

        AutoLoopTask(Banner banner) {
            this.reference = new WeakReference<>(banner);
        }

        @Override
        public void run() {
            Banner banner = reference.get();
            if (banner != null && banner.mIsAutoLoop) {
                int count = banner.getItemCount();
                if (count == 0) {
                    return;
                }
                int next = (banner.getCurrentItem() + 1) % count;
                banner.setCurrentItem(next);
                banner.postDelayed(banner.mLoopTask, banner.mLoopTime);
            }
        }
    }

    private final RecyclerView.AdapterDataObserver mAdapterDataObserver = new RecyclerView.AdapterDataObserver() {
        @Override
        public void onChanged() {
            if (getItemCount() <= 1) {
                stop();
            } else {
                start();
            }
            setIndicatorPageChange();
        }
    };

    private void initIndicator() {
        if (getIndicator() == null || getAdapter() == null) {
            return;
        }
        if (getIndicator().getIndicatorConfig().isAttachToBanner()) {
            removeIndicator();
            addView(getIndicator().getIndicatorView());
        }
        initIndicatorAttr();
        setIndicatorPageChange();
    }

    private void setInfiniteLoop() {
        // 当不支持无限循环时,要关闭自动轮播
        if (!isInfiniteLoop()) {
            isAutoLoop(false);
        }
        setStartPosition(isInfiniteLoop() ? mStartPosition : 0);
    }

    private void setRecyclerViewPadding(int itemPadding) {
        setRecyclerViewPadding(itemPadding, itemPadding);
    }

    private void setRecyclerViewPadding(int leftItemPadding, int rightItemPadding) {
        RecyclerView recyclerView = (RecyclerView) getViewPager2().getChildAt(0);
        if (getViewPager2().getOrientation() == ViewPager2.ORIENTATION_VERTICAL) {
            recyclerView.setPadding(mViewPager2.getPaddingLeft(), leftItemPadding, mViewPager2.getPaddingRight(), rightItemPadding);
        } else {
            recyclerView.setPadding(leftItemPadding, mViewPager2.getPaddingTop(), rightItemPadding, mViewPager2.getPaddingBottom());
        }
        recyclerView.setClipToPadding(false);
    }


    /**
     * **********************************************************************
     * ------------------------ 对外公开API ---------------------------------*
     * **********************************************************************
     */

    public int getCurrentItem() {
        return getViewPager2().getCurrentItem();
    }

    public int getItemCount() {
        if (getAdapter() != null) {
            return getAdapter().getItemCount();
        }
        return 0;

    }

    public int getScrollTime() {
        return mScrollTime;
    }

    public boolean isInfiniteLoop() {
        return mIsInfiniteLoop;
    }

    public BannerAdapter getAdapter() {
        return mAdapter;
    }

    public ViewPager2 getViewPager2() {
        return mViewPager2;
    }

    public Indicator getIndicator() {
        return mIndicator;
    }

    public IndicatorConfig getIndicatorConfig() {
        if (getIndicator() != null) {
            return getIndicator().getIndicatorConfig();
        }
        return null;
    }

    /**
     * 返回banner真实总数
     */
    public int getRealCount() {
        if (getAdapter() != null) {
            return getAdapter().getRealCount();
        }
        return 0;

    }

    //-----------------------------------------------------------------------------------------

    /**
     * 是否要拦截事件
     * @param intercept
     * @return
     */
    public Banner setIntercept(boolean intercept) {
        isIntercept = intercept;
        return this;
    }

    /**
     * 跳转到指定位置(最好在设置了数据后在调用,不然没有意义)
     * @param position
     * @return
     */
    public Banner setCurrentItem(int position) {
        return setCurrentItem(position, true);
    }

    /**
     * 跳转到指定位置(最好在设置了数据后在调用,不然没有意义)
     * @param position
     * @param smoothScroll
     * @return
     */
    public Banner setCurrentItem(int position, boolean smoothScroll) {
        getViewPager2().setCurrentItem(position, smoothScroll);
        return this;
    }

    public Banner setIndicatorPageChange() {
        if (getIndicator() != null) {
            int realPosition = BannerUtils.getRealPosition(isInfiniteLoop(), getCurrentItem(), getRealCount());
            getIndicator().onPageChanged(getRealCount(), realPosition);
        }
        return this;
    }

    public Banner removeIndicator() {
        if (getIndicator() != null) {
            removeView(getIndicator().getIndicatorView());
        }
        return this;
    }


    /**
     * 设置开始的位置 (需要在setAdapter或者setDatas之前调用才有效哦)
     */
    public Banner setStartPosition(int mStartPosition) {
        this.mStartPosition = mStartPosition;
        return this;
    }

    public int getStartPosition() {
        return mStartPosition;
    }

    /**
     * 禁止手动滑动
     *
     * @param enabled true 允许,false 禁止
     */
    public Banner setUserInputEnabled(boolean enabled) {
        getViewPager2().setUserInputEnabled(enabled);
        return this;
    }

    /**
     * 添加PageTransformer,可以组合效果
     * {@link ViewPager2.PageTransformer}
     * 如果找不到请导入implementation "androidx.viewpager2:viewpager2:1.0.0"
     */
    public Banner addPageTransformer(@Nullable ViewPager2.PageTransformer transformer) {
        mCompositePageTransformer.addTransformer(transformer);
        return this;
    }

    /**
     * 设置PageTransformer,和addPageTransformer不同,这个只支持一种transformer
     */
    public Banner setPageTransformer(@Nullable ViewPager2.PageTransformer transformer) {
        getViewPager2().setPageTransformer(transformer);
        return this;
    }

    public Banner removeTransformer(ViewPager2.PageTransformer transformer) {
        mCompositePageTransformer.removeTransformer(transformer);
        return this;
    }

    /**
     * 添加 ItemDecoration
     */
    public Banner addItemDecoration(RecyclerView.ItemDecoration decor) {
        getViewPager2().addItemDecoration(decor);
        return this;
    }

    public Banner addItemDecoration(RecyclerView.ItemDecoration decor, int index) {
        getViewPager2().addItemDecoration(decor, index);
        return this;
    }

    /**
     * 是否允许自动轮播
     *
     * @param isAutoLoop ture 允许,false 不允许
     */
    public Banner isAutoLoop(boolean isAutoLoop) {
        this.mIsAutoLoop = isAutoLoop;
        return this;
    }


    /**
     * 设置轮播间隔时间
     *
     * @param loopTime 时间(毫秒)
     */
    public Banner setLoopTime(long loopTime) {
        this.mLoopTime = loopTime;
        return this;
    }

    /**
     * 设置轮播滑动过程的时间
     */
    public Banner setScrollTime(int scrollTime) {
        this.mScrollTime = scrollTime;
        return this;
    }

    /**
     * 开始轮播
     */
    public Banner start() {
        if (mIsAutoLoop) {
            stop();
            postDelayed(mLoopTask, mLoopTime);
        }
        return this;
    }

    /**
     * 停止轮播
     */
    public Banner stop() {
        if (mIsAutoLoop) {
            removeCallbacks(mLoopTask);
        }
        return this;
    }

    /**
     * 移除一些引用
     */
    public void destroy() {
        if (getViewPager2() != null && mPageChangeCallback != null) {
            getViewPager2().unregisterOnPageChangeCallback(mPageChangeCallback);
            mPageChangeCallback = null;
        }
        stop();
    }

    /**
     * 设置banner的适配器
     */
    public Banner setAdapter(BA adapter) {
        if (adapter == null) {
            throw new NullPointerException(getContext().getString(R.string.banner_adapter_null_error));
        }
        this.mAdapter = adapter;
        if (!isInfiniteLoop()) {
            getAdapter().setIncreaseCount(0);
        }
        getAdapter().registerAdapterDataObserver(mAdapterDataObserver);
        mViewPager2.setAdapter(adapter);
        setCurrentItem(mStartPosition, false);
        initIndicator();
        return this;
    }

    /**
     * 设置banner的适配器
     * @param adapter
     * @param isInfiniteLoop 是否支持无限循环
     * @return
     */
    public Banner setAdapter(BA adapter,boolean isInfiniteLoop) {
        mIsInfiniteLoop=isInfiniteLoop;
        setInfiniteLoop();
        setAdapter(adapter);
        return this;
    }

    /**
     * 重新设置banner数据,当然你也可以在你adapter中自己操作数据,不要过于局限在这个方法,举一反三哈
     *
     * @param datas 数据集合,当传null或者datas没有数据时,banner会变成空白的,请做好占位UI处理
     */
    public Banner setDatas(List<T> datas) {
        if (getAdapter() != null) {
            getAdapter().setDatas(datas);
            setCurrentItem(mStartPosition, false);
            setIndicatorPageChange();
            start();
        }
        return this;
    }

    /**
     * 设置banner轮播方向
     *
     * @param orientation {@link Orientation}
     */
    public Banner setOrientation(@Orientation int orientation) {
        getViewPager2().setOrientation(orientation);
        return this;
    }

    /**
     * 改变最小滑动距离
     */
    public Banner setTouchSlop(int mTouchSlop) {
        this.mTouchSlop = mTouchSlop;
        return this;
    }

    /**
     * 设置点击事件
     */
    public Banner setOnBannerListener(OnBannerListener<T> listener) {
        if (getAdapter() != null) {
            getAdapter().setOnBannerListener(listener);
        }
        return this;
    }

    /**
     * 添加viewpager切换事件
     * <p>
     * 在viewpager2中切换事件{@link ViewPager2.OnPageChangeCallback}是一个抽象类,
     * 为了方便使用习惯这里用的是和viewpager一样的{@link ViewPager.OnPageChangeListener}接口
     * </p>
     */
    public Banner addOnPageChangeListener(OnPageChangeListener pageListener) {
        this.mOnPageChangeListener = pageListener;
        return this;
    }

    /**
     * 设置banner圆角
     * <p>
     * 默认没有圆角,需要取消圆角把半径设置为0即可
     *
     * @param radius 圆角半径
     */
    public Banner setBannerRound(float radius) {
        mBannerRadius = radius;
        return this;
    }

    /**
     * 设置banner圆角(第二种方式,和上面的方法不要同时使用),只支持5.0以上
     */
    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public Banner setBannerRound2(float radius) {
        BannerUtils.setBannerRound(this, radius);
        return this;
    }

    /**
     * 为banner添加画廊效果
     *
     * @param itemWidth  item左右展示的宽度,单位dp
     * @param pageMargin 页面间距,单位dp
     */
    public Banner setBannerGalleryEffect(int itemWidth, int pageMargin) {
        return setBannerGalleryEffect(itemWidth, pageMargin, .85f);
    }

    /**
     * 为banner添加画廊效果
     *
     * @param leftItemWidth  item左展示的宽度,单位dp
     * @param rightItemWidth item右展示的宽度,单位dp
     * @param pageMargin     页面间距,单位dp
     */
    public Banner setBannerGalleryEffect(int leftItemWidth, int rightItemWidth, int pageMargin) {
        return setBannerGalleryEffect(leftItemWidth,rightItemWidth, pageMargin, .85f);
    }

    /**
     * 为banner添加画廊效果
     *
     * @param itemWidth  item左右展示的宽度,单位dp
     * @param pageMargin 页面间距,单位dp
     * @param scale      缩放[0-1],1代表不缩放
     */
    public Banner setBannerGalleryEffect(int itemWidth, int pageMargin, float scale) {
        return setBannerGalleryEffect(itemWidth, itemWidth, pageMargin, scale);
    }

    /**
     * 为banner添加画廊效果
     *
     * @param leftItemWidth  item左展示的宽度,单位dp
     * @param rightItemWidth item右展示的宽度,单位dp
     * @param pageMargin     页面间距,单位dp
     * @param scale          缩放[0-1],1代表不缩放
     */
    public Banner setBannerGalleryEffect(int leftItemWidth, int rightItemWidth, int pageMargin, float scale) {
        if (pageMargin > 0) {
            addPageTransformer(new MarginPageTransformer(BannerUtils.dp2px(pageMargin)));
        }
        if (scale < 1 && scale > 0) {
            addPageTransformer(new ScaleInTransformer(scale));
        }
        setRecyclerViewPadding(leftItemWidth > 0 ? BannerUtils.dp2px(leftItemWidth + pageMargin) : 0,
                rightItemWidth > 0 ? BannerUtils.dp2px(rightItemWidth + pageMargin) : 0);
        return this;
    }

    /**
     * 为banner添加魅族效果
     *
     * @param itemWidth item左右展示的宽度,单位dp
     */
    public Banner setBannerGalleryMZ(int itemWidth) {
        return setBannerGalleryMZ(itemWidth, .88f);
    }

    /**
     * 为banner添加魅族效果
     *
     * @param itemWidth item左右展示的宽度,单位dp
     * @param scale     缩放[0-1],1代表不缩放
     */
    public Banner setBannerGalleryMZ(int itemWidth, float scale) {
        if (scale < 1 && scale > 0) {
            addPageTransformer(new MZScaleInTransformer(scale));
        }
        setRecyclerViewPadding(BannerUtils.dp2px(itemWidth));
        return this;
    }

    /**
     * **********************************************************************
     * ------------------------ 指示器相关设置 --------------------------------*
     * **********************************************************************
     */

    /**
     * 设置轮播指示器(显示在banner上)
     */
    public Banner setIndicator(Indicator indicator) {
        return setIndicator(indicator, true);
    }

    /**
     * 设置轮播指示器(如果你的指示器写在布局文件中,attachToBanner传false)
     *
     * @param attachToBanner 是否将指示器添加到banner中,false 代表你可以将指示器通过布局放在任何位置
     *                       注意:设置为false后,内置的 setIndicatorGravity()和setIndicatorMargins() 方法将失效。
     *                       想改变可以自己调用系统提供的属性在布局文件中进行设置。具体可以参照demo
     */
    public Banner setIndicator(Indicator indicator, boolean attachToBanner) {
        removeIndicator();
        indicator.getIndicatorConfig().setAttachToBanner(attachToBanner);
        this.mIndicator = indicator;
        initIndicator();
        return this;
    }


    public Banner setIndicatorSelectedColor(@ColorInt int color) {
        if (getIndicatorConfig() != null) {
            getIndicatorConfig().setSelectedColor(color);
        }
        return this;
    }

    public Banner setIndicatorSelectedColorRes(@ColorRes int color) {
        setIndicatorSelectedColor(ContextCompat.getColor(getContext(), color));
        return this;
    }

    public Banner setIndicatorNormalColor(@ColorInt int color) {
        if (getIndicatorConfig() != null) {
            getIndicatorConfig().setNormalColor(color);
        }
        return this;
    }

    public Banner setIndicatorNormalColorRes(@ColorRes int color) {
        setIndicatorNormalColor(ContextCompat.getColor(getContext(), color));
        return this;
    }

    public Banner setIndicatorGravity(@IndicatorConfig.Direction int gravity) {
        if (getIndicatorConfig() != null && getIndicatorConfig().isAttachToBanner()) {
            getIndicatorConfig().setGravity(gravity);
            getIndicator().getIndicatorView().postInvalidate();
        }
        return this;
    }

    public Banner setIndicatorSpace(int indicatorSpace) {
        if (getIndicatorConfig() != null) {
            getIndicatorConfig().setIndicatorSpace(indicatorSpace);
        }
        return this;
    }

    public Banner setIndicatorMargins(IndicatorConfig.Margins margins) {
        if (getIndicatorConfig() != null && getIndicatorConfig().isAttachToBanner()) {
            getIndicatorConfig().setMargins(margins);
            getIndicator().getIndicatorView().requestLayout();
        }
        return this;
    }

    public Banner setIndicatorWidth(int normalWidth, int selectedWidth) {
        if (getIndicatorConfig() != null) {
            getIndicatorConfig().setNormalWidth(normalWidth);
            getIndicatorConfig().setSelectedWidth(selectedWidth);
        }
        return this;
    }

    public Banner setIndicatorNormalWidth(int normalWidth) {
        if (getIndicatorConfig() != null) {
            getIndicatorConfig().setNormalWidth(normalWidth);
        }
        return this;
    }

    public Banner setIndicatorSelectedWidth(int selectedWidth) {
        if (getIndicatorConfig() != null) {
            getIndicatorConfig().setSelectedWidth(selectedWidth);
        }
        return this;
    }

    public Banner setIndicatorRadius(int indicatorRadius) {
        if (getIndicatorConfig() != null) {
            getIndicatorConfig().setRadius(indicatorRadius);
        }
        return this;
    }

    public Banner setIndicatorHeight(int indicatorHeight) {
        if (getIndicatorConfig() != null) {
            getIndicatorConfig().setHeight(indicatorHeight);
        }
        return this;
    }

    /**
     * **********************************************************************
     * ------------------------ 生命周期控制 --------------------------------*
     * **********************************************************************
     */

    public Banner addBannerLifecycleObserver(LifecycleOwner owner) {
        if (owner != null) {
            owner.getLifecycle().addObserver(new BannerLifecycleObserverAdapter(owner, this));
        }
        return this;
    }

    @Override
    public void onStart(LifecycleOwner owner) {
        start();
    }

    @Override
    public void onStop(LifecycleOwner owner) {
        stop();
    }

    @Override
    public void onDestroy(LifecycleOwner owner) {
        destroy();
    }

}


================================================
FILE: banner/src/main/java/com/youth/banner/adapter/BannerAdapter.java
================================================
package com.youth.banner.adapter;

import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import com.youth.banner.R;
import com.youth.banner.config.BannerConfig;
import com.youth.banner.holder.IViewHolder;
import com.youth.banner.listener.OnBannerListener;
import com.youth.banner.util.BannerUtils;

import java.util.ArrayList;
import java.util.List;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;


public abstract class BannerAdapter<T, VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<VH> implements IViewHolder<T, VH> {
    protected List<T> mDatas = new ArrayList<>();
    private OnBannerListener<T> mOnBannerListener;
    private VH mViewHolder;
    private int mIncreaseCount = BannerConfig.INCREASE_COUNT;

    public BannerAdapter(List<T> datas) {
        setDatas(datas);
    }

    /**
     * 设置实体集合(可以在自己的adapter自定义,不一定非要使用)
     *
     * @param datas
     */
    public void setDatas(List<T> datas) {
        if (datas == null) {
            datas = new ArrayList<>();
        }
        mDatas.clear();
        mDatas.addAll(datas);
        notifyDataSetChanged();
    }

    /**
     * 获取指定的实体(可以在自己的adapter自定义,不一定非要使用)
     *
     * @param position 真实的position
     * @return
     */
    public T getData(int position) {
        if (position > mDatas.size()-1) {
            return null;
        }
        return mDatas.get(position);
    }

    /**
     * 获取指定的实体(可以在自己的adapter自定义,不一定非要使用)
     *
     * @param position 这里传的position不是真实的,获取时转换了一次
     * @return
     */
    public T getRealData(int position) {
        int realPosition = getRealPosition(position);
        if (realPosition > mDatas.size()-1) {
            return null;
        }
        return mDatas.get(realPosition);
    }


    @Override
    public final void onBindViewHolder(@NonNull VH holder, int position) {
        mViewHolder = holder;
        int real = getRealPosition(position);
        T data = mDatas.get(real);
        holder.itemView.setTag(R.id.banner_data_key, data);
        holder.itemView.setTag(R.id.banner_pos_key, real);
        onBindView(holder, mDatas.get(real), real, getRealCount());
        if (mOnBannerListener != null) {
            holder.itemView.setOnClickListener(view -> mOnBannerListener.OnBannerClick(data, real));
        }
    }

    @NonNull
    @Override
    @SuppressWarnings("unchecked")
    public VH onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        VH vh = onCreateHolder(parent, viewType);
        vh.itemView.setOnClickListener(v -> {
            if (mOnBannerListener != null) {
                T data = (T) vh.itemView.getTag(R.id.banner_data_key);
                int real = (int) vh.itemView.getTag(R.id.banner_pos_key);
                mOnBannerListener.OnBannerClick(data, real);
            }
        });
        return vh;
    }

    @Override
    public int getItemCount() {
        return getRealCount() > 1 ? getRealCount() + mIncreaseCount : getRealCount();
    }

    public int getRealCount() {
        return mDatas == null ? 0 : mDatas.size();
    }

    public int getRealPosition(int position) {
        return BannerUtils.getRealPosition(mIncreaseCount == BannerConfig.INCREASE_COUNT, position, getRealCount());
    }

    public void setOnBannerListener(OnBannerListener<T> listener) {
        this.mOnBannerListener = listener;
    }

    public VH getViewHolder() {
        return mViewHolder;
    }

    public void setIncreaseCount(int increaseCount) {
        this.mIncreaseCount = increaseCount;
    }
}

================================================
FILE: banner/src/main/java/com/youth/banner/adapter/BannerImageAdapter.java
================================================
package com.youth.banner.adapter;

import android.view.ViewGroup;
import android.widget.ImageView;

import com.youth.banner.holder.BannerImageHolder;

import java.util.List;

/**
 * 默认实现的图片适配器,图片加载需要自己实现
 */
public abstract class BannerImageAdapter<T> extends BannerAdapter<T, BannerImageHolder> {

    public BannerImageAdapter(List<T> mData) {
        super(mData);
    }

    @Override
    public BannerImageHolder onCreateHolder(ViewGroup parent, int viewType) {
        ImageView imageView = new ImageView(parent.getContext());
        //注意,必须设置为match_parent,这个是viewpager2强制要求的
        ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT);
        imageView.setLayoutParams(params);
        imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
        return new BannerImageHolder(imageView);
    }

}


================================================
FILE: banner/src/main/java/com/youth/banner/config/BannerConfig.java
================================================
package com.youth.banner.config;

import com.youth.banner.util.BannerUtils;

/**
 * 不忘初心
 *
 * ┌───┐   ┌───┬───┬───┬───┐ ┌───┬───┬───┬───┐ ┌───┬───┬───┬───┐ ┌───┬───┬───┐  ┌┐    ┌┐    ┌┐
 * │Esc│   │ F1│ F2│ F3│ F4│ │ F5│ F6│ F7│ F8│ │ F9│F10│F11│F12│ │P/S│S L│P/B│  └┘    └┘    └┘
 * └───┘   └───┴───┴───┴───┘ └───┴───┴───┴───┘ └───┴───┴───┴───┘ └───┴───┴───┘
 * ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐ ┌───┬───┬───┐ ┌───┬───┬───┬───┐
 * │~ `│! 1│@ 2│# 3│$ 4│% 5│^ 6│& 7│* 8│( 9│) 0│_ -│+ =│ BacSp │ │Ins│Hom│PUp│ │N L│ / │ * │ - │
 * ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤ ├───┼───┼───┤ ├───┼───┼───┼───┤
 * │ Tab │ Q │ W │ E │ R │ T │ Y │ U │ I │ O │ P │{ [│} ]│ | \ │ │Del│End│PDn│ │ 7 │ 8 │ 9 │   │
 * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴─────┤ └───┴───┴───┘ ├───┼───┼───┤ + │
 * │ Caps │ A │ S │ D │ F │ G │ H │ J │ K │ L │: ;│" '│ Enter  │               │ 4 │ 5 │ 6 │   │
 * ├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴────────┤     ┌───┐     ├───┼───┼───┼───┤
 * │ Shift  │ Z │ X │ C │ V │ B │ N │ M │< ,│> .│? /│  Shift   │     │ ↑ │     │ 1 │ 2 │ 3 │   │
 * ├─────┬──┴─┬─┴──┬┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤ ┌───┼───┼───┐ ├───┴───┼───┤ E││
 * │ Ctrl│    │Alt │         Space         │ Alt│    │    │Ctrl│ │ ← │ ↓ │ → │ │   0   │ . │←─┘│
 * └─────┴────┴────┴───────────────────────┴────┴────┴────┴────┘ └───┴───┴───┘ └───────┴───┴───┘
 *
 *  @author youth5201314/spring
 *  @date 2020/1/24
 *  banner 配置参数
 */
public class BannerConfig {
    public static final boolean IS_AUTO_LOOP = true;
    public static final boolean IS_INFINITE_LOOP = true;
    public static final int LOOP_TIME = 3000;
    public static final int SCROLL_TIME = 600;
    public static final int INCREASE_COUNT = 2;
    public static final int INDICATOR_NORMAL_COLOR = 0x88ffffff;
    public static final int INDICATOR_SELECTED_COLOR = 0x88000000;
    public static final int INDICATOR_NORMAL_WIDTH = (int) BannerUtils.dp2px(5);
    public static final int INDICATOR_SELECTED_WIDTH = (int) BannerUtils.dp2px(7);
    public static final int INDICATOR_SPACE = (int) BannerUtils.dp2px(5);
    public static final int INDICATOR_MARGIN = (int) BannerUtils.dp2px(5);

    public static final int INDICATOR_HEIGHT = (int) BannerUtils.dp2px(3);
    public static final int INDICATOR_RADIUS = (int) BannerUtils.dp2px(3);

}


================================================
FILE: banner/src/main/java/com/youth/banner/config/IndicatorConfig.java
================================================
package com.youth.banner.config;

import androidx.annotation.ColorInt;
import androidx.annotation.IntDef;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

public class IndicatorConfig {

    private int indicatorSize;
    private int currentPosition;
    private int gravity = Direction.CENTER;
    private int indicatorSpace = BannerConfig.INDICATOR_SPACE;
    private int normalWidth = BannerConfig.INDICATOR_NORMAL_WIDTH;
    private int selectedWidth = BannerConfig.INDICATOR_SELECTED_WIDTH;
    @ColorInt
    private int normalColor = BannerConfig.INDICATOR_NORMAL_COLOR;
    @ColorInt
    private int selectedColor = BannerConfig.INDICATOR_SELECTED_COLOR;

    private int radius = BannerConfig.INDICATOR_RADIUS;
    private int height = BannerConfig.INDICATOR_HEIGHT;

    private Margins margins;

    //是将指示器添加到banner上
    private boolean attachToBanner = true;

    @IntDef({Direction.LEFT, Direction.CENTER, Direction.RIGHT})
    @Retention(RetentionPolicy.SOURCE)
    public @interface Direction {
        int LEFT = 0;
        int CENTER = 1;
        int RIGHT = 2;
    }

    public static class Margins {
        public int leftMargin;
        public int topMargin;
        public int rightMargin;
        public int bottomMargin;

        public Margins() {
            this(BannerConfig.INDICATOR_MARGIN);
        }

        public Margins(int marginSize) {
            this(marginSize, marginSize, marginSize, marginSize);
        }

        public Margins(int leftMargin, int topMargin, int rightMargin, int bottomMargin) {
            this.leftMargin = leftMargin;
            this.topMargin = topMargin;
            this.rightMargin = rightMargin;
            this.bottomMargin = bottomMargin;
        }
    }

    public Margins getMargins() {
        if (margins == null) {
            setMargins(new Margins());
        }
        return margins;
    }

    public IndicatorConfig setMargins(Margins margins) {
        this.margins = margins;
        return this;
    }

    public int getIndicatorSize() {
        return indicatorSize;
    }

    public IndicatorConfig setIndicatorSize(int indicatorSize) {
        this.indicatorSize = indicatorSize;
        return this;
    }

    public int getNormalColor() {
        return normalColor;
    }

    public IndicatorConfig setNormalColor(int normalColor) {
        this.normalColor = normalColor;
        return this;
    }

    public int getSelectedColor() {
        return selectedColor;
    }

    public IndicatorConfig setSelectedColor(int selectedColor) {
        this.selectedColor = selectedColor;
        return this;
    }

    public int getIndicatorSpace() {
        return indicatorSpace;
    }

    public IndicatorConfig setIndicatorSpace(int indicatorSpace) {
        this.indicatorSpace = indicatorSpace;
        return this;
    }

    public int getCurrentPosition() {
        return currentPosition;
    }

    public IndicatorConfig setCurrentPosition(int currentPosition) {
        this.currentPosition = currentPosition;
        return this;
    }

    public int getNormalWidth() {
        return normalWidth;
    }

    public IndicatorConfig setNormalWidth(int normalWidth) {
        this.normalWidth = normalWidth;
        return this;
    }

    public int getSelectedWidth() {
        return selectedWidth;
    }

    public IndicatorConfig setSelectedWidth(int selectedWidth) {
        this.selectedWidth = selectedWidth;
        return this;
    }

    public int getGravity() {
        return gravity;
    }

    public IndicatorConfig setGravity(@Direction int gravity) {
        this.gravity = gravity;
        return this;
    }

    public boolean isAttachToBanner() {
        return attachToBanner;
    }

    public IndicatorConfig setAttachToBanner(boolean attachToBanner) {
        this.attachToBanner = attachToBanner;
        return this;
    }

    public int getRadius() {
        return radius;
    }

    public IndicatorConfig setRadius(int radius) {
        this.radius = radius;
        return this;
    }

    public int getHeight() {
        return height;
    }

    public IndicatorConfig setHeight(int height) {
        this.height = height;
        return this;
    }
}


================================================
FILE: banner/src/main/java/com/youth/banner/holder/BannerImageHolder.java
================================================
package com.youth.banner.holder;

import android.view.View;
import android.widget.ImageView;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

public
class BannerImageHolder extends RecyclerView.ViewHolder {
    public ImageView imageView;

    public BannerImageHolder(@NonNull View view) {
        super(view);
        this.imageView = (ImageView) view;
    }
}


================================================
FILE: banner/src/main/java/com/youth/banner/holder/IViewHolder.java
================================================
package com.youth.banner.holder;

import android.view.ViewGroup;

public interface IViewHolder<T, VH> {

    /**
     * 创建ViewHolder
     *
     * @return XViewHolder
     */
    VH onCreateHolder(ViewGroup parent, int viewType);

    /**
     * 绑定布局数据
     *
     * @param holder   XViewHolder
     * @param data     数据实体
     * @param position 当前位置
     * @param size     总数
     */
    void onBindView(VH holder, T data, int position, int size);

}


================================================
FILE: banner/src/main/java/com/youth/banner/indicator/BaseIndicator.java
================================================
package com.youth.banner.indicator;

import android.content.Context;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.widget.FrameLayout;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.youth.banner.config.IndicatorConfig;
import com.youth.banner.util.LogUtils;

public class BaseIndicator extends View implements Indicator {
    protected IndicatorConfig config;
    protected Paint mPaint;
    protected float offset;

    public BaseIndicator(Context context) {
        this(context, null);
    }

    public BaseIndicator(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public BaseIndicator(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        config = new IndicatorConfig();
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setColor(Color.TRANSPARENT);
        mPaint.setColor(config.getNormalColor());
    }

    @NonNull
    @Override
    public View getIndicatorView() {
        if (config.isAttachToBanner()) {
            FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(
                    ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
            switch (config.getGravity()) {
                case IndicatorConfig.Direction.LEFT:
                    layoutParams.gravity = Gravity.BOTTOM | Gravity.START;
                    break;
                case IndicatorConfig.Direction.CENTER:
                    layoutParams.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
                    break;
                case IndicatorConfig.Direction.RIGHT:
                    layoutParams.gravity = Gravity.BOTTOM | Gravity.END;
                    break;
            }
            layoutParams.leftMargin = config.getMargins().leftMargin;
            layoutParams.rightMargin = config.getMargins().rightMargin;
            layoutParams.topMargin = config.getMargins().topMargin;
            layoutParams.bottomMargin = config.getMargins().bottomMargin;
            setLayoutParams(layoutParams);
        }
        return this;
    }

    @Override
    public IndicatorConfig getIndicatorConfig() {
        return config;
    }

    @Override
    public void onPageChanged(int count, int currentPosition) {
        config.setIndicatorSize(count);
        config.setCurrentPosition(currentPosition);
        requestLayout();
    }

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        offset = positionOffset;
        invalidate();

    }

    @Override
    public void onPageSelected(int position) {
        config.setCurrentPosition(position);
        invalidate();
    }

    @Override
    public void onPageScrollStateChanged(int state) {

    }
}


================================================
FILE: banner/src/main/java/com/youth/banner/indicator/CircleIndicator.java
================================================
package com.youth.banner.indicator;

import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;

/**
 * 圆形指示器
 * 如果想要大小一样,可以将选中和默认设置成同样大小
 */
public class CircleIndicator extends BaseIndicator {
    private int mNormalRadius;
    private int mSelectedRadius;
    private int maxRadius;

    public CircleIndicator(Context context) {
        this(context, null);
    }

    public CircleIndicator(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CircleIndicator(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mNormalRadius = config.getNormalWidth() / 2;
        mSelectedRadius = config.getSelectedWidth() / 2;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int count = config.getIndicatorSize();
        if (count <= 1) {
            return;
        }

        mNormalRadius = config.getNormalWidth() / 2;
        mSelectedRadius = config.getSelectedWidth() / 2;
        //考虑当 选中和默认 的大小不一样的情况
        maxRadius = Math.max(mSelectedRadius, mNormalRadius);
        //间距*(总数-1)+选中宽度+默认宽度*(总数-1)
        int width = (count - 1) * config.getIndicatorSpace() + config.getSelectedWidth() + config.getNormalWidth() * (count - 1);
        setMeasuredDimension(width, Math.max(config.getNormalWidth(), config.getSelectedWidth()));
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int count = config.getIndicatorSize();
        if (count <= 1) {
            return;
        }
        float left = 0;
        for (int i = 0; i < count; i++) {
            mPaint.setColor(config.getCurrentPosition() == i ? config.getSelectedColor() : config.getNormalColor());
            int indicatorWidth = config.getCurrentPosition() == i ? config.getSelectedWidth() : config.getNormalWidth();
            int radius = config.getCurrentPosition() == i ? mSelectedRadius : mNormalRadius;
            canvas.drawCircle(left + radius, maxRadius, radius, mPaint);
            left += indicatorWidth + config.getIndicatorSpace();
        }
//        mPaint.setColor(config.getNormalColor());
//        for (int i = 0; i < count; i++) {
//            canvas.drawCircle(left + maxRadius, maxRadius, mNormalRadius, mPaint);
//            left += config.getNormalWidth() + config.getIndicatorSpace();
//        }
//        mPaint.setColor(config.getSelectedColor());
//        left = maxRadius + (config.getNormalWidth() + config.getIndicatorSpace()) * config.getCurrentPosition();
//        canvas.drawCircle(left, maxRadius, mSelectedRadius, mPaint);
    }

}


================================================
FILE: banner/src/main/java/com/youth/banner/indicator/DrawableIndicator.java
================================================
package com.youth.banner.indicator;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;

import androidx.annotation.DrawableRes;
import androidx.annotation.IdRes;

import com.youth.banner.R;


/**
 * Drawable指示器
 */
public class DrawableIndicator extends BaseIndicator {
    private Bitmap normalBitmap;
    private Bitmap selectedBitmap;

    /**
     * 实例化Drawable指示器 ,也可以通过自定义属性设置
     * @param context
     * @param normalResId
     * @param selectedResId
     */
    public DrawableIndicator(Context context, @DrawableRes int normalResId, @DrawableRes int selectedResId) {
        super(context);
        normalBitmap = BitmapFactory.decodeResource(getResources(), normalResId);
        selectedBitmap = BitmapFactory.decodeResource(getResources(), selectedResId);
    }

    public DrawableIndicator(Context context) {
        this(context, null);
    }

    public DrawableIndicator(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public DrawableIndicator(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DrawableIndicator);
        if (a != null) {
            BitmapDrawable normal = (BitmapDrawable) a.getDrawable(R.styleable.DrawableIndicator_normal_drawable);
            BitmapDrawable selected = (BitmapDrawable) a.getDrawable(R.styleable.DrawableIndicator_selected_drawable);
            normalBitmap = normal.getBitmap();
            selectedBitmap = selected.getBitmap();
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int count = config.getIndicatorSize();
        if (count <= 1) {
            return;
        }
        setMeasuredDimension(selectedBitmap.getWidth() * (count - 1) + selectedBitmap.getWidth() + config.getIndicatorSpace() * (count - 1),
                Math.max(normalBitmap.getHeight(), selectedBitmap.getHeight()));
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int count = config.getIndicatorSize();
        if (count <= 1 || normalBitmap == null || selectedBitmap == null) {
            return;
        }

        float left = 0;
        for (int i = 0; i < count; i++) {
            canvas.drawBitmap(config.getCurrentPosition() == i ? selectedBitmap : normalBitmap, left, 0, mPaint);
            left += normalBitmap.getWidth() + config.getIndicatorSpace();
        }
    }


}


================================================
FILE: banner/src/main/java/com/youth/banner/indicator/Indicator.java
================================================
package com.youth.banner.indicator;

import android.view.View;

import androidx.annotation.NonNull;

import com.youth.banner.config.IndicatorConfig;
import com.youth.banner.listener.OnPageChangeListener;

public interface Indicator extends OnPageChangeListener {
    @NonNull
    View getIndicatorView();

    IndicatorConfig getIndicatorConfig();

    void onPageChanged(int count, int currentPosition);

}


================================================
FILE: banner/src/main/java/com/youth/banner/indicator/RectangleIndicator.java
================================================
package com.youth.banner.indicator;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.RectF;
import android.util.AttributeSet;

import com.youth.banner.config.BannerConfig;

/**
 * 矩形(条形)指示器
 * 1、可以设置选中和默认的宽度、指示器的圆角
 * 2、如果需要正方形将圆角设置为0,可将宽度和高度设置为一样
 * 3、如果不想选中时变长,可将选中的宽度和默认宽度设置为一样
 */
public class RectangleIndicator extends BaseIndicator {
    RectF rectF;

    public RectangleIndicator(Context context) {
        this(context, null);
    }

    public RectangleIndicator(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public RectangleIndicator(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        rectF = new RectF();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int count = config.getIndicatorSize();
        if (count <= 1) {
            return;
        }
        //间距*(总数-1)+默认宽度*(总数-1)+选中宽度
        int space = config.getIndicatorSpace() * (count - 1);
        int normal = config.getNormalWidth() * (count - 1);
        setMeasuredDimension(space + normal + config.getSelectedWidth(), config.getHeight());
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int count = config.getIndicatorSize();
        if (count <= 1) {
            return;
        }
        float left = 0;
        for (int i = 0; i < count; i++) {
            mPaint.setColor(config.getCurrentPosition() == i ? config.getSelectedColor() : config.getNormalColor());
            int indicatorWidth = config.getCurrentPosition() == i ? config.getSelectedWidth() : config.getNormalWidth();
            rectF.set(left, 0, left + indicatorWidth, config.getHeight());
            left += indicatorWidth + config.getIndicatorSpace();
            canvas.drawRoundRect(rectF, config.getRadius(), config.getRadius(), mPaint);
        }
    }
}


================================================
FILE: banner/src/main/java/com/youth/banner/indicator/RoundLinesIndicator.java
================================================
package com.youth.banner.indicator;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;

import androidx.annotation.Nullable;

import com.youth.banner.util.BannerUtils;

public class RoundLinesIndicator extends BaseIndicator {

    public RoundLinesIndicator(Context context) {
        this(context, null);
    }

    public RoundLinesIndicator(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public RoundLinesIndicator(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mPaint.setStyle(Paint.Style.FILL);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int count = config.getIndicatorSize();
        if (count <= 1) return;
        setMeasuredDimension((int) (config.getSelectedWidth() * count), config.getHeight());
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int count = config.getIndicatorSize();
        if (count <= 1) return;

        mPaint.setColor(config.getNormalColor());
        RectF oval = new RectF(0, 0, canvas.getWidth(), config.getHeight());
        canvas.drawRoundRect(oval, config.getRadius(), config.getRadius(), mPaint);

        mPaint.setColor(config.getSelectedColor());
        int left = config.getCurrentPosition() * config.getSelectedWidth();
        RectF rectF = new RectF(left, 0, left + config.getSelectedWidth(), config.getHeight());
        canvas.drawRoundRect(rectF, config.getRadius(), config.getRadius(), mPaint);
    }
}


================================================
FILE: banner/src/main/java/com/youth/banner/itemdecoration/MarginDecoration.java
================================================
package com.youth.banner.itemdecoration;

import android.graphics.Rect;
import android.view.View;

import androidx.annotation.NonNull;
import androidx.annotation.Px;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.youth.banner.util.BannerUtils;


public class MarginDecoration extends RecyclerView.ItemDecoration {
    private int mMarginPx;

    public MarginDecoration(@Px int margin) {
        mMarginPx = margin;
    }

    @Override
    public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent,
                               @NonNull RecyclerView.State state) {
        LinearLayoutManager linearLayoutManager = requireLinearLayoutManager(parent);
        if (linearLayoutManager.getOrientation() == LinearLayoutManager.VERTICAL) {
            outRect.top = mMarginPx;
            outRect.bottom = mMarginPx;
        } else {
            outRect.left = mMarginPx;
            outRect.right = mMarginPx;
        }
    }

    private LinearLayoutManager requireLinearLayoutManager(@NonNull RecyclerView parent) {
        RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
        if (layoutManager instanceof LinearLayoutManager) {
            return (LinearLayoutManager) layoutManager;
        }
        throw new IllegalStateException("The layoutManager must be LinearLayoutManager");
    }
}


================================================
FILE: banner/src/main/java/com/youth/banner/listener/OnBannerListener.java
================================================
package com.youth.banner.listener;

public interface OnBannerListener<T> {

    /**
     * 点击事件
     *
     * @param data     数据实体
     * @param position 当前位置
     */
    void OnBannerClick(T data, int position);

}


================================================
FILE: banner/src/main/java/com/youth/banner/listener/OnPageChangeListener.java
================================================
package com.youth.banner.listener;

import androidx.annotation.Px;
import androidx.viewpager2.widget.ViewPager2;


public interface OnPageChangeListener {
    /**
     * This method will be invoked when the current page is scrolled, either as part
     * of a programmatically initiated smooth scroll or a user initiated touch scroll.
     *
     * @param position             Position index of the first page currently being displayed.
     *                             Page position+1 will be visible if positionOffset is nonzero.
     * @param positionOffset       Value from [0, 1) indicating the offset from the page at position.
     * @param positionOffsetPixels Value in pixels indicating the offset from position.
     */
    void onPageScrolled(int position, float positionOffset, @Px int positionOffsetPixels);

    /**
     * This method will be invoked when a new page becomes selected. Animation is not
     * necessarily complete.
     *
     * @param position Position index of the new selected page.
     */
    void onPageSelected(int position);

    /**
Download .txt
gitextract_a7zjbpp5/

├── .gitignore
├── BannerExample.iml
├── LICENSE
├── README.md
├── app/
│   ├── .gitignore
│   ├── build.gradle
│   ├── proguard-rules.pro
│   └── src/
│       └── main/
│           ├── AndroidManifest.xml
│           ├── java/
│           │   └── com/
│           │       └── test/
│           │           └── banner/
│           │               ├── MainActivity.java
│           │               ├── adapter/
│           │               │   ├── ImageAdapter.java
│           │               │   ├── ImageNetAdapter.java
│           │               │   ├── ImageTitleAdapter.java
│           │               │   ├── ImageTitleNumAdapter.java
│           │               │   ├── MultipleTypesAdapter.java
│           │               │   ├── MyRecyclerViewAdapter.java
│           │               │   └── TopLineAdapter.java
│           │               ├── bean/
│           │               │   └── DataBean.java
│           │               ├── indicator/
│           │               │   └── NumIndicator.java
│           │               ├── ui/
│           │               │   ├── BannerFragment.java
│           │               │   ├── BannerListFragment.java
│           │               │   ├── BlankFragment.java
│           │               │   ├── ConstraintLayoutBannerActivity.java
│           │               │   ├── GalleryActivity.java
│           │               │   ├── RecyclerViewBannerActivity.java
│           │               │   ├── TVActivity.java
│           │               │   ├── TouTiaoActivity.java
│           │               │   ├── VideoActivity.java
│           │               │   └── Vp2FragmentRecyclerviewActivity.java
│           │               ├── util/
│           │               │   ├── ParentRecyclerView.java
│           │               │   └── TabLayoutMediator.java
│           │               └── viewholder/
│           │                   ├── ImageHolder.java
│           │                   ├── ImageTitleHolder.java
│           │                   ├── TitleHolder.java
│           │                   └── VideoHolder.java
│           └── res/
│               ├── drawable/
│               │   ├── background.xml
│               │   ├── default_selecter.xml
│               │   ├── green.xml
│               │   ├── selected_radius.xml
│               │   ├── unselected_radius.xml
│               │   └── white.xml
│               ├── layout/
│               │   ├── activity_constraint_layout_banner.xml
│               │   ├── activity_gallery.xml
│               │   ├── activity_main.xml
│               │   ├── activity_recyclerview_banner.xml
│               │   ├── activity_t_v.xml
│               │   ├── activity_tou_tiao.xml
│               │   ├── activity_video.xml
│               │   ├── activity_vp2_fragment_recyclerview.xml
│               │   ├── banner.xml
│               │   ├── banner_image.xml
│               │   ├── banner_image_title.xml
│               │   ├── banner_image_title_num.xml
│               │   ├── banner_title.xml
│               │   ├── banner_video.xml
│               │   ├── item.xml
│               │   ├── test.xml
│               │   └── top_line_item2.xml
│               ├── values/
│               │   ├── arrays.xml
│               │   ├── colors.xml
│               │   ├── dimens.xml
│               │   ├── strings.xml
│               │   └── styles.xml
│               └── values-w820dp/
│                   └── dimens.xml
├── banner/
│   ├── .gitignore
│   ├── build.gradle
│   ├── proguard-rules.pro
│   └── src/
│       └── main/
│           ├── AndroidManifest.xml
│           ├── java/
│           │   └── com/
│           │       └── youth/
│           │           └── banner/
│           │               ├── Banner.java
│           │               ├── adapter/
│           │               │   ├── BannerAdapter.java
│           │               │   └── BannerImageAdapter.java
│           │               ├── config/
│           │               │   ├── BannerConfig.java
│           │               │   └── IndicatorConfig.java
│           │               ├── holder/
│           │               │   ├── BannerImageHolder.java
│           │               │   └── IViewHolder.java
│           │               ├── indicator/
│           │               │   ├── BaseIndicator.java
│           │               │   ├── CircleIndicator.java
│           │               │   ├── DrawableIndicator.java
│           │               │   ├── Indicator.java
│           │               │   ├── RectangleIndicator.java
│           │               │   └── RoundLinesIndicator.java
│           │               ├── itemdecoration/
│           │               │   └── MarginDecoration.java
│           │               ├── listener/
│           │               │   ├── OnBannerListener.java
│           │               │   └── OnPageChangeListener.java
│           │               ├── transformer/
│           │               │   ├── AlphaPageTransformer.java
│           │               │   ├── BasePageTransformer.java
│           │               │   ├── DepthPageTransformer.java
│           │               │   ├── MZScaleInTransformer.java
│           │               │   ├── RotateDownPageTransformer.java
│           │               │   ├── RotateUpPageTransformer.java
│           │               │   ├── RotateYTransformer.java
│           │               │   ├── ScaleInTransformer.java
│           │               │   └── ZoomOutPageTransformer.java
│           │               └── util/
│           │                   ├── BannerLifecycleObserver.java
│           │                   ├── BannerLifecycleObserverAdapter.java
│           │                   ├── BannerUtils.java
│           │                   ├── LogUtils.java
│           │                   └── ScrollSpeedManger.java
│           └── res/
│               └── values/
│                   ├── attr.xml
│                   ├── ids.xml
│                   └── strings.xml
├── build.gradle
├── gradle/
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── settings.gradle
├── update_message.md
└── usekotlin/
    ├── .gitignore
    ├── build.gradle
    ├── consumer-rules.pro
    ├── proguard-rules.pro
    └── src/
        ├── androidTest/
        │   └── java/
        │       └── com/
        │           └── spring/
        │               └── usekotlin/
        │                   └── ExampleInstrumentedTest.kt
        ├── main/
        │   ├── AndroidManifest.xml
        │   ├── java/
        │   │   └── com/
        │   │       └── spring/
        │   │           └── usekotlin/
        │   │               ├── ImageAdapter.kt
        │   │               └── MainActivity.kt
        │   └── res/
        │       ├── layout/
        │       │   └── activity_main.xml
        │       └── values/
        │           ├── colors.xml
        │           ├── strings.xml
        │           └── styles.xml
        └── test/
            └── java/
                └── com/
                    └── spring/
                        └── usekotlin/
                            └── ExampleUnitTest.kt
Download .txt
SYMBOL INDEX (385 symbols across 56 files)

FILE: app/src/main/java/com/test/banner/MainActivity.java
  class MainActivity (line 45) | public class MainActivity extends AppCompatActivity {
    method onCreate (line 53) | @Override
    method click (line 102) | @OnClick({R.id.style_image, R.id.style_image_title, R.id.style_image_t...

FILE: app/src/main/java/com/test/banner/adapter/ImageAdapter.java
  class ImageAdapter (line 15) | public class ImageAdapter extends BannerAdapter<DataBean, ImageHolder> {
    method ImageAdapter (line 17) | public ImageAdapter(List<DataBean> mDatas) {
    method updateData (line 23) | public void updateData(List<DataBean> data) {
    method onCreateHolder (line 32) | @Override
    method onBindView (line 44) | @Override

FILE: app/src/main/java/com/test/banner/adapter/ImageNetAdapter.java
  class ImageNetAdapter (line 34) | public class ImageNetAdapter extends BannerAdapter<DataBean, ImageHolder> {
    method ImageNetAdapter (line 36) | public ImageNetAdapter(List<DataBean> mDatas) {
    method onCreateHolder (line 40) | @Override
    method onBindView (line 50) | @Override

FILE: app/src/main/java/com/test/banner/adapter/ImageTitleAdapter.java
  class ImageTitleAdapter (line 19) | public class ImageTitleAdapter extends BannerAdapter<DataBean, ImageTitl...
    method ImageTitleAdapter (line 21) | public ImageTitleAdapter(List<DataBean> mDatas) {
    method onCreateHolder (line 25) | @Override
    method onBindView (line 30) | @Override

FILE: app/src/main/java/com/test/banner/adapter/ImageTitleNumAdapter.java
  class ImageTitleNumAdapter (line 21) | public class ImageTitleNumAdapter extends BannerAdapter<DataBean, ImageT...
    method ImageTitleNumAdapter (line 23) | public ImageTitleNumAdapter(List<DataBean> mDatas) {
    method onCreateHolder (line 29) | @Override
    method onBindView (line 38) | @Override
    class BannerViewHolder (line 47) | class BannerViewHolder extends RecyclerView.ViewHolder {
      method BannerViewHolder (line 52) | public BannerViewHolder(@NonNull View view) {

FILE: app/src/main/java/com/test/banner/adapter/MultipleTypesAdapter.java
  class MultipleTypesAdapter (line 25) | public class MultipleTypesAdapter extends BannerAdapter<DataBean, Recycl...
    method MultipleTypesAdapter (line 29) | public MultipleTypesAdapter(Context context, List<DataBean> mDatas) {
    method onCreateHolder (line 34) | @Override
    method getItemViewType (line 47) | @Override
    method onBindView (line 57) | @Override
    method getVHMap (line 87) | public SparseArray<RecyclerView.ViewHolder> getVHMap() {

FILE: app/src/main/java/com/test/banner/adapter/MyRecyclerViewAdapter.java
  class MyRecyclerViewAdapter (line 20) | public class MyRecyclerViewAdapter extends RecyclerView.Adapter {
    method MyRecyclerViewAdapter (line 23) | public MyRecyclerViewAdapter(Context context) {
    method onCreateViewHolder (line 27) | @NonNull
    method onBindViewHolder (line 37) | @Override
    method getItemViewType (line 51) | @Override
    method getItemCount (line 60) | @Override
    class MyViewHolder (line 90) | class MyViewHolder extends RecyclerView.ViewHolder {
      method MyViewHolder (line 93) | public MyViewHolder(@NonNull View itemView) {
    class MyBannerViewHolder (line 99) | class MyBannerViewHolder extends RecyclerView.ViewHolder {
      method MyBannerViewHolder (line 102) | public MyBannerViewHolder(@NonNull View itemView) {

FILE: app/src/main/java/com/test/banner/adapter/TopLineAdapter.java
  class TopLineAdapter (line 20) | public class TopLineAdapter extends BannerAdapter<DataBean, TopLineAdapt...
    method TopLineAdapter (line 22) | public TopLineAdapter(List<DataBean> mDatas) {
    method onCreateHolder (line 26) | @Override
    method onBindView (line 31) | @Override
    class TopLineHolder (line 43) | class TopLineHolder extends RecyclerView.ViewHolder {
      method TopLineHolder (line 47) | public TopLineHolder(@NonNull View view) {

FILE: app/src/main/java/com/test/banner/bean/DataBean.java
  class DataBean (line 9) | public class DataBean {
    method DataBean (line 15) | public DataBean(Integer imageRes, String title, int viewType) {
    method DataBean (line 21) | public DataBean(String imageUrl, String title, int viewType) {
    method getTestData (line 27) | public static List<DataBean> getTestData() {
    method getTestData2 (line 38) | public static List<DataBean> getTestData2() {
    method getTestDataVideo (line 52) | public static List<DataBean> getTestDataVideo() {
    method getTestData3 (line 63) | public static List<DataBean> getTestData3() {
    method getVideos (line 73) | public static List<DataBean> getVideos() {
    method getColors (line 85) | public static List<String> getColors(int size) {
    method getRandColor (line 99) | public static String getRandColor() {

FILE: app/src/main/java/com/test/banner/indicator/NumIndicator.java
  class NumIndicator (line 18) | public class NumIndicator extends BaseIndicator {
    method NumIndicator (line 23) | public NumIndicator(Context context) {
    method NumIndicator (line 27) | public NumIndicator(Context context, AttributeSet attrs) {
    method NumIndicator (line 31) | public NumIndicator(Context context, AttributeSet attrs, int defStyleA...
    method onMeasure (line 40) | @Override
    method onDraw (line 50) | @Override

FILE: app/src/main/java/com/test/banner/ui/BannerFragment.java
  class BannerFragment (line 22) | public class BannerFragment extends Fragment {
    method newInstance (line 27) | public static Fragment newInstance() {
    method onCreateView (line 31) | @Nullable
    method onViewCreated (line 39) | @Override
    method onStart (line 48) | @Override
    method onStop (line 54) | @Override

FILE: app/src/main/java/com/test/banner/ui/BannerListFragment.java
  class BannerListFragment (line 22) | public class BannerListFragment extends Fragment {
    method newInstance (line 29) | public static Fragment newInstance(int i) {
    method onCreateView (line 34) | @Nullable
    method onViewCreated (line 42) | @Override

FILE: app/src/main/java/com/test/banner/ui/BlankFragment.java
  class BlankFragment (line 29) | public class BlankFragment extends Fragment {
    method newInstance (line 31) | public static Fragment newInstance() {
    method onCreateView (line 35) | @Nullable
    method onActivityCreated (line 41) | @Override

FILE: app/src/main/java/com/test/banner/ui/ConstraintLayoutBannerActivity.java
  class ConstraintLayoutBannerActivity (line 23) | public class ConstraintLayoutBannerActivity extends AppCompatActivity {
    method onCreate (line 28) | @Override

FILE: app/src/main/java/com/test/banner/ui/GalleryActivity.java
  class GalleryActivity (line 20) | public class GalleryActivity extends AppCompatActivity {
    method onCreate (line 29) | @Override

FILE: app/src/main/java/com/test/banner/ui/RecyclerViewBannerActivity.java
  class RecyclerViewBannerActivity (line 18) | public class RecyclerViewBannerActivity extends AppCompatActivity {
    method onCreate (line 22) | @Override

FILE: app/src/main/java/com/test/banner/ui/TVActivity.java
  class TVActivity (line 19) | public class TVActivity extends AppCompatActivity {
    method onCreate (line 25) | @Override
    method onKeyDown (line 35) | @Override

FILE: app/src/main/java/com/test/banner/ui/TouTiaoActivity.java
  class TouTiaoActivity (line 17) | public class TouTiaoActivity extends AppCompatActivity {
    method onCreate (line 21) | @Override

FILE: app/src/main/java/com/test/banner/ui/VideoActivity.java
  class VideoActivity (line 25) | public class VideoActivity extends AppCompatActivity {
    method onCreate (line 30) | @Override
    method stopVideo (line 59) | private void stopVideo(int position) {
    method onPause (line 76) | @Override
    method onResume (line 83) | @Override
    method onDestroy (line 90) | @Override
    method onBackPressed (line 96) | @Override

FILE: app/src/main/java/com/test/banner/ui/Vp2FragmentRecyclerviewActivity.java
  class Vp2FragmentRecyclerviewActivity (line 21) | public class Vp2FragmentRecyclerviewActivity extends AppCompatActivity {
    method onCreate (line 30) | @Override

FILE: app/src/main/java/com/test/banner/util/ParentRecyclerView.java
  class ParentRecyclerView (line 11) | public class ParentRecyclerView extends RecyclerView {
    method ParentRecyclerView (line 12) | public ParentRecyclerView(@NonNull Context context) {
    method ParentRecyclerView (line 16) | public ParentRecyclerView(@NonNull Context context, @Nullable Attribut...
    method ParentRecyclerView (line 20) | public ParentRecyclerView(@NonNull Context context, @Nullable Attribut...
    method dispatchTouchEvent (line 26) | @Override

FILE: app/src/main/java/com/test/banner/util/TabLayoutMediator.java
  class TabLayoutMediator (line 31) | @RestrictTo(LIBRARY_GROUP)
    type OnConfigureTabCallback (line 48) | public interface OnConfigureTabCallback {
      method onConfigureTab (line 57) | void onConfigureTab(@NonNull TabLayout.Tab tab, int position);
    method TabLayoutMediator (line 68) | public TabLayoutMediator(@NonNull TabLayout tabLayout, @NonNull ViewPa...
    method TabLayoutMediator (line 83) | public TabLayoutMediator(@NonNull TabLayout tabLayout, @NonNull ViewPa...
    method attach (line 96) | public void attach() {
    method detach (line 132) | public void detach() {
    method populateTabsFromPagerAdapter (line 142) | @SuppressWarnings("WeakerAccess")
    class TabLayoutOnPageChangeCallback (line 172) | private static class TabLayoutOnPageChangeCallback extends ViewPager2....
      method TabLayoutOnPageChangeCallback (line 177) | TabLayoutOnPageChangeCallback(TabLayout tabLayout) {
      method onPageScrollStateChanged (line 182) | @Override
      method onPageScrolled (line 188) | @Override
      method onPageSelected (line 205) | @Override
      method reset (line 220) | void reset() {
    method setScrollPosition (line 252) | @SuppressWarnings("WeakerAccess")
    method selectTab (line 267) | @SuppressWarnings("WeakerAccess")
    method throwMethodNotFound (line 280) | private static void throwMethodNotFound(String method) {
    method throwInvokeFailed (line 284) | private static void throwInvokeFailed(String method) {
    class ViewPagerOnTabSelectedListener (line 294) | private static class ViewPagerOnTabSelectedListener implements TabLayo...
      method ViewPagerOnTabSelectedListener (line 297) | ViewPagerOnTabSelectedListener(ViewPager2 viewPager) {
      method onTabSelected (line 301) | @Override
      method onTabUnselected (line 306) | @Override
      method onTabReselected (line 311) | @Override
    class PagerAdapterObserver (line 317) | private class PagerAdapterObserver extends RecyclerView.AdapterDataObs...
      method PagerAdapterObserver (line 318) | PagerAdapterObserver() {}
      method onChanged (line 320) | @Override
      method onItemRangeChanged (line 325) | @Override
      method onItemRangeChanged (line 330) | @Override
      method onItemRangeInserted (line 335) | @Override
      method onItemRangeRemoved (line 340) | @Override
      method onItemRangeMoved (line 345) | @Override

FILE: app/src/main/java/com/test/banner/viewholder/ImageHolder.java
  class ImageHolder (line 9) | public class ImageHolder extends RecyclerView.ViewHolder {
    method ImageHolder (line 12) | public ImageHolder(@NonNull View view) {

FILE: app/src/main/java/com/test/banner/viewholder/ImageTitleHolder.java
  class ImageTitleHolder (line 12) | public class ImageTitleHolder extends RecyclerView.ViewHolder {
    method ImageTitleHolder (line 16) | public ImageTitleHolder(@NonNull View view) {

FILE: app/src/main/java/com/test/banner/viewholder/TitleHolder.java
  class TitleHolder (line 12) | public class TitleHolder extends RecyclerView.ViewHolder {
    method TitleHolder (line 15) | public TitleHolder(@NonNull View view) {

FILE: app/src/main/java/com/test/banner/viewholder/VideoHolder.java
  class VideoHolder (line 11) | public class VideoHolder extends RecyclerView.ViewHolder {
    method VideoHolder (line 14) | public VideoHolder(@NonNull View view) {

FILE: banner/src/main/java/com/youth/banner/Banner.java
  class Banner (line 54) | public class Banner<T, BA extends BannerAdapter<T, ? extends RecyclerVie...
    method Banner (line 116) | public Banner(Context context) {
    method Banner (line 120) | public Banner(Context context, AttributeSet attrs) {
    method Banner (line 124) | public Banner(Context context, AttributeSet attrs, int defStyleAttr) {
    method init (line 130) | private void init(Context context) {
    method initTypedArray (line 152) | private void initTypedArray(Context context, AttributeSet attrs) {
    method initIndicatorAttr (line 183) | private void initIndicatorAttr() {
    method dispatchTouchEvent (line 219) | @Override
    method onInterceptTouchEvent (line 236) | @Override
    method dispatchDraw (line 267) | @Override
    method drawTopLeft (line 300) | private void drawTopLeft(Canvas canvas) {
    method drawTopRight (line 310) | private void drawTopRight(Canvas canvas) {
    method drawBottomLeft (line 321) | private void drawBottomLeft(Canvas canvas) {
    method drawBottomRight (line 332) | private void drawBottomRight(Canvas canvas) {
    method onAttachedToWindow (line 344) | @Override
    method onDetachedFromWindow (line 350) | @Override
    class BannerOnPageChangeCallback (line 356) | class BannerOnPageChangeCallback extends ViewPager2.OnPageChangeCallba...
      method onPageScrolled (line 360) | @Override
      method onPageSelected (line 371) | @Override
      method onPageScrollStateChanged (line 385) | @Override
    class AutoLoopTask (line 411) | static class AutoLoopTask implements Runnable {
      method AutoLoopTask (line 414) | AutoLoopTask(Banner banner) {
      method run (line 418) | @Override
    method onChanged (line 434) | @Override
    method initIndicator (line 445) | private void initIndicator() {
    method setInfiniteLoop (line 457) | private void setInfiniteLoop() {
    method setRecyclerViewPadding (line 465) | private void setRecyclerViewPadding(int itemPadding) {
    method setRecyclerViewPadding (line 469) | private void setRecyclerViewPadding(int leftItemPadding, int rightItem...
    method getCurrentItem (line 486) | public int getCurrentItem() {
    method getItemCount (line 490) | public int getItemCount() {
    method getScrollTime (line 498) | public int getScrollTime() {
    method isInfiniteLoop (line 502) | public boolean isInfiniteLoop() {
    method getAdapter (line 506) | public BannerAdapter getAdapter() {
    method getViewPager2 (line 510) | public ViewPager2 getViewPager2() {
    method getIndicator (line 514) | public Indicator getIndicator() {
    method getIndicatorConfig (line 518) | public IndicatorConfig getIndicatorConfig() {
    method getRealCount (line 528) | public int getRealCount() {
    method setIntercept (line 543) | public Banner setIntercept(boolean intercept) {
    method setCurrentItem (line 553) | public Banner setCurrentItem(int position) {
    method setCurrentItem (line 563) | public Banner setCurrentItem(int position, boolean smoothScroll) {
    method setIndicatorPageChange (line 568) | public Banner setIndicatorPageChange() {
    method removeIndicator (line 576) | public Banner removeIndicator() {
    method setStartPosition (line 587) | public Banner setStartPosition(int mStartPosition) {
    method getStartPosition (line 592) | public int getStartPosition() {
    method setUserInputEnabled (line 601) | public Banner setUserInputEnabled(boolean enabled) {
    method addPageTransformer (line 611) | public Banner addPageTransformer(@Nullable ViewPager2.PageTransformer ...
    method setPageTransformer (line 619) | public Banner setPageTransformer(@Nullable ViewPager2.PageTransformer ...
    method removeTransformer (line 624) | public Banner removeTransformer(ViewPager2.PageTransformer transformer) {
    method addItemDecoration (line 632) | public Banner addItemDecoration(RecyclerView.ItemDecoration decor) {
    method addItemDecoration (line 637) | public Banner addItemDecoration(RecyclerView.ItemDecoration decor, int...
    method isAutoLoop (line 647) | public Banner isAutoLoop(boolean isAutoLoop) {
    method setLoopTime (line 658) | public Banner setLoopTime(long loopTime) {
    method setScrollTime (line 666) | public Banner setScrollTime(int scrollTime) {
    method start (line 674) | public Banner start() {
    method stop (line 685) | public Banner stop() {
    method destroy (line 695) | public void destroy() {
    method setAdapter (line 706) | public Banner setAdapter(BA adapter) {
    method setAdapter (line 727) | public Banner setAdapter(BA adapter,boolean isInfiniteLoop) {
    method setDatas (line 739) | public Banner setDatas(List<T> datas) {
    method setOrientation (line 754) | public Banner setOrientation(@Orientation int orientation) {
    method setTouchSlop (line 762) | public Banner setTouchSlop(int mTouchSlop) {
    method setOnBannerListener (line 770) | public Banner setOnBannerListener(OnBannerListener<T> listener) {
    method addOnPageChangeListener (line 784) | public Banner addOnPageChangeListener(OnPageChangeListener pageListene...
    method setBannerRound (line 796) | public Banner setBannerRound(float radius) {
    method setBannerRound2 (line 804) | @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    method setBannerGalleryEffect (line 816) | public Banner setBannerGalleryEffect(int itemWidth, int pageMargin) {
    method setBannerGalleryEffect (line 827) | public Banner setBannerGalleryEffect(int leftItemWidth, int rightItemW...
    method setBannerGalleryEffect (line 838) | public Banner setBannerGalleryEffect(int itemWidth, int pageMargin, fl...
    method setBannerGalleryEffect (line 850) | public Banner setBannerGalleryEffect(int leftItemWidth, int rightItemW...
    method setBannerGalleryMZ (line 867) | public Banner setBannerGalleryMZ(int itemWidth) {
    method setBannerGalleryMZ (line 877) | public Banner setBannerGalleryMZ(int itemWidth, float scale) {
    method setIndicator (line 894) | public Banner setIndicator(Indicator indicator) {
    method setIndicator (line 905) | public Banner setIndicator(Indicator indicator, boolean attachToBanner) {
    method setIndicatorSelectedColor (line 914) | public Banner setIndicatorSelectedColor(@ColorInt int color) {
    method setIndicatorSelectedColorRes (line 921) | public Banner setIndicatorSelectedColorRes(@ColorRes int color) {
    method setIndicatorNormalColor (line 926) | public Banner setIndicatorNormalColor(@ColorInt int color) {
    method setIndicatorNormalColorRes (line 933) | public Banner setIndicatorNormalColorRes(@ColorRes int color) {
    method setIndicatorGravity (line 938) | public Banner setIndicatorGravity(@IndicatorConfig.Direction int gravi...
    method setIndicatorSpace (line 946) | public Banner setIndicatorSpace(int indicatorSpace) {
    method setIndicatorMargins (line 953) | public Banner setIndicatorMargins(IndicatorConfig.Margins margins) {
    method setIndicatorWidth (line 961) | public Banner setIndicatorWidth(int normalWidth, int selectedWidth) {
    method setIndicatorNormalWidth (line 969) | public Banner setIndicatorNormalWidth(int normalWidth) {
    method setIndicatorSelectedWidth (line 976) | public Banner setIndicatorSelectedWidth(int selectedWidth) {
    method setIndicatorRadius (line 983) | public Banner setIndicatorRadius(int indicatorRadius) {
    method setIndicatorHeight (line 990) | public Banner setIndicatorHeight(int indicatorHeight) {
    method addBannerLifecycleObserver (line 1003) | public Banner addBannerLifecycleObserver(LifecycleOwner owner) {
    method onStart (line 1010) | @Override
    method onStop (line 1015) | @Override
    method onDestroy (line 1020) | @Override

FILE: banner/src/main/java/com/youth/banner/adapter/BannerAdapter.java
  class BannerAdapter (line 21) | public abstract class BannerAdapter<T, VH extends RecyclerView.ViewHolde...
    method BannerAdapter (line 27) | public BannerAdapter(List<T> datas) {
    method setDatas (line 36) | public void setDatas(List<T> datas) {
    method getData (line 51) | public T getData(int position) {
    method getRealData (line 64) | public T getRealData(int position) {
    method onBindViewHolder (line 73) | @Override
    method onCreateViewHolder (line 86) | @NonNull
    method getItemCount (line 101) | @Override
    method getRealCount (line 106) | public int getRealCount() {
    method getRealPosition (line 110) | public int getRealPosition(int position) {
    method setOnBannerListener (line 114) | public void setOnBannerListener(OnBannerListener<T> listener) {
    method getViewHolder (line 118) | public VH getViewHolder() {
    method setIncreaseCount (line 122) | public void setIncreaseCount(int increaseCount) {

FILE: banner/src/main/java/com/youth/banner/adapter/BannerImageAdapter.java
  class BannerImageAdapter (line 13) | public abstract class BannerImageAdapter<T> extends BannerAdapter<T, Ban...
    method BannerImageAdapter (line 15) | public BannerImageAdapter(List<T> mData) {
    method onCreateHolder (line 19) | @Override

FILE: banner/src/main/java/com/youth/banner/config/BannerConfig.java
  class BannerConfig (line 27) | public class BannerConfig {

FILE: banner/src/main/java/com/youth/banner/config/IndicatorConfig.java
  class IndicatorConfig (line 9) | public class IndicatorConfig {
    class Margins (line 38) | public static class Margins {
      method Margins (line 44) | public Margins() {
      method Margins (line 48) | public Margins(int marginSize) {
      method Margins (line 52) | public Margins(int leftMargin, int topMargin, int rightMargin, int b...
    method getMargins (line 60) | public Margins getMargins() {
    method setMargins (line 67) | public IndicatorConfig setMargins(Margins margins) {
    method getIndicatorSize (line 72) | public int getIndicatorSize() {
    method setIndicatorSize (line 76) | public IndicatorConfig setIndicatorSize(int indicatorSize) {
    method getNormalColor (line 81) | public int getNormalColor() {
    method setNormalColor (line 85) | public IndicatorConfig setNormalColor(int normalColor) {
    method getSelectedColor (line 90) | public int getSelectedColor() {
    method setSelectedColor (line 94) | public IndicatorConfig setSelectedColor(int selectedColor) {
    method getIndicatorSpace (line 99) | public int getIndicatorSpace() {
    method setIndicatorSpace (line 103) | public IndicatorConfig setIndicatorSpace(int indicatorSpace) {
    method getCurrentPosition (line 108) | public int getCurrentPosition() {
    method setCurrentPosition (line 112) | public IndicatorConfig setCurrentPosition(int currentPosition) {
    method getNormalWidth (line 117) | public int getNormalWidth() {
    method setNormalWidth (line 121) | public IndicatorConfig setNormalWidth(int normalWidth) {
    method getSelectedWidth (line 126) | public int getSelectedWidth() {
    method setSelectedWidth (line 130) | public IndicatorConfig setSelectedWidth(int selectedWidth) {
    method getGravity (line 135) | public int getGravity() {
    method setGravity (line 139) | public IndicatorConfig setGravity(@Direction int gravity) {
    method isAttachToBanner (line 144) | public boolean isAttachToBanner() {
    method setAttachToBanner (line 148) | public IndicatorConfig setAttachToBanner(boolean attachToBanner) {
    method getRadius (line 153) | public int getRadius() {
    method setRadius (line 157) | public IndicatorConfig setRadius(int radius) {
    method getHeight (line 162) | public int getHeight() {
    method setHeight (line 166) | public IndicatorConfig setHeight(int height) {

FILE: banner/src/main/java/com/youth/banner/holder/BannerImageHolder.java
  class BannerImageHolder (line 9) | public
    method BannerImageHolder (line 13) | public BannerImageHolder(@NonNull View view) {

FILE: banner/src/main/java/com/youth/banner/holder/IViewHolder.java
  type IViewHolder (line 5) | public interface IViewHolder<T, VH> {
    method onCreateHolder (line 12) | VH onCreateHolder(ViewGroup parent, int viewType);
    method onBindView (line 22) | void onBindView(VH holder, T data, int position, int size);

FILE: banner/src/main/java/com/youth/banner/indicator/BaseIndicator.java
  class BaseIndicator (line 20) | public class BaseIndicator extends View implements Indicator {
    method BaseIndicator (line 25) | public BaseIndicator(Context context) {
    method BaseIndicator (line 29) | public BaseIndicator(Context context, @Nullable AttributeSet attrs) {
    method BaseIndicator (line 33) | public BaseIndicator(Context context, @Nullable AttributeSet attrs, in...
    method getIndicatorView (line 42) | @NonNull
    method getIndicatorConfig (line 68) | @Override
    method onPageChanged (line 73) | @Override
    method onPageScrolled (line 80) | @Override
    method onPageSelected (line 87) | @Override
    method onPageScrollStateChanged (line 93) | @Override

FILE: banner/src/main/java/com/youth/banner/indicator/CircleIndicator.java
  class CircleIndicator (line 11) | public class CircleIndicator extends BaseIndicator {
    method CircleIndicator (line 16) | public CircleIndicator(Context context) {
    method CircleIndicator (line 20) | public CircleIndicator(Context context, AttributeSet attrs) {
    method CircleIndicator (line 24) | public CircleIndicator(Context context, AttributeSet attrs, int defSty...
    method onMeasure (line 30) | @Override
    method onDraw (line 47) | @Override

FILE: banner/src/main/java/com/youth/banner/indicator/DrawableIndicator.java
  class DrawableIndicator (line 22) | public class DrawableIndicator extends BaseIndicator {
    method DrawableIndicator (line 32) | public DrawableIndicator(Context context, @DrawableRes int normalResId...
    method DrawableIndicator (line 38) | public DrawableIndicator(Context context) {
    method DrawableIndicator (line 42) | public DrawableIndicator(Context context, AttributeSet attrs) {
    method DrawableIndicator (line 46) | public DrawableIndicator(Context context, AttributeSet attrs, int defS...
    method onMeasure (line 57) | @Override
    method onDraw (line 68) | @Override

FILE: banner/src/main/java/com/youth/banner/indicator/Indicator.java
  type Indicator (line 10) | public interface Indicator extends OnPageChangeListener {
    method getIndicatorView (line 11) | @NonNull
    method getIndicatorConfig (line 14) | IndicatorConfig getIndicatorConfig();
    method onPageChanged (line 16) | void onPageChanged(int count, int currentPosition);

FILE: banner/src/main/java/com/youth/banner/indicator/RectangleIndicator.java
  class RectangleIndicator (line 16) | public class RectangleIndicator extends BaseIndicator {
    method RectangleIndicator (line 19) | public RectangleIndicator(Context context) {
    method RectangleIndicator (line 23) | public RectangleIndicator(Context context, AttributeSet attrs) {
    method RectangleIndicator (line 27) | public RectangleIndicator(Context context, AttributeSet attrs, int def...
    method onMeasure (line 32) | @Override
    method onDraw (line 45) | @Override

FILE: banner/src/main/java/com/youth/banner/indicator/RoundLinesIndicator.java
  class RoundLinesIndicator (line 13) | public class RoundLinesIndicator extends BaseIndicator {
    method RoundLinesIndicator (line 15) | public RoundLinesIndicator(Context context) {
    method RoundLinesIndicator (line 19) | public RoundLinesIndicator(Context context, @Nullable AttributeSet att...
    method RoundLinesIndicator (line 23) | public RoundLinesIndicator(Context context, @Nullable AttributeSet att...
    method onMeasure (line 28) | @Override
    method onDraw (line 36) | @Override

FILE: banner/src/main/java/com/youth/banner/itemdecoration/MarginDecoration.java
  class MarginDecoration (line 14) | public class MarginDecoration extends RecyclerView.ItemDecoration {
    method MarginDecoration (line 17) | public MarginDecoration(@Px int margin) {
    method getItemOffsets (line 21) | @Override
    method requireLinearLayoutManager (line 34) | private LinearLayoutManager requireLinearLayoutManager(@NonNull Recycl...

FILE: banner/src/main/java/com/youth/banner/listener/OnBannerListener.java
  type OnBannerListener (line 3) | public interface OnBannerListener<T> {
    method OnBannerClick (line 11) | void OnBannerClick(T data, int position);

FILE: banner/src/main/java/com/youth/banner/listener/OnPageChangeListener.java
  type OnPageChangeListener (line 7) | public interface OnPageChangeListener {
    method onPageScrolled (line 17) | void onPageScrolled(int position, float positionOffset, @Px int positi...
    method onPageSelected (line 25) | void onPageSelected(int position);
    method onPageScrollStateChanged (line 35) | void onPageScrollStateChanged(@ViewPager2.ScrollState int state);

FILE: banner/src/main/java/com/youth/banner/transformer/AlphaPageTransformer.java
  class AlphaPageTransformer (line 7) | public class AlphaPageTransformer extends BasePageTransformer {
    method AlphaPageTransformer (line 11) | public AlphaPageTransformer() {
    method AlphaPageTransformer (line 14) | public AlphaPageTransformer(float minAlpha) {
    method transformPage (line 18) | @Override

FILE: banner/src/main/java/com/youth/banner/transformer/BasePageTransformer.java
  class BasePageTransformer (line 5) | public abstract class BasePageTransformer implements ViewPager2.PageTran...

FILE: banner/src/main/java/com/youth/banner/transformer/DepthPageTransformer.java
  class DepthPageTransformer (line 7) | public class DepthPageTransformer extends BasePageTransformer {
    method DepthPageTransformer (line 11) | public DepthPageTransformer() {
    method DepthPageTransformer (line 14) | public DepthPageTransformer(float minScale) {
    method transformPage (line 18) | public void transformPage(View view, float position) {

FILE: banner/src/main/java/com/youth/banner/transformer/MZScaleInTransformer.java
  class MZScaleInTransformer (line 13) | public class MZScaleInTransformer extends BasePageTransformer {
    method MZScaleInTransformer (line 17) | public MZScaleInTransformer() {
    method MZScaleInTransformer (line 20) | public MZScaleInTransformer(float minScale) {
    method transformPage (line 24) | @Override
    method requireViewPager (line 62) | private ViewPager2 requireViewPager(@NonNull View page) {

FILE: banner/src/main/java/com/youth/banner/transformer/RotateDownPageTransformer.java
  class RotateDownPageTransformer (line 7) | public class RotateDownPageTransformer extends BasePageTransformer {
    method RotateDownPageTransformer (line 11) | public RotateDownPageTransformer() {
    method RotateDownPageTransformer (line 14) | public RotateDownPageTransformer(float maxRotate) {
    method transformPage (line 18) | @Override

FILE: banner/src/main/java/com/youth/banner/transformer/RotateUpPageTransformer.java
  class RotateUpPageTransformer (line 7) | public class RotateUpPageTransformer extends BasePageTransformer {
    method RotateUpPageTransformer (line 11) | public RotateUpPageTransformer() {
    method RotateUpPageTransformer (line 14) | public RotateUpPageTransformer(float maxRotate) {
    method transformPage (line 18) | @Override

FILE: banner/src/main/java/com/youth/banner/transformer/RotateYTransformer.java
  class RotateYTransformer (line 7) | public class RotateYTransformer extends BasePageTransformer {
    method RotateYTransformer (line 11) | public RotateYTransformer() {
    method RotateYTransformer (line 14) | public RotateYTransformer(float maxRotate) {
    method transformPage (line 18) | @Override

FILE: banner/src/main/java/com/youth/banner/transformer/ScaleInTransformer.java
  class ScaleInTransformer (line 12) | public class ScaleInTransformer extends BasePageTransformer {
    method ScaleInTransformer (line 16) | public ScaleInTransformer() {
    method ScaleInTransformer (line 19) | public ScaleInTransformer(float minScale) {
    method transformPage (line 23) | @Override

FILE: banner/src/main/java/com/youth/banner/transformer/ZoomOutPageTransformer.java
  class ZoomOutPageTransformer (line 8) | public class ZoomOutPageTransformer extends BasePageTransformer {
    method ZoomOutPageTransformer (line 14) | public ZoomOutPageTransformer() {
    method ZoomOutPageTransformer (line 17) | public ZoomOutPageTransformer(float minScale,float minAlpha ) {
    method transformPage (line 22) | public void transformPage(View view, float position) {

FILE: banner/src/main/java/com/youth/banner/util/BannerLifecycleObserver.java
  type BannerLifecycleObserver (line 6) | public interface BannerLifecycleObserver extends LifecycleObserver {
    method onStop (line 8) | void onStop(LifecycleOwner owner);
    method onStart (line 10) | void onStart(LifecycleOwner owner);
    method onDestroy (line 12) | void onDestroy(LifecycleOwner owner);

FILE: banner/src/main/java/com/youth/banner/util/BannerLifecycleObserverAdapter.java
  class BannerLifecycleObserverAdapter (line 8) | public class BannerLifecycleObserverAdapter implements LifecycleObserver {
    method BannerLifecycleObserverAdapter (line 12) | public BannerLifecycleObserverAdapter(LifecycleOwner lifecycleOwner, B...
    method onStart (line 17) | @OnLifecycleEvent(Lifecycle.Event.ON_START)
    method onStop (line 23) | @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    method onDestroy (line 29) | @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)

FILE: banner/src/main/java/com/youth/banner/util/BannerUtils.java
  class BannerUtils (line 16) | public class BannerUtils {
    method getRealPosition (line 26) | public static int getRealPosition(boolean isIncrease, int position, in...
    method getView (line 48) | public static View getView(@NonNull ViewGroup parent, @LayoutRes int l...
    method dp2px (line 60) | public static int dp2px(float dp) {
    method setBannerRound (line 70) | @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)

FILE: banner/src/main/java/com/youth/banner/util/LogUtils.java
  class LogUtils (line 7) | public class LogUtils {
    method d (line 12) | public static void d(String msg) {
    method e (line 18) | public static void e(String msg) {
    method i (line 24) | public static void i(String msg) {
    method v (line 30) | public static void v( String msg) {
    method w (line 36) | public static void w(String msg) {

FILE: banner/src/main/java/com/youth/banner/util/ScrollSpeedManger.java
  class ScrollSpeedManger (line 16) | public class ScrollSpeedManger extends LinearLayoutManager {
    method ScrollSpeedManger (line 19) | public ScrollSpeedManger(Banner banner, LinearLayoutManager linearLayo...
    method smoothScrollToPosition (line 24) | @Override
    method reflectLayoutManager (line 36) | public static void reflectLayoutManager(Banner banner) {
Condensed preview — 118 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (242K chars).
[
  {
    "path": ".gitignore",
    "chars": 490,
    "preview": "# Built application files\r\n*.apk\r\n*.ap_\r\n\r\n# Files for the Dalvik VM\r\n*.dex\r\n\r\n# Java class files\r\n*.class\r\n\r\n# Generate"
  },
  {
    "path": "BannerExample.iml",
    "chars": 975,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<module external.linked.project.id=\"BannerExample\" external.linked.project.path=\""
  },
  {
    "path": "LICENSE",
    "chars": 11357,
    "preview": "                                 Apache License\n                           Version 2.0, January 2004\n                   "
  },
  {
    "path": "README.md",
    "chars": 10775,
    "preview": "\r\n## Banner 2.0 全新升级\r\n> 只做一个可以自定义的轮播容器,不侵入UI ———— Banner 2.0\r\n\r\n```\r\n> 各位老铁反馈的问题我都有看,不是不解决,有时真的很难复现,\r\n> 如果能在提交问题时,有条件提供个"
  },
  {
    "path": "app/.gitignore",
    "chars": 7,
    "preview": "/build\n"
  },
  {
    "path": "app/build.gradle",
    "chars": 1840,
    "preview": "apply plugin: 'com.android.application'\n\nandroid {\n    compileSdk 33\n\n    defaultConfig {\n        applicationId \"com.tes"
  },
  {
    "path": "app/proguard-rules.pro",
    "chars": 2210,
    "preview": "#指定代码的压缩级别\n-optimizationpasses 5\n#包明不混合大小写\n-dontusemixedcaseclassnames\n#不去忽略非公共的库类\n-dontskipnonpubliclibraryclasses\n#优化 "
  },
  {
    "path": "app/src/main/AndroidManifest.xml",
    "chars": 1289,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package="
  },
  {
    "path": "app/src/main/java/com/test/banner/MainActivity.java",
    "chars": 7765,
    "preview": "package com.test.banner;\n\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport and"
  },
  {
    "path": "app/src/main/java/com/test/banner/adapter/ImageAdapter.java",
    "chars": 1416,
    "preview": "package com.test.banner.adapter;\n\nimport android.view.ViewGroup;\nimport android.widget.ImageView;\n\nimport com.test.banne"
  },
  {
    "path": "app/src/main/java/com/test/banner/adapter/ImageNetAdapter.java",
    "chars": 2110,
    "preview": "package com.test.banner.adapter;\n\nimport android.graphics.Bitmap;\nimport android.graphics.Outline;\nimport android.graphi"
  },
  {
    "path": "app/src/main/java/com/test/banner/adapter/ImageTitleAdapter.java",
    "chars": 995,
    "preview": "package com.test.banner.adapter;\n\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.View"
  },
  {
    "path": "app/src/main/java/com/test/banner/adapter/ImageTitleNumAdapter.java",
    "chars": 1892,
    "preview": "package com.test.banner.adapter;\n\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.View"
  },
  {
    "path": "app/src/main/java/com/test/banner/adapter/MultipleTypesAdapter.java",
    "chars": 3325,
    "preview": "package com.test.banner.adapter;\n\nimport android.content.Context;\nimport android.graphics.Color;\nimport android.util.Spa"
  },
  {
    "path": "app/src/main/java/com/test/banner/adapter/MyRecyclerViewAdapter.java",
    "chars": 3537,
    "preview": "package com.test.banner.adapter;\n\nimport android.content.Context;\nimport android.graphics.Color;\nimport android.util.Log"
  },
  {
    "path": "app/src/main/java/com/test/banner/adapter/TopLineAdapter.java",
    "chars": 1503,
    "preview": "package com.test.banner.adapter;\n\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.TextVie"
  },
  {
    "path": "app/src/main/java/com/test/banner/bean/DataBean.java",
    "chars": 4455,
    "preview": "package com.test.banner.bean;\n\nimport com.test.banner.R;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java"
  },
  {
    "path": "app/src/main/java/com/test/banner/indicator/NumIndicator.java",
    "chars": 1920,
    "preview": "package com.test.banner.indicator;\n\nimport android.content.Context;\nimport android.graphics.Canvas;\nimport android.graph"
  },
  {
    "path": "app/src/main/java/com/test/banner/ui/BannerFragment.java",
    "chars": 1647,
    "preview": "package com.test.banner.ui;\n\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimp"
  },
  {
    "path": "app/src/main/java/com/test/banner/ui/BannerListFragment.java",
    "chars": 1569,
    "preview": "package com.test.banner.ui;\n\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimp"
  },
  {
    "path": "app/src/main/java/com/test/banner/ui/BlankFragment.java",
    "chars": 1844,
    "preview": "package com.test.banner.ui;\n\nimport android.os.Bundle;\nimport android.view.Gravity;\nimport android.view.LayoutInflater;\n"
  },
  {
    "path": "app/src/main/java/com/test/banner/ui/ConstraintLayoutBannerActivity.java",
    "chars": 1504,
    "preview": "package com.test.banner.ui;\n\nimport android.os.Bundle;\nimport android.util.Log;\nimport android.view.KeyEvent;\n\nimport an"
  },
  {
    "path": "app/src/main/java/com/test/banner/ui/GalleryActivity.java",
    "chars": 1647,
    "preview": "package com.test.banner.ui;\n\nimport android.os.Bundle;\nimport android.view.View;\n\nimport com.test.banner.R;\nimport com.t"
  },
  {
    "path": "app/src/main/java/com/test/banner/ui/RecyclerViewBannerActivity.java",
    "chars": 932,
    "preview": "package com.test.banner.ui;\n\nimport android.os.Bundle;\nimport android.view.View;\nimport android.widget.TextView;\n\nimport"
  },
  {
    "path": "app/src/main/java/com/test/banner/ui/TVActivity.java",
    "chars": 2183,
    "preview": "package com.test.banner.ui;\n\nimport androidx.appcompat.app.AppCompatActivity;\n\nimport android.os.Bundle;\nimport android."
  },
  {
    "path": "app/src/main/java/com/test/banner/ui/TouTiaoActivity.java",
    "chars": 1215,
    "preview": "package com.test.banner.ui;\n\nimport androidx.appcompat.app.AppCompatActivity;\nimport butterknife.BindView;\nimport butter"
  },
  {
    "path": "app/src/main/java/com/test/banner/ui/VideoActivity.java",
    "chars": 3128,
    "preview": "package com.test.banner.ui;\n\nimport android.os.Bundle;\nimport android.util.Log;\n\nimport com.shuyu.gsyvideoplayer.GSYVide"
  },
  {
    "path": "app/src/main/java/com/test/banner/ui/Vp2FragmentRecyclerviewActivity.java",
    "chars": 2043,
    "preview": "package com.test.banner.ui;\n\nimport android.os.Bundle;\n\nimport com.google.android.material.tabs.TabLayout;\nimport com.te"
  },
  {
    "path": "app/src/main/java/com/test/banner/util/ParentRecyclerView.java",
    "chars": 1398,
    "preview": "package com.test.banner.util;\n\nimport android.content.Context;\nimport android.util.AttributeSet;\nimport android.view.Mot"
  },
  {
    "path": "app/src/main/java/com/test/banner/util/TabLayoutMediator.java",
    "chars": 14220,
    "preview": "package com.test.banner.util;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx."
  },
  {
    "path": "app/src/main/java/com/test/banner/viewholder/ImageHolder.java",
    "chars": 392,
    "preview": "package com.test.banner.viewholder;\n\nimport android.view.View;\nimport android.widget.ImageView;\n\nimport androidx.annotat"
  },
  {
    "path": "app/src/main/java/com/test/banner/viewholder/ImageTitleHolder.java",
    "chars": 550,
    "preview": "package com.test.banner.viewholder;\n\nimport android.view.View;\nimport android.widget.ImageView;\nimport android.widget.Te"
  },
  {
    "path": "app/src/main/java/com/test/banner/viewholder/TitleHolder.java",
    "chars": 457,
    "preview": "package com.test.banner.viewholder;\n\nimport android.view.View;\nimport android.widget.ImageView;\nimport android.widget.Te"
  },
  {
    "path": "app/src/main/java/com/test/banner/viewholder/VideoHolder.java",
    "chars": 465,
    "preview": "package com.test.banner.viewholder;\n\nimport android.view.View;\n\nimport androidx.annotation.NonNull;\nimport androidx.recy"
  },
  {
    "path": "app/src/main/res/drawable/background.xml",
    "chars": 224,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <gradient\n"
  },
  {
    "path": "app/src/main/res/drawable/default_selecter.xml",
    "chars": 335,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item a"
  },
  {
    "path": "app/src/main/res/drawable/green.xml",
    "chars": 377,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:sha"
  },
  {
    "path": "app/src/main/res/drawable/selected_radius.xml",
    "chars": 224,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:sha"
  },
  {
    "path": "app/src/main/res/drawable/unselected_radius.xml",
    "chars": 214,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:sha"
  },
  {
    "path": "app/src/main/res/drawable/white.xml",
    "chars": 184,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:sha"
  },
  {
    "path": "app/src/main/res/layout/activity_constraint_layout_banner.xml",
    "chars": 1224,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas."
  },
  {
    "path": "app/src/main/res/layout/activity_gallery.xml",
    "chars": 1425,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    "
  },
  {
    "path": "app/src/main/res/layout/activity_main.xml",
    "chars": 6253,
    "preview": "<androidx.swiperefreshlayout.widget.SwipeRefreshLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n  "
  },
  {
    "path": "app/src/main/res/layout/activity_recyclerview_banner.xml",
    "chars": 662,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    andr"
  },
  {
    "path": "app/src/main/res/layout/activity_t_v.xml",
    "chars": 1301,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas."
  },
  {
    "path": "app/src/main/res/layout/activity_tou_tiao.xml",
    "chars": 1942,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout\n    xmlns:android=\"http://sche"
  },
  {
    "path": "app/src/main/res/layout/activity_video.xml",
    "chars": 667,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas."
  },
  {
    "path": "app/src/main/res/layout/activity_vp2_fragment_recyclerview.xml",
    "chars": 2609,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=\"http://schema"
  },
  {
    "path": "app/src/main/res/layout/banner.xml",
    "chars": 449,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmln"
  },
  {
    "path": "app/src/main/res/layout/banner_image.xml",
    "chars": 254,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ImageView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android"
  },
  {
    "path": "app/src/main/res/layout/banner_image_title.xml",
    "chars": 879,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    an"
  },
  {
    "path": "app/src/main/res/layout/banner_image_title_num.xml",
    "chars": 1476,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    an"
  },
  {
    "path": "app/src/main/res/layout/banner_title.xml",
    "chars": 495,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    an"
  },
  {
    "path": "app/src/main/res/layout/banner_video.xml",
    "chars": 393,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    andro"
  },
  {
    "path": "app/src/main/res/layout/item.xml",
    "chars": 679,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.cardview.widget.CardView xmlns:android=\"http://schemas.android.com/apk/"
  },
  {
    "path": "app/src/main/res/layout/test.xml",
    "chars": 549,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    andr"
  },
  {
    "path": "app/src/main/res/layout/top_line_item2.xml",
    "chars": 1240,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    an"
  },
  {
    "path": "app/src/main/res/values/arrays.xml",
    "chars": 3750,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <array name=\"url\">\n        <item>http://ww4.sinaimg.cn/large/006u"
  },
  {
    "path": "app/src/main/res/values/colors.xml",
    "chars": 330,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"colorPrimary\">@color/main_color</color>\n    <color n"
  },
  {
    "path": "app/src/main/res/values/dimens.xml",
    "chars": 211,
    "preview": "<resources>\n    <!-- Default screen margins, per the Android Design guidelines. -->\n    <dimen name=\"activity_horizontal"
  },
  {
    "path": "app/src/main/res/values/strings.xml",
    "chars": 70,
    "preview": "<resources>\n    <string name=\"app_name\">Banner</string>\n\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/styles.xml",
    "chars": 383,
    "preview": "<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.DarkActionBar"
  },
  {
    "path": "app/src/main/res/values-w820dp/dimens.xml",
    "chars": 358,
    "preview": "<resources>\n    <!-- Example customization of dimensions originally defined in res/values/dimens.xml\n         (such as s"
  },
  {
    "path": "banner/.gitignore",
    "chars": 7,
    "preview": "/build\n"
  },
  {
    "path": "banner/build.gradle",
    "chars": 2899,
    "preview": "apply plugin: 'com.android.library'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\nversion = '2.2.3'\n\nandroid {\n"
  },
  {
    "path": "banner/proguard-rules.pro",
    "chars": 251,
    "preview": "-dontwarn androidx.viewpager2.**\n-keep class androidx.viewpager2.** {*;}\n-dontwarn androidx.recyclerview.widget.Recycler"
  },
  {
    "path": "banner/src/main/AndroidManifest.xml",
    "chars": 155,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package="
  },
  {
    "path": "banner/src/main/java/com/youth/banner/Banner.java",
    "chars": 33909,
    "preview": "package com.youth.banner;\n\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.graphic"
  },
  {
    "path": "banner/src/main/java/com/youth/banner/adapter/BannerAdapter.java",
    "chars": 3606,
    "preview": "package com.youth.banner.adapter;\n\nimport android.view.ViewGroup;\n\nimport androidx.annotation.NonNull;\nimport androidx.r"
  },
  {
    "path": "banner/src/main/java/com/youth/banner/adapter/BannerImageAdapter.java",
    "chars": 924,
    "preview": "package com.youth.banner.adapter;\n\nimport android.view.ViewGroup;\nimport android.widget.ImageView;\n\nimport com.youth.ban"
  },
  {
    "path": "banner/src/main/java/com/youth/banner/config/BannerConfig.java",
    "chars": 2381,
    "preview": "package com.youth.banner.config;\n\nimport com.youth.banner.util.BannerUtils;\n\n/**\n * 不忘初心\n *\n * ┌───┐   ┌───┬───┬───┬───┐"
  },
  {
    "path": "banner/src/main/java/com/youth/banner/config/IndicatorConfig.java",
    "chars": 4240,
    "preview": "package com.youth.banner.config;\n\nimport androidx.annotation.ColorInt;\nimport androidx.annotation.IntDef;\n\nimport java.l"
  },
  {
    "path": "banner/src/main/java/com/youth/banner/holder/BannerImageHolder.java",
    "chars": 402,
    "preview": "package com.youth.banner.holder;\n\nimport android.view.View;\nimport android.widget.ImageView;\n\nimport androidx.annotation"
  },
  {
    "path": "banner/src/main/java/com/youth/banner/holder/IViewHolder.java",
    "chars": 452,
    "preview": "package com.youth.banner.holder;\n\nimport android.view.ViewGroup;\n\npublic interface IViewHolder<T, VH> {\n\n    /**\n     * "
  },
  {
    "path": "banner/src/main/java/com/youth/banner/indicator/BaseIndicator.java",
    "chars": 3104,
    "preview": "package com.youth.banner.indicator;\n\nimport android.content.Context;\nimport android.graphics.Color;\nimport android.graph"
  },
  {
    "path": "banner/src/main/java/com/youth/banner/indicator/CircleIndicator.java",
    "chars": 2744,
    "preview": "package com.youth.banner.indicator;\n\nimport android.content.Context;\nimport android.graphics.Canvas;\nimport android.util"
  },
  {
    "path": "banner/src/main/java/com/youth/banner/indicator/DrawableIndicator.java",
    "chars": 2846,
    "preview": "package com.youth.banner.indicator;\n\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport andro"
  },
  {
    "path": "banner/src/main/java/com/youth/banner/indicator/Indicator.java",
    "chars": 408,
    "preview": "package com.youth.banner.indicator;\n\nimport android.view.View;\n\nimport androidx.annotation.NonNull;\n\nimport com.youth.ba"
  },
  {
    "path": "banner/src/main/java/com/youth/banner/indicator/RectangleIndicator.java",
    "chars": 2017,
    "preview": "package com.youth.banner.indicator;\n\nimport android.content.Context;\nimport android.graphics.Canvas;\nimport android.grap"
  },
  {
    "path": "banner/src/main/java/com/youth/banner/indicator/RoundLinesIndicator.java",
    "chars": 1763,
    "preview": "package com.youth.banner.indicator;\n\nimport android.content.Context;\nimport android.graphics.Canvas;\nimport android.grap"
  },
  {
    "path": "banner/src/main/java/com/youth/banner/itemdecoration/MarginDecoration.java",
    "chars": 1432,
    "preview": "package com.youth.banner.itemdecoration;\n\nimport android.graphics.Rect;\nimport android.view.View;\n\nimport androidx.annot"
  },
  {
    "path": "banner/src/main/java/com/youth/banner/listener/OnBannerListener.java",
    "chars": 216,
    "preview": "package com.youth.banner.listener;\n\npublic interface OnBannerListener<T> {\n\n    /**\n     * 点击事件\n     *\n     * @param dat"
  },
  {
    "path": "banner/src/main/java/com/youth/banner/listener/OnPageChangeListener.java",
    "chars": 1563,
    "preview": "package com.youth.banner.listener;\n\nimport androidx.annotation.Px;\nimport androidx.viewpager2.widget.ViewPager2;\n\n\npubli"
  },
  {
    "path": "banner/src/main/java/com/youth/banner/transformer/AlphaPageTransformer.java",
    "chars": 1125,
    "preview": "package com.youth.banner.transformer;\n\nimport android.view.View;\n\nimport androidx.annotation.NonNull;\n\npublic class Alph"
  },
  {
    "path": "banner/src/main/java/com/youth/banner/transformer/BasePageTransformer.java",
    "chars": 225,
    "preview": "package com.youth.banner.transformer;\n\nimport androidx.viewpager2.widget.ViewPager2;\n\npublic abstract class BasePageTran"
  },
  {
    "path": "banner/src/main/java/com/youth/banner/transformer/DepthPageTransformer.java",
    "chars": 1721,
    "preview": "package com.youth.banner.transformer;\n\nimport android.view.View;\n\nimport androidx.viewpager2.widget.ViewPager2;\n\npublic "
  },
  {
    "path": "banner/src/main/java/com/youth/banner/transformer/MZScaleInTransformer.java",
    "chars": 2772,
    "preview": "package com.youth.banner.transformer;\n\nimport android.view.View;\nimport android.view.ViewParent;\n\nimport androidx.annota"
  },
  {
    "path": "banner/src/main/java/com/youth/banner/transformer/RotateDownPageTransformer.java",
    "chars": 1544,
    "preview": "package com.youth.banner.transformer;\n\nimport android.view.View;\n\nimport androidx.annotation.NonNull;\n\npublic class Rota"
  },
  {
    "path": "banner/src/main/java/com/youth/banner/transformer/RotateUpPageTransformer.java",
    "chars": 1586,
    "preview": "package com.youth.banner.transformer;\n\nimport android.view.View;\n\nimport androidx.annotation.NonNull;\n\npublic class Rota"
  },
  {
    "path": "banner/src/main/java/com/youth/banner/transformer/RotateYTransformer.java",
    "chars": 1527,
    "preview": "package com.youth.banner.transformer;\n\nimport android.view.View;\n\nimport androidx.annotation.NonNull;\n\npublic class Rota"
  },
  {
    "path": "banner/src/main/java/com/youth/banner/transformer/ScaleInTransformer.java",
    "chars": 2016,
    "preview": "package com.youth.banner.transformer;\n\nimport android.view.View;\nimport android.view.ViewParent;\n\nimport androidx.annota"
  },
  {
    "path": "banner/src/main/java/com/youth/banner/transformer/ZoomOutPageTransformer.java",
    "chars": 1886,
    "preview": "package com.youth.banner.transformer;\n\nimport android.view.View;\n\nimport androidx.viewpager2.widget.ViewPager2;\n\n\npublic"
  },
  {
    "path": "banner/src/main/java/com/youth/banner/util/BannerLifecycleObserver.java",
    "chars": 315,
    "preview": "package com.youth.banner.util;\n\nimport androidx.lifecycle.LifecycleObserver;\nimport androidx.lifecycle.LifecycleOwner;\n\n"
  },
  {
    "path": "banner/src/main/java/com/youth/banner/util/BannerLifecycleObserverAdapter.java",
    "chars": 1047,
    "preview": "package com.youth.banner.util;\n\nimport androidx.lifecycle.Lifecycle;\nimport androidx.lifecycle.LifecycleObserver;\nimport"
  },
  {
    "path": "banner/src/main/java/com/youth/banner/util/BannerUtils.java",
    "chars": 2300,
    "preview": "package com.youth.banner.util;\n\nimport android.content.res.Resources;\nimport android.graphics.Outline;\nimport android.os"
  },
  {
    "path": "banner/src/main/java/com/youth/banner/util/LogUtils.java",
    "chars": 765,
    "preview": "package com.youth.banner.util;\n\nimport android.util.Log;\n\nimport com.youth.banner.BuildConfig;\n\npublic class LogUtils {\n"
  },
  {
    "path": "banner/src/main/java/com/youth/banner/util/ScrollSpeedManger.java",
    "chars": 3132,
    "preview": "package com.youth.banner.util;\n\nimport androidx.recyclerview.widget.LinearLayoutManager;\nimport androidx.recyclerview.wi"
  },
  {
    "path": "banner/src/main/res/values/attr.xml",
    "chars": 2174,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <declare-styleable name=\"Banner\">\n        <attr name=\"banner_loop"
  },
  {
    "path": "banner/src/main/res/values/ids.xml",
    "chars": 152,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <item name=\"banner_data_key\" type=\"id\"/>\n    <item name=\"banner_p"
  },
  {
    "path": "banner/src/main/res/values/strings.xml",
    "chars": 203,
    "preview": "<resources>\n    <string name=\"indicator_color_error\">indicator color attribute : “@color/colorID or #000000”</string>\n  "
  },
  {
    "path": "build.gradle",
    "chars": 1003,
    "preview": "\nbuildscript {\n    ext {\n        kotlin_version = '1.7.0'\n    }\n    repositories {\n        maven { url 'https://maven.al"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "chars": 200,
    "preview": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributi"
  },
  {
    "path": "settings.gradle",
    "chars": 54,
    "preview": "include ':app'\ninclude ':banner'\ninclude ':usekotlin'\n"
  },
  {
    "path": "update_message.md",
    "chars": 2648,
    "preview": "\n## 更新说明\n#### v2.2.3\n    * 修改adapter 数据相关操作方法\n    * banner 去掉泛型返回\n    * demo 添加更新数据注释\n    * 更新viewpager2到beta2\n\n#### v2."
  },
  {
    "path": "usekotlin/.gitignore",
    "chars": 7,
    "preview": "/build\n"
  },
  {
    "path": "usekotlin/build.gradle",
    "chars": 1361,
    "preview": "apply plugin: 'com.android.application'\napply plugin: 'kotlin-android'\napply plugin: 'kotlin-android-extensions'\n\nandroi"
  },
  {
    "path": "usekotlin/consumer-rules.pro",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "usekotlin/proguard-rules.pro",
    "chars": 751,
    "preview": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguar"
  },
  {
    "path": "usekotlin/src/androidTest/java/com/spring/usekotlin/ExampleInstrumentedTest.kt",
    "chars": 673,
    "preview": "package com.spring.usekotlin\n\nimport androidx.test.platform.app.InstrumentationRegistry\nimport androidx.test.ext.junit.r"
  },
  {
    "path": "usekotlin/src/main/AndroidManifest.xml",
    "chars": 749,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package="
  },
  {
    "path": "usekotlin/src/main/java/com/spring/usekotlin/ImageAdapter.kt",
    "chars": 1198,
    "preview": "package com.spring.usekotlin\n\nimport android.view.View\nimport android.view.ViewGroup\nimport android.widget.ImageView\nimp"
  },
  {
    "path": "usekotlin/src/main/java/com/spring/usekotlin/MainActivity.kt",
    "chars": 1936,
    "preview": "package com.spring.usekotlin\n\nimport android.os.Bundle\nimport androidx.appcompat.app.AppCompatActivity\nimport com.bumpte"
  },
  {
    "path": "usekotlin/src/main/res/layout/activity_main.xml",
    "chars": 886,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout\n    xmlns:android=\"http://sche"
  },
  {
    "path": "usekotlin/src/main/res/values/colors.xml",
    "chars": 330,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"colorPrimary\">@color/main_color</color>\n    <color n"
  },
  {
    "path": "usekotlin/src/main/res/values/strings.xml",
    "chars": 84,
    "preview": "<resources>\n    <string name=\"app_name\">Banner kotlin Example</string>\n</resources>\n"
  },
  {
    "path": "usekotlin/src/main/res/values/styles.xml",
    "chars": 383,
    "preview": "<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.DarkActionBar"
  },
  {
    "path": "usekotlin/src/test/java/com/spring/usekotlin/ExampleUnitTest.kt",
    "chars": 345,
    "preview": "package com.spring.usekotlin\n\nimport org.junit.Test\n\nimport org.junit.Assert.*\n\n/**\n * Example local unit test, which wi"
  }
]

// ... and 1 more files (download for full content)

About this extraction

This page contains the full source code of the youth5201314/banner GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 118 files (219.4 KB), approximately 57.3k tokens, and a symbol index with 385 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!