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
================================================
================================================
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上一直稳定运行,如果真有严重问题肯定第一时间就修复了
```
Banner 1.4.10(还想看老版本的可以点击这里)
### 阔别已久,从新回归
* 首先我声明几点:
* 这只是一个开源库,如果满意你可以使用、可以借鉴修改,希望对你们有所帮助。
* 如果不满意请友好的提出,注明错误的详细信息或者修改建议,好的想法和自定义的东西亦可以直接提交,大家都能来一起完善。
* 如果你觉得实在是没用,也请你做一个有自我修养的人。
### 主要改进功能介绍
最开始是想上传以前基于viewpager更新好的版本,但是看着viewpager2正式版已经出来了,就上新的吧,viewpager2确实比viewpager性能好很多。
- [x] 使用了ViewPager2为基础控件 ViewPager2介绍
- [x] 支持了androidx兼容包
- [x] 方便了UI、Indicator自定义
- [x] 支持画廊效果、魅族效果
- [x] 兼容了水平和垂直轮播,也可以实现类似淘宝头条的效果
- [x] 依赖包目前只需要导入了ViewPager2
### 效果图
更多效果运行demo查看




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


|内置的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)|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
```
#### Step 3.在布局文件中添加Banner,可以设置自定义属性
!!!此步骤可以省略,可以直接在Activity或者Fragment中new Banner();
```xml
```
#### Step 4.继承BannerAdapter,和RecyclerView的Adapter一样(如果你只是图片轮播也可以使用默认的)
!!!此步骤可以省略,图片轮播提供有默认适配器,其他的没有提供是因为大家的可变性要求不确定,所以直接自定义的比较好。
```java
/**
* 自定义布局,下面是常见的图片样式,更多实现可以看demo,可以自己随意发挥
*/
public class ImageAdapter extends BannerAdapter {
public ImageAdapter(List 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.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)
### 联系方式
* 我的个人微博:https://weibo.com/u/3013494003 有兴趣的也可以关注,大家一起交流
* 有问题可以加群大家一起交流,如果你觉得对你有帮助可以扫描下面支付宝二维码随意打赏下哦!
## 更新说明
[更新说明](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 (**, android.view.View); }
-keep class butterknife.*
-keepclasseswithmembernames class * { @butterknife.* ; }
-keepclasseswithmembernames class * { @butterknife.* ; }
-keepclassmembers class * { @butterknife.* ; }
-keepclassmembers class * { @butterknife.* ; }
#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 (android.content.Context);
public (android.content.Context, android.util.AttributeSet);
public (android.content.Context, android.util.AttributeSet, int);
}
-dontwarn com.google.android.exoplayer.**
-keep class com.google.android.exoplayer.**{*;}
================================================
FILE: app/src/main/AndroidManifest.xml
================================================
================================================
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 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.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 {
public ImageAdapter(List mDatas) {
//设置数据,也可以调用banner提供的方法,或者自己在adapter中实现
super(mDatas);
}
//更新数据
public void updateData(List 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 {
public ImageNetAdapter(List 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 {
public ImageTitleAdapter(List 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 {
public ImageTitleNumAdapter(List 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 {
private Context context;
private SparseArray mVHMap = new SparseArray<>();
public MultipleTypesAdapter(Context context, List 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 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 {
public TopLineAdapter(List 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 getTestData() {
List 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 getTestData2() {
List 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 getTestDataVideo() {
List 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 getTestData3() {
List 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 getVideos() {
List 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 getColors(int size) {
List 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.
*
*
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 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
================================================
================================================
FILE: app/src/main/res/drawable/default_selecter.xml
================================================
================================================
FILE: app/src/main/res/drawable/green.xml
================================================
================================================
FILE: app/src/main/res/drawable/selected_radius.xml
================================================
================================================
FILE: app/src/main/res/drawable/unselected_radius.xml
================================================
================================================
FILE: app/src/main/res/drawable/white.xml
================================================
================================================
FILE: app/src/main/res/layout/activity_constraint_layout_banner.xml
================================================
================================================
FILE: app/src/main/res/layout/activity_gallery.xml
================================================
================================================
FILE: app/src/main/res/layout/activity_main.xml
================================================
================================================
FILE: app/src/main/res/layout/activity_recyclerview_banner.xml
================================================
================================================
FILE: app/src/main/res/layout/activity_t_v.xml
================================================
================================================
FILE: app/src/main/res/layout/activity_tou_tiao.xml
================================================
================================================
FILE: app/src/main/res/layout/activity_video.xml
================================================
================================================
FILE: app/src/main/res/layout/activity_vp2_fragment_recyclerview.xml
================================================
================================================
FILE: app/src/main/res/layout/banner.xml
================================================
================================================
FILE: app/src/main/res/layout/banner_image.xml
================================================
================================================
FILE: app/src/main/res/layout/banner_image_title.xml
================================================
================================================
FILE: app/src/main/res/layout/banner_image_title_num.xml
================================================
================================================
FILE: app/src/main/res/layout/banner_title.xml
================================================
================================================
FILE: app/src/main/res/layout/banner_video.xml
================================================
================================================
FILE: app/src/main/res/layout/item.xml
================================================
================================================
FILE: app/src/main/res/layout/test.xml
================================================
================================================
FILE: app/src/main/res/layout/top_line_item2.xml
================================================
================================================
FILE: app/src/main/res/values/arrays.xml
================================================
http://ww4.sinaimg.cn/large/006uZZy8jw1faic1xjab4j30ci08cjrv.jpghttp://ww4.sinaimg.cn/large/006uZZy8jw1faic21363tj30ci08ct96.jpghttp://ww4.sinaimg.cn/large/006uZZy8jw1faic259ohaj30ci08c74r.jpghttp://ww4.sinaimg.cn/large/006uZZy8jw1faic2b16zuj30ci08cwf4.jpghttp://ww4.sinaimg.cn/large/006uZZy8jw1faic2e7vsaj30ci08cglz.jpghttp://img.zcool.cn/community/01700557a7f42f0000018c1bd6eb23.jpghttp://img.zcool.cn/community/01d28457d621800000018c1bb7877e.jpghttp://img.zcool.cn/community/01ae5656e1427f6ac72531cb72bac5.jpghttp://img.zcool.cn/community/01b72057a7e0790000018c1bf4fce0.pnghttp://img.zcool.cn/community/01fca557a7f5f90000012e7e9feea8.jpghttp://img.zcool.cn/community/01996b57a7f6020000018c1bedef97.jpghttp://img.zcool.cn/community/01700557a7f42f0000018c1bd6eb23.jpghttp://bpic.588ku.com/element_origin_min_pic/00/00/05/115732f19cc0079.jpghttp://bpic.588ku.com/element_origin_min_pic/00/00/05/115732f1ac12d1d.jpghttp://bpic.588ku.com/element_origin_min_pic/00/00/05/115732f1bad97d1.jpghttp://bpic.588ku.com/element_origin_min_pic/00/00/05/115732f1c83c228.jpghttp://bpic.588ku.com/element_origin_min_pic/00/00/05/115732f1d53e3dd.jpghttp://bpic.588ku.com/element_origin_min_pic/00/00/05/115732f1e37fea9.jpghttp://bpic.588ku.com/element_origin_min_pic/00/00/05/115732f1ef4d709.jpghttp://bpic.588ku.com/element_origin_min_pic/00/00/05/115732f20b3ea10.jpghttp://bpic.588ku.com/element_origin_min_pic/00/00/05/115732f21927f8d.jpg51巅峰钜惠十大星级品牌联盟,全场2折起生命不是要超越别人,而是要超越自己。己所不欲,勿施于人。——孔子嗨购5折不要停banner动画预览banner内置样式预览banner指示器位置设置预览banner一些自定义样式方法预览banner加载本地图片banner自定义布局文件(这里通过修改ViewPager举一反三吧)!!banner更多用法请看文档,这里就不一一列举了!DefaultAccordionBackgroundToForegroundForegroundToBackgroundCubeInCubeOutDepthPageFlipHorizontalFlipVerticalRotateDownRotateUpScaleInOutStackTabletZoomInZoomOutZoomOutSlideNOT_INDICATORCIRCLE_INDICATORNUM_INDICATORNUM_INDICATOR_TITLECIRCLE_INDICATOR_TITLECIRCLE_INDICATOR_TITLE_INSIDELEFTCENTERRIGHT
================================================
FILE: app/src/main/res/values/colors.xml
================================================
@color/main_color@color/main_color@color/main_color#BDBDBD#5CB85C
================================================
FILE: app/src/main/res/values/dimens.xml
================================================
16dp16dp
================================================
FILE: app/src/main/res/values/strings.xml
================================================
Banner
================================================
FILE: app/src/main/res/values/styles.xml
================================================
================================================
FILE: app/src/main/res/values-w820dp/dimens.xml
================================================
64dp
================================================
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
================================================
================================================
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> 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 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 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 listener) {
if (getAdapter() != null) {
getAdapter().setOnBannerListener(listener);
}
return this;
}
/**
* 添加viewpager切换事件
*