├── .gitignore
├── README.md
├── build.gradle
├── demo
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── cn
│ │ └── bingoogolapple
│ │ └── bgabanner
│ │ └── demo
│ │ ├── App.java
│ │ ├── engine
│ │ └── Engine.java
│ │ ├── model
│ │ ├── BannerModel.java
│ │ └── RefreshModel.java
│ │ └── ui
│ │ └── activity
│ │ ├── FrescoDemoActivity.java
│ │ ├── GuideActivity.java
│ │ ├── ListViewDemoActivity.java
│ │ ├── MainActivity.java
│ │ └── RecyclerViewDemoActivity.java
│ └── res
│ ├── drawable-hdpi
│ ├── holder.png
│ ├── ic_launcher.png
│ ├── point_focused.png
│ ├── point_focused_big.png
│ ├── point_unfocused.png
│ └── point_unfocused_small.png
│ ├── drawable-mdpi
│ └── ic_launcher.png
│ ├── drawable-xhdpi
│ ├── ic_launcher.png
│ ├── uoko_guide_background_1.png
│ ├── uoko_guide_background_2.png
│ ├── uoko_guide_background_3.png
│ ├── uoko_guide_foreground_1.png
│ ├── uoko_guide_foreground_2.png
│ └── uoko_guide_foreground_3.png
│ ├── drawable-xxhdpi
│ └── ic_launcher.png
│ ├── drawable
│ ├── selector_banner_point.xml
│ ├── selector_banner_unequal.xml
│ ├── selector_btn_test.xml
│ └── shape_number_indicator_background.xml
│ ├── layout
│ ├── activity_fresco_demo.xml
│ ├── activity_guide.xml
│ ├── activity_listview_demo.xml
│ ├── activity_main.xml
│ ├── activity_recyclerview_demo.xml
│ ├── item_fresco.xml
│ ├── item_normal.xml
│ └── layout_header.xml
│ ├── values
│ ├── colors.xml
│ ├── dimens.xml
│ ├── strings.xml
│ ├── styles.xml
│ └── styles_base.xml
│ └── xml
│ └── network_security_config.xml
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── library
├── build.gradle
├── consumer-proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── cn
│ │ └── bingoogolapple
│ │ └── bgabanner
│ │ ├── BGABanner.java
│ │ ├── BGABannerScroller.java
│ │ ├── BGABannerUtil.java
│ │ ├── BGAGuideLinkageLayout.java
│ │ ├── BGALocalImageSize.java
│ │ ├── BGAOnNoDoubleClickListener.java
│ │ ├── BGAViewPager.java
│ │ └── transformer
│ │ ├── AccordionPageTransformer.java
│ │ ├── AlphaPageTransformer.java
│ │ ├── BGAPageTransformer.java
│ │ ├── CubePageTransformer.java
│ │ ├── DefaultPageTransformer.java
│ │ ├── DepthPageTransformer.java
│ │ ├── FadePageTransformer.java
│ │ ├── FlipPageTransformer.java
│ │ ├── RotatePageTransformer.java
│ │ ├── StackPageTransformer.java
│ │ ├── TransitionEffect.java
│ │ ├── ZoomCenterPageTransformer.java
│ │ ├── ZoomFadePageTransformer.java
│ │ ├── ZoomPageTransformer.java
│ │ └── ZoomStackPageTransformer.java
│ └── res
│ ├── drawable-xhdpi
│ ├── bga_banner_point_disabled.png
│ └── bga_banner_point_enabled.png
│ ├── drawable
│ ├── bga_banner_selector_point_hollow.xml
│ └── bga_banner_selector_point_solid.xml
│ ├── layout
│ └── bga_banner_item_image.xml
│ └── values
│ ├── attrs.xml
│ └── ids.xml
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.ap_
4 |
5 | # Files for the Dalvik VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # Generated files
12 | bin/
13 | gen/
14 |
15 | # Gradle files
16 | .gradle/
17 | build/
18 | /*/build/
19 |
20 | # Local configuration file (sdk path, etc)
21 | local.properties
22 |
23 | # Proguard folder generated by Eclipse
24 | proguard/
25 |
26 | # Log Files
27 | *.log
28 |
29 | # Eclipse project files
30 | .classpath
31 | .project
32 | .settings/
33 |
34 | # Intellij project files
35 | *.iml
36 | *.ipr
37 | *.iws
38 | .idea/
39 |
40 | # Mac system files
41 | .DS_Store
42 |
43 | *.keystore
44 |
45 | captures
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | :running:BGABanner-Android:running:
2 | ============
3 |
4 | ## 目录
5 |
6 | * [功能介绍](#功能介绍)
7 | * [效果图与示例 apk](#效果图与示例-apk)
8 | * [常见问题](#常见问题)
9 | * [使用](#使用)
10 | * [自定义属性说明](#自定义属性说明)
11 | * [关于我](#关于我)
12 | * [打赏支持](#打赏支持)
13 | * [License](#license)
14 |
15 | ## 功能介绍
16 |
17 | - [x] 引导界面导航效果
18 | - [x] 支持根据服务端返回的数据动态设置广告条的总页数
19 | - [x] 支持大于等于1页时的无限循环自动轮播、手指按下暂停轮播、抬起手指开始轮播
20 | - [x] 支持自定义指示器位置和广告文案位置
21 | - [x] 支持图片指示器和数字指示器
22 | - [x] 支持 ViewPager 各种切换动画
23 | - [x] 支持选中特定页面
24 | - [x] 支持监听 item 点击事件
25 | - [x] 加载网络数据时支持占位图设置,避免出现整个广告条空白的情况
26 | - [x] 多个 ViewPager 跟随滚动
27 |
28 | ## 效果图与示例 apk
29 |
30 | 
31 |
32 | [点击下载 BGABannerDemo.apk](http://fir.im/BGABannerDemo) 或扫描下面的二维码安装
33 |
34 | 
35 |
36 | ## 常见问题
37 |
38 | 1. 结合 Fresco 加载图片请参考 [FrescoDemoActivity](https://github.com/bingoogolapple/BGABanner-Android/blob/master/demo/src/main/java/cn/bingoogolapple/bgabanner/demo/ui/activity/FrescoDemoActivity.java)
39 | 2. 自定义 item 布局文件请参考 [FrescoDemoActivity](https://github.com/bingoogolapple/BGABanner-Android/blob/master/demo/src/main/java/cn/bingoogolapple/bgabanner/demo/ui/activity/FrescoDemoActivity.java)
40 |
41 | ## 使用
42 |
43 | ### 1.添加 Gradle 依赖
44 |
45 | * 把 `maven { url 'https://jitpack.io' }` 添加到 root build.gradle 的 repositories 中
46 | * 在 app build.gradle 中添加如下依赖,末尾的「latestVersion」指的是徽章 [](https://jitpack.io/#bingoogolapple/BGABanner-Android) 里的版本名称,请自行替换
47 |
48 | ```groovy
49 | implementation 'androidx.legacy:legacy-support-v4:latestVersion'
50 | implementation 'com.github.bingoogolapple:BGABanner-Android:latestVersion'
51 | ```
52 |
53 | ### 2.在布局文件中添加 BGABanner
54 |
55 | ```xml
56 |
65 | ```
66 |
67 | ### 3.在 Activity 或者 Fragment 中配置 BGABanner 的数据源
68 |
69 | 有多种配置数据源的方式,这里仅列出三种方式。更多初始化方式请查看 [demo](https://github.com/bingoogolapple/BGABanner-Android/tree/master/demo)
70 |
71 | >配置数据源的方式1:通过传入数据模型并结合 Adapter 的方式配置数据源。这种方式主要用于加载网络图片,以及实现少于3页时的无限轮播
72 |
73 | ```java
74 | mContentBanner.setAdapter(new BGABanner.Adapter() {
75 | @Override
76 | public void fillBannerItem(BGABanner banner, ImageView itemView, String model, int position) {
77 | Glide.with(MainActivity.this)
78 | .load(model)
79 | .placeholder(R.drawable.holder)
80 | .error(R.drawable.holder)
81 | .centerCrop()
82 | .dontAnimate()
83 | .into(itemView);
84 | }
85 | });
86 |
87 | mContentBanner.setData(Arrays.asList("网络图片路径1", "网络图片路径2", "网络图片路径3"), Arrays.asList("提示文字1", "提示文字2", "提示文字3"));
88 | ```
89 |
90 | > 配置数据源的方式2:通过直接传入视图集合的方式配置数据源,主要用于自定义引导页每个页面布局的情况
91 |
92 | ```java
93 | List views = new ArrayList<>();
94 | views.add(View.inflate(context, R.layout.layout_guide_one, null));
95 | views.add(View.inflate(context, R.layout.layout_guide_two, null));
96 | views.add(View.inflate(context, R.layout.layout_guide_three, null));
97 | mContentBanner.setData(views);
98 | ```
99 |
100 | > 配置数据源的方式3:通过传入图片资源 id 的方式配置数据源,主要用于引导页每一页都是只显示图片的情况
101 |
102 | ```
103 | // Bitmap 的宽高在 maxWidth maxHeight 和 minWidth minHeight 之间
104 | BGALocalImageSize localImageSize = new BGALocalImageSize(720, 1280, 320, 640);
105 | // 设置数据源
106 | mContentBanner.setData(localImageSize, ImageView.ScaleType.CENTER_CROP,
107 | R.drawable.uoko_guide_background_1,
108 | R.drawable.uoko_guide_background_2,
109 | R.drawable.uoko_guide_background_3);
110 | ```
111 |
112 | ### 4.监听广告 item 的单击事件,在 BGABanner 里已经帮开发者处理了防止重复点击事件
113 |
114 | ```java
115 | mContentBanner.setDelegate(new BGABanner.Delegate() {
116 | @Override
117 | public void onBannerItemClick(BGABanner banner, ImageView itemView, String model, int position) {
118 | Toast.makeText(banner.getContext(), "点击了" + position, Toast.LENGTH_SHORT).show();
119 | }
120 | });
121 | ```
122 |
123 | ### 5.设置「进入按钮」和「跳过按钮」控件资源 id 及其点击事件,如果进入按钮和跳过按钮有一个不存在的话就传 0,在 BGABanner 里已经帮开发者处理了防止重复点击事件,在 BGABanner 里已经帮开发者处理了「跳过按钮」和「进入按钮」的显示与隐藏
124 |
125 | ```java
126 | mContentBanner.setEnterSkipViewIdAndDelegate(R.id.btn_guide_enter, R.id.tv_guide_skip, new BGABanner.GuideDelegate() {
127 | @Override
128 | public void onClickEnterOrSkip() {
129 | startActivity(new Intent(GuideActivity.this, MainActivity.class));
130 | finish();
131 | }
132 | });
133 | ```
134 |
135 | ## 自定义属性说明
136 | ```xml
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 | ```
202 |
203 | ## 代码是最好的老师,更多详细用法请查看 [demo](https://github.com/bingoogolapple/BGABanner-Android/tree/master/demo):feet:
204 |
205 | ## 作者联系方式
206 |
207 | | 个人主页 | 邮箱 |
208 | | ------------- | ------------ |
209 | | bingoogolapple.cn | bingoogolapple@gmail.com |
210 |
211 | | 个人微信号 | 微信群 | 公众号 |
212 | | ------------ | ------------ | ------------ |
213 | |
|
|
|
214 |
215 | | 个人 QQ 号 | QQ 群 |
216 | | ------------ | ------------ |
217 | |
|
|
218 |
219 | ## 打赏支持作者
220 |
221 | 如果您觉得 BGA 系列开源库或工具软件帮您节省了大量的开发时间,可以扫描下方的二维码打赏支持。您的支持将鼓励我继续创作,打赏后还可以加我微信免费开通一年 [上帝小助手浏览器扩展/插件开发平台](https://github.com/bingoogolapple/bga-god-assistant-config) 的会员服务
222 |
223 | | 微信 | QQ | 支付宝 |
224 | | ------------- | ------------- | ------------- |
225 | |
|
|
|
226 |
227 | ## 作者项目推荐
228 |
229 | * 欢迎您使用我开发的第一个独立开发软件产品 [上帝小助手浏览器扩展/插件开发平台](https://github.com/bingoogolapple/bga-god-assistant-config)
230 |
231 | ## License
232 |
233 | Copyright 2015 bingoogolapple
234 |
235 | Licensed under the Apache License, Version 2.0 (the "License");
236 | you may not use this file except in compliance with the License.
237 | You may obtain a copy of the License at
238 |
239 | http://www.apache.org/licenses/LICENSE-2.0
240 |
241 | Unless required by applicable law or agreed to in writing, software
242 | distributed under the License is distributed on an "AS IS" BASIS,
243 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
244 | See the License for the specific language governing permissions and
245 | limitations under the License.
246 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | google()
7 | }
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:3.5.4'
10 | classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1'
11 | }
12 | }
13 |
14 | allprojects {
15 | repositories {
16 | maven { url 'https://jitpack.io' }
17 | jcenter()
18 | google()
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/demo/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion ANDROID_BUILD_SDK_VERSION as int
5 |
6 | defaultConfig {
7 | minSdkVersion ANDROID_BUILD_MIN_SDK_VERSION as int
8 | targetSdkVersion ANDROID_BUILD_TARGET_SDK_VERSION as int
9 | versionCode VERSION_CODE as int
10 | versionName VERSION_NAME
11 | }
12 |
13 | buildTypes {
14 | release {
15 | minifyEnabled true
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 |
20 | dataBinding {
21 | enabled = true
22 | }
23 | }
24 |
25 | dependencies {
26 | implementation project(':library')
27 |
28 | // -------------------- 以下两个库是必须依赖的 ----------------------------
29 | // implementation 'com.github.bingoogolapple:BGABanner-Android:3.0.1'
30 | implementation 'androidx.legacy:legacy-support-v4:1.0.0'
31 | // -------------------- 以上两个库是必须依赖的 ----------------------------
32 |
33 | // 以下几个库是演示案例所使用到的
34 | implementation 'androidx.appcompat:appcompat:1.1.0'
35 | implementation 'androidx.recyclerview:recyclerview:1.0.0'
36 | implementation 'androidx.cardview:cardview:1.0.0'
37 | implementation 'com.github.bumptech.glide:glide:4.7.1'
38 | implementation 'com.squareup.retrofit2:retrofit:2.4.0'
39 | implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
40 | implementation 'com.github.bingoogolapple:BGABaseAdapter-Android:2.0.1'
41 |
42 | implementation 'com.facebook.fresco:fresco:2.0.0'
43 | }
--------------------------------------------------------------------------------
/demo/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | ## ----------------------------------
2 | ## Okio 相关
3 | ## ----------------------------------
4 | -keep class sun.misc.Unsafe { *; }
5 | -dontwarn java.nio.file.*
6 | -dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
7 | -dontwarn okio.**
8 |
9 | ## ----------------------------------
10 | ## Retrofit 2.X 相关
11 | ## ----------------------------------
12 | -dontwarn retrofit2.**
13 | -keep class retrofit2.** { *; }
14 | -keepattributes Signature
15 | -keepattributes Exceptions
16 |
17 | -keepclasseswithmembers class * {
18 | @retrofit2.http.* ;
19 | }
20 |
21 | ## ----------------------------------
22 | ## RxJava 1.X 相关
23 | ## ----------------------------------
24 | -dontwarn sun.misc.**
25 |
26 | -keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* {
27 | long producerIndex;
28 | long consumerIndex;
29 | }
30 |
31 | -keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef {
32 | rx.internal.util.atomic.LinkedQueueNode producerNode;
33 | }
34 |
35 | -keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueConsumerNodeRef {
36 | rx.internal.util.atomic.LinkedQueueNode consumerNode;
37 | }
38 |
39 | ## ----------------------------------
40 | ## Glide 相关
41 | ## ----------------------------------
42 | -keep class com.bumptech.glide.Glide { *; }
43 | -keep public class * implements com.bumptech.glide.module.GlideModule
44 | -keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
45 | **[] $VALUES;
46 | public *;
47 | }
48 | -dontwarn com.bumptech.glide.**
49 |
50 | ## ----------------------------------
51 | ## Fresco 相关
52 | ## ----------------------------------
53 | -keep,allowobfuscation @interface com.facebook.common.internal.DoNotStrip
54 |
55 | # Do not strip any method/class that is annotated with @DoNotStrip
56 | -keep @com.facebook.common.internal.DoNotStrip class *
57 | -keepclassmembers class * {
58 | @com.facebook.common.internal.DoNotStrip *;
59 | }
60 |
61 | # Keep native methods
62 | -keepclassmembers class * {
63 | native ;
64 | }
65 |
66 | -dontwarn okio.**
67 | -dontwarn javax.annotation.**
68 | -dontwarn com.android.volley.toolbox.**
69 |
70 | ## ----------------------------------
71 | ## DataBinding 相关
72 | ## ----------------------------------
73 | -keepclasseswithmembers class * extends android.databinding.ViewDataBinding{
74 | ;
75 | }
76 |
77 | ## ----------------------------------
78 | ## 配置不混淆 Demo 里的 Model
79 | ## ----------------------------------
80 | -keep class cn.bingoogolapple.bgabanner.demo.model.**{*;}
--------------------------------------------------------------------------------
/demo/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
14 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
28 |
29 |
32 |
33 |
36 |
37 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/demo/src/main/java/cn/bingoogolapple/bgabanner/demo/App.java:
--------------------------------------------------------------------------------
1 | package cn.bingoogolapple.bgabanner.demo;
2 |
3 | import android.app.Application;
4 |
5 | import com.facebook.drawee.backends.pipeline.Fresco;
6 |
7 | import cn.bingoogolapple.bgabanner.demo.engine.Engine;
8 | import retrofit2.Retrofit;
9 | import retrofit2.converter.gson.GsonConverterFactory;
10 |
11 | /**
12 | * 作者:王浩 邮件:bingoogolapple@gmail.com
13 | * 创建时间:15/6/21 下午10:13
14 | * 描述:
15 | */
16 | public class App extends Application {
17 | private static App sInstance;
18 | private Engine mEngine;
19 |
20 | @Override
21 | public void onCreate() {
22 | super.onCreate();
23 |
24 | sInstance = this;
25 | mEngine = new Retrofit.Builder()
26 | .baseUrl("http://bgashare.bingoogolapple.cn/banner/api/")
27 | .addConverterFactory(GsonConverterFactory.create())
28 | .build().create(Engine.class);
29 |
30 | Fresco.initialize(this);
31 | }
32 |
33 |
34 | public static App getInstance() {
35 | return sInstance;
36 | }
37 |
38 | public Engine getEngine() {
39 | return mEngine;
40 | }
41 | }
--------------------------------------------------------------------------------
/demo/src/main/java/cn/bingoogolapple/bgabanner/demo/engine/Engine.java:
--------------------------------------------------------------------------------
1 | package cn.bingoogolapple.bgabanner.demo.engine;
2 |
3 | import java.util.List;
4 |
5 | import cn.bingoogolapple.bgabanner.demo.model.BannerModel;
6 | import cn.bingoogolapple.bgabanner.demo.model.RefreshModel;
7 | import retrofit2.Call;
8 | import retrofit2.http.GET;
9 | import retrofit2.http.Path;
10 | import retrofit2.http.Url;
11 |
12 |
13 | /**
14 | * 作者:王浩 邮件:bingoogolapple@gmail.com
15 | * 创建时间:15/9/17 下午12:44
16 | * 描述:
17 | */
18 | public interface Engine {
19 |
20 | @GET("{itemCount}item.json")
21 | Call fetchItemsWithItemCount(@Path("itemCount") int itemCount);
22 |
23 | @GET
24 | Call> loadContentData(@Url String url);
25 | }
--------------------------------------------------------------------------------
/demo/src/main/java/cn/bingoogolapple/bgabanner/demo/model/BannerModel.java:
--------------------------------------------------------------------------------
1 | package cn.bingoogolapple.bgabanner.demo.model;
2 |
3 | import java.util.List;
4 |
5 | /**
6 | * 作者:王浩 邮件:bingoogolapple@gmail.com
7 | * 创建时间:15/6/21 下午11:16
8 | * 描述:
9 | */
10 | public class BannerModel {
11 | public List imgs;
12 | public List tips;
13 | }
--------------------------------------------------------------------------------
/demo/src/main/java/cn/bingoogolapple/bgabanner/demo/model/RefreshModel.java:
--------------------------------------------------------------------------------
1 | package cn.bingoogolapple.bgabanner.demo.model;
2 |
3 | /**
4 | * 作者:王浩 邮件:bingoogolapple@gmail.com
5 | * 创建时间:15/5/21 14:53
6 | * 描述:
7 | */
8 | public class RefreshModel {
9 | public String title;
10 | public String detail;
11 |
12 | public RefreshModel() {
13 | }
14 |
15 | public RefreshModel(String title, String detail) {
16 | this.title = title;
17 | this.detail = detail;
18 | }
19 | }
--------------------------------------------------------------------------------
/demo/src/main/java/cn/bingoogolapple/bgabanner/demo/ui/activity/FrescoDemoActivity.java:
--------------------------------------------------------------------------------
1 | package cn.bingoogolapple.bgabanner.demo.ui.activity;
2 |
3 | import android.net.Uri;
4 | import android.os.Bundle;
5 | import androidx.annotation.Nullable;
6 | import androidx.appcompat.app.AppCompatActivity;
7 | import androidx.cardview.widget.CardView;
8 | import android.widget.Toast;
9 |
10 | import com.facebook.drawee.view.SimpleDraweeView;
11 |
12 | import cn.bingoogolapple.bgabanner.BGABanner;
13 | import cn.bingoogolapple.bgabanner.demo.App;
14 | import cn.bingoogolapple.bgabanner.demo.R;
15 | import cn.bingoogolapple.bgabanner.demo.model.BannerModel;
16 | import retrofit2.Call;
17 | import retrofit2.Callback;
18 | import retrofit2.Response;
19 |
20 | /**
21 | * 作者:王浩 邮件:bingoogolapple@gmail.com
22 | * 创建时间:16/12/12 下午10:37
23 | * 描述:
24 | */
25 | public class FrescoDemoActivity extends AppCompatActivity {
26 | private BGABanner mContentBanner;
27 |
28 | @Override
29 | protected void onCreate(@Nullable Bundle savedInstanceState) {
30 | super.onCreate(savedInstanceState);
31 | setContentView(R.layout.activity_fresco_demo);
32 | setTitle("FrescoDemo");
33 |
34 | mContentBanner = findViewById(R.id.banner_fresco_demo_content);
35 | mContentBanner.setDelegate(new BGABanner.Delegate() {
36 | @Override
37 | public void onBannerItemClick(BGABanner banner, CardView itemView, String model, int position) {
38 | Toast.makeText(banner.getContext(), "点击了第" + (position + 1) + "页", Toast.LENGTH_SHORT).show();
39 | }
40 | });
41 | mContentBanner.setAdapter(new BGABanner.Adapter() {
42 | @Override
43 | public void fillBannerItem(BGABanner banner, CardView itemView, String model, int position) {
44 | SimpleDraweeView simpleDraweeView = itemView.findViewById(R.id.sdv_item_fresco_content);
45 | simpleDraweeView.setImageURI(Uri.parse(model));
46 | }
47 | });
48 |
49 | App.getInstance().getEngine().fetchItemsWithItemCount(5).enqueue(new Callback() {
50 | @Override
51 | public void onResponse(Call call, Response response) {
52 | BannerModel bannerModel = response.body();
53 | // mContentBanner.setData(R.layout.item_fresco, bannerModel.imgs, bannerModel.tips);
54 | mContentBanner.setData(R.layout.item_fresco, bannerModel.imgs, null);
55 | }
56 |
57 | @Override
58 | public void onFailure(Call call, Throwable t) {
59 | Toast.makeText(App.getInstance(), "网络数据加载失败", Toast.LENGTH_SHORT).show();
60 | }
61 | });
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/demo/src/main/java/cn/bingoogolapple/bgabanner/demo/ui/activity/GuideActivity.java:
--------------------------------------------------------------------------------
1 | package cn.bingoogolapple.bgabanner.demo.ui.activity;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 | import android.widget.ImageView;
7 |
8 | import cn.bingoogolapple.bgabanner.BGABanner;
9 | import cn.bingoogolapple.bgabanner.BGALocalImageSize;
10 | import cn.bingoogolapple.bgabanner.demo.R;
11 |
12 | public class GuideActivity extends Activity {
13 | private static final String TAG = GuideActivity.class.getSimpleName();
14 | private BGABanner mBackgroundBanner;
15 | private BGABanner mForegroundBanner;
16 |
17 | @Override
18 | protected void onCreate(Bundle savedInstanceState) {
19 | super.onCreate(savedInstanceState);
20 |
21 | initView();
22 | setListener();
23 | processLogic();
24 | }
25 |
26 | private void initView() {
27 | setContentView(R.layout.activity_guide);
28 | mBackgroundBanner = findViewById(R.id.banner_guide_background);
29 | mForegroundBanner = findViewById(R.id.banner_guide_foreground);
30 | }
31 |
32 | private void setListener() {
33 | /**
34 | * 设置进入按钮和跳过按钮控件资源 id 及其点击事件
35 | * 如果进入按钮和跳过按钮有一个不存在的话就传 0
36 | * 在 BGABanner 里已经帮开发者处理了防止重复点击事件
37 | * 在 BGABanner 里已经帮开发者处理了「跳过按钮」和「进入按钮」的显示与隐藏
38 | */
39 | mForegroundBanner.setEnterSkipViewIdAndDelegate(R.id.btn_guide_enter, R.id.tv_guide_skip, new BGABanner.GuideDelegate() {
40 | @Override
41 | public void onClickEnterOrSkip() {
42 | startActivity(new Intent(GuideActivity.this, MainActivity.class));
43 | finish();
44 | }
45 | });
46 | }
47 |
48 | private void processLogic() {
49 | // Bitmap 的宽高在 maxWidth maxHeight 和 minWidth minHeight 之间
50 | BGALocalImageSize localImageSize = new BGALocalImageSize(720, 1280, 320, 640);
51 | // 设置数据源
52 | mBackgroundBanner.setData(localImageSize, ImageView.ScaleType.CENTER_CROP,
53 | R.drawable.uoko_guide_background_1,
54 | R.drawable.uoko_guide_background_2,
55 | R.drawable.uoko_guide_background_3);
56 |
57 | mForegroundBanner.setData(localImageSize, ImageView.ScaleType.CENTER_CROP,
58 | R.drawable.uoko_guide_foreground_1,
59 | R.drawable.uoko_guide_foreground_2,
60 | R.drawable.uoko_guide_foreground_3);
61 | }
62 |
63 | @Override
64 | protected void onResume() {
65 | super.onResume();
66 |
67 | // 如果开发者的引导页主题是透明的,需要在界面可见时给背景 Banner 设置一个白色背景,避免滑动过程中两个 Banner 都设置透明度后能看到 Launcher
68 | mBackgroundBanner.setBackgroundResource(android.R.color.white);
69 | }
70 | }
--------------------------------------------------------------------------------
/demo/src/main/java/cn/bingoogolapple/bgabanner/demo/ui/activity/ListViewDemoActivity.java:
--------------------------------------------------------------------------------
1 | package cn.bingoogolapple.bgabanner.demo.ui.activity;
2 |
3 | import android.content.Context;
4 | import android.os.Bundle;
5 | import android.view.View;
6 | import android.widget.ImageView;
7 | import android.widget.ListView;
8 | import android.widget.Toast;
9 |
10 | import com.bumptech.glide.Glide;
11 | import com.bumptech.glide.request.RequestOptions;
12 |
13 | import java.util.List;
14 |
15 | import androidx.appcompat.app.AppCompatActivity;
16 | import cn.bingoogolapple.baseadapter.BGAAdapterViewAdapter;
17 | import cn.bingoogolapple.baseadapter.BGAViewHolderHelper;
18 | import cn.bingoogolapple.bgabanner.BGABanner;
19 | import cn.bingoogolapple.bgabanner.demo.App;
20 | import cn.bingoogolapple.bgabanner.demo.R;
21 | import cn.bingoogolapple.bgabanner.demo.engine.Engine;
22 | import cn.bingoogolapple.bgabanner.demo.model.BannerModel;
23 | import cn.bingoogolapple.bgabanner.demo.model.RefreshModel;
24 | import retrofit2.Call;
25 | import retrofit2.Callback;
26 | import retrofit2.Response;
27 |
28 | /**
29 | * 作者:王浩 邮件:bingoogolapple@gmail.com
30 | * 创建时间:16/7/21 下午8:26
31 | * 描述:
32 | */
33 | public class ListViewDemoActivity extends AppCompatActivity implements BGABanner.Adapter, BGABanner.Delegate {
34 | private ListView mContentLv;
35 | private BGABanner mBanner;
36 | private ContentAdapter mContentAdapter;
37 |
38 | private Engine mEngine;
39 |
40 | @Override
41 | protected void onCreate(Bundle savedInstanceState) {
42 | super.onCreate(savedInstanceState);
43 | setContentView(R.layout.activity_listview_demo);
44 | mContentLv = findViewById(R.id.lv_content);
45 |
46 | setTitle("ListViewDemo");
47 | mEngine = App.getInstance().getEngine();
48 |
49 | initListView();
50 |
51 |
52 | loadBannerData();
53 | loadContentData();
54 | }
55 |
56 | /**
57 | * 初始化ListView
58 | */
59 | private void initListView() {
60 | // 初始化HeaderView
61 | View headerView = View.inflate(this, R.layout.layout_header, null);
62 | mBanner = headerView.findViewById(R.id.banner);
63 | mBanner.setAdapter(this);
64 | mBanner.setDelegate(this);
65 |
66 | // 初始化ListView
67 | mContentLv.addHeaderView(headerView);
68 | mContentAdapter = new ContentAdapter(this);
69 | mContentLv.setAdapter(mContentAdapter);
70 | }
71 |
72 | @Override
73 | public void fillBannerItem(BGABanner banner, ImageView itemView, String model, int position) {
74 | Glide.with(this)
75 | .load(model)
76 | .apply(new RequestOptions().placeholder(R.drawable.holder).error(R.drawable.holder).dontAnimate().centerCrop())
77 | .into(itemView);
78 | }
79 |
80 | @Override
81 | public void onBannerItemClick(BGABanner banner, ImageView imageView, String model, int position) {
82 | Toast.makeText(this, "点击了第" + (position + 1) + "页", Toast.LENGTH_SHORT).show();
83 | }
84 |
85 | /**
86 | * 加载头部广告条的数据
87 | */
88 | private void loadBannerData() {
89 | mEngine.fetchItemsWithItemCount(5).enqueue(new Callback() {
90 | @Override
91 | public void onResponse(Call call, Response response) {
92 | BannerModel bannerModel = response.body();
93 | mBanner.setData(bannerModel.imgs, bannerModel.tips);
94 | }
95 |
96 | @Override
97 | public void onFailure(Call call, Throwable t) {
98 | Toast.makeText(App.getInstance(), "加载广告条数据失败", Toast.LENGTH_SHORT).show();
99 | }
100 | });
101 | }
102 |
103 | /**
104 | * 加载内容列表数据
105 | */
106 | private void loadContentData() {
107 | mEngine.loadContentData("http://bgashare.bingoogolapple.cn/refreshlayout/api/defaultdata.json").enqueue(new Callback>() {
108 | @Override
109 | public void onResponse(Call> call, Response> response) {
110 | mContentAdapter.setData(response.body());
111 | }
112 |
113 | @Override
114 | public void onFailure(Call> call, Throwable t) {
115 | Toast.makeText(App.getInstance(), "加载内容数据失败", Toast.LENGTH_SHORT).show();
116 | }
117 | });
118 | }
119 |
120 | private class ContentAdapter extends BGAAdapterViewAdapter {
121 |
122 | public ContentAdapter(Context context) {
123 | super(context, R.layout.item_normal);
124 | }
125 |
126 | @Override
127 | protected void fillData(BGAViewHolderHelper helper, int position, RefreshModel model) {
128 | helper.setText(R.id.tv_item_normal_title, model.title).setText(R.id.tv_item_normal_detail, model.detail);
129 | }
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/demo/src/main/java/cn/bingoogolapple/bgabanner/demo/ui/activity/MainActivity.java:
--------------------------------------------------------------------------------
1 | package cn.bingoogolapple.bgabanner.demo.ui.activity;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import androidx.appcompat.app.AppCompatActivity;
6 | import android.view.View;
7 | import android.widget.ImageView;
8 | import android.widget.Toast;
9 |
10 | import com.bumptech.glide.Glide;
11 | import com.bumptech.glide.request.RequestOptions;
12 |
13 | import cn.bingoogolapple.bgabanner.BGABanner;
14 | import cn.bingoogolapple.bgabanner.demo.App;
15 | import cn.bingoogolapple.bgabanner.demo.R;
16 | import cn.bingoogolapple.bgabanner.demo.engine.Engine;
17 | import cn.bingoogolapple.bgabanner.demo.model.BannerModel;
18 | import cn.bingoogolapple.bgabanner.transformer.TransitionEffect;
19 | import retrofit2.Call;
20 | import retrofit2.Callback;
21 | import retrofit2.Response;
22 |
23 | public class MainActivity extends AppCompatActivity implements BGABanner.Delegate, BGABanner.Adapter {
24 | private BGABanner mDefaultBanner;
25 | private BGABanner mCubeBanner;
26 | private BGABanner mAccordionBanner;
27 | private BGABanner mFlipBanner;
28 | private BGABanner mRotateBanner;
29 | private BGABanner mAlphaBanner;
30 | private BGABanner mZoomFadeBanner;
31 | private BGABanner mFadeBanner;
32 | private BGABanner mZoomCenterBanner;
33 | private BGABanner mZoomBanner;
34 | private BGABanner mStackBanner;
35 | private BGABanner mZoomStackBanner;
36 | private BGABanner mDepthBanner;
37 |
38 | private Engine mEngine;
39 |
40 | @Override
41 | protected void onCreate(Bundle savedInstanceState) {
42 | super.onCreate(savedInstanceState);
43 | setContentView(R.layout.activity_main);
44 |
45 | setTitle("BGABannerDemo");
46 | mEngine = App.getInstance().getEngine();
47 |
48 | initView();
49 | setListener();
50 | loadData();
51 | }
52 |
53 | private void initView() {
54 | mDefaultBanner = findViewById(R.id.banner_main_default);
55 | mCubeBanner = findViewById(R.id.banner_main_cube);
56 | mAccordionBanner = findViewById(R.id.banner_main_accordion);
57 | mFlipBanner = findViewById(R.id.banner_main_flip);
58 | mRotateBanner = findViewById(R.id.banner_main_rotate);
59 | mAlphaBanner = findViewById(R.id.banner_main_alpha);
60 | mZoomFadeBanner = findViewById(R.id.banner_main_zoomFade);
61 | mFadeBanner = findViewById(R.id.banner_main_fade);
62 | mZoomCenterBanner = findViewById(R.id.banner_main_zoomCenter);
63 | mZoomBanner = findViewById(R.id.banner_main_zoom);
64 | mStackBanner = findViewById(R.id.banner_main_stack);
65 | mZoomStackBanner = findViewById(R.id.banner_main_zoomStack);
66 | mDepthBanner = findViewById(R.id.banner_main_depth);
67 | }
68 |
69 | private void setListener() {
70 | mDefaultBanner.setDelegate(this);
71 | mCubeBanner.setDelegate(this);
72 | }
73 |
74 | private void loadData() {
75 | loadData(mDefaultBanner, 1);
76 | loadData(mCubeBanner, 2);
77 | loadData(mAccordionBanner, 3);
78 | loadData(mFlipBanner, 4);
79 | loadData(mRotateBanner, 5);
80 | loadData(mAlphaBanner, 6);
81 | loadData(mZoomFadeBanner, 3);
82 | loadData(mFadeBanner, 4);
83 | loadData(mZoomCenterBanner, 5);
84 | loadData(mZoomBanner, 6);
85 | loadData(mStackBanner, 3);
86 | loadData(mZoomStackBanner, 4);
87 | loadData(mDepthBanner, 5);
88 | }
89 |
90 | private void loadData(final BGABanner banner, final int count) {
91 | mEngine.fetchItemsWithItemCount(count).enqueue(new Callback() {
92 | @Override
93 | public void onResponse(Call call, Response response) {
94 | BannerModel bannerModel = response.body();
95 |
96 | /**
97 | * 设置是否开启自动轮播,需要在 setData 方法之前调用,并且调了该方法后必须再调用一次 setData 方法
98 | * 例如根据图片当图片数量大于 1 时开启自动轮播,等于 1 时不开启自动轮播
99 | */
100 | banner.setAutoPlayAble(bannerModel.imgs.size() > 1);
101 |
102 | banner.setAdapter(MainActivity.this);
103 | banner.setData(bannerModel.imgs, bannerModel.tips);
104 | }
105 |
106 | @Override
107 | public void onFailure(Call call, Throwable t) {
108 | Toast.makeText(App.getInstance(), "网络数据加载失败", Toast.LENGTH_SHORT).show();
109 | }
110 | });
111 | }
112 |
113 | @Override
114 | public void onBannerItemClick(BGABanner banner, ImageView itemView, String model, int position) {
115 | Toast.makeText(banner.getContext(), "点击了第" + (position + 1) + "页", Toast.LENGTH_SHORT).show();
116 | }
117 |
118 | @Override
119 | public void fillBannerItem(BGABanner banner, ImageView itemView, String model, int position) {
120 | Glide.with(itemView.getContext())
121 | .load(model)
122 | .apply(new RequestOptions().placeholder(R.drawable.holder).error(R.drawable.holder).dontAnimate().centerCrop())
123 | .into(itemView);
124 | }
125 |
126 | public void onClick(View v) {
127 | switch (v.getId()) {
128 | case R.id.tv_main_visible:
129 | mDefaultBanner.setVisibility(View.VISIBLE);
130 | break;
131 | case R.id.tv_main_invisible:
132 | mDefaultBanner.setVisibility(View.INVISIBLE);
133 | break;
134 | case R.id.tv_main_gone:
135 | mDefaultBanner.setVisibility(View.GONE);
136 | break;
137 | case R.id.tv_main_change_height:
138 | // 设置宽高比例,如果大于 0,则会根据宽度来计算高度,否则使用 android:layout_height 指定的高度
139 | mDefaultBanner.setAspectRatio(2.1f);
140 | break;
141 | case R.id.tv_main_enable_auto_play:
142 | /**
143 | * 设置是否开启自动轮播,需要在 setData 方法之前调用,并且调了该方法后必须再调用一次 setData 方法
144 | * 例如根据图片当图片数量大于 1 时开启自动轮播,等于 1 时不开启自动轮播
145 | */
146 | mDefaultBanner.setAutoPlayAble(true);
147 | break;
148 | case R.id.tv_main_disable_auto_play:
149 | /**
150 | * 设置是否开启自动轮播,需要在 setData 方法之前调用,并且调了该方法后必须再调用一次 setData 方法
151 | * 例如根据图片当图片数量大于 1 时开启自动轮播,等于 1 时不开启自动轮播
152 | */
153 | mDefaultBanner.setAutoPlayAble(false);
154 | break;
155 | case R.id.tv_main_start_auto_play:
156 | // 仅在 autoPlayAble 为 true 时才会生效「开发者使用该库时不用调用该方法,这里只是为了演示而已,界面可见时在 BGABanner 内部已经帮开发者调用了该方方法」
157 | mDefaultBanner.startAutoPlay();
158 | break;
159 | case R.id.tv_main_stop_auto_play:
160 | // 仅在 autoPlayAble 为 true 时才会生效「开发者使用该库时不用调用该方法,这里只是为了演示而已,界面不可见时在 BGABanner 内部已经帮开发者调用了该方方法」
161 | mDefaultBanner.stopAutoPlay();
162 | break;
163 | case R.id.tv_main_select_page_one:
164 | mDefaultBanner.setCurrentItem(0);
165 | break;
166 | case R.id.tv_main_select_page_two:
167 | mDefaultBanner.setCurrentItem(1);
168 | break;
169 | case R.id.tv_main_select_page_three:
170 | mDefaultBanner.setCurrentItem(2);
171 | break;
172 | case R.id.tv_main_select_page_four:
173 | mDefaultBanner.setCurrentItem(3);
174 | break;
175 | case R.id.tv_main_select_page_five:
176 | mDefaultBanner.setCurrentItem(4);
177 | break;
178 | case R.id.tv_main_get_item_count:
179 | Toast.makeText(App.getInstance(), "广告条总页数为 " + mDefaultBanner.getItemCount(), Toast.LENGTH_SHORT).show();
180 | break;
181 | case R.id.tv_main_get_current_item:
182 | Toast.makeText(App.getInstance(), "广告当前索引位置为 " + mDefaultBanner.getCurrentItem(), Toast.LENGTH_SHORT).show();
183 | break;
184 | case R.id.tv_main_load_zero_item:
185 | mDefaultBanner.setAdapter(this);
186 | mDefaultBanner.setAutoPlayAble(false);
187 | mDefaultBanner.setData(null, null);
188 | mDefaultBanner.showPlaceholder();
189 | break;
190 | case R.id.tv_main_load_one_item:
191 | loadData(mDefaultBanner, 1);
192 | break;
193 | case R.id.tv_main_load_two_item:
194 | loadData(mDefaultBanner, 2);
195 | break;
196 | case R.id.tv_main_load_three_item:
197 | loadData(mDefaultBanner, 3);
198 | break;
199 | case R.id.tv_main_load_five_item:
200 | loadData(mDefaultBanner, 5);
201 | break;
202 | case R.id.tv_main_cube:
203 | mDefaultBanner.setTransitionEffect(TransitionEffect.Cube);
204 | break;
205 | case R.id.tv_main_depth:
206 | mDefaultBanner.setTransitionEffect(TransitionEffect.Depth);
207 | break;
208 | case R.id.tv_main_flip:
209 | mDefaultBanner.setTransitionEffect(TransitionEffect.Flip);
210 | break;
211 | case R.id.tv_main_rotate:
212 | mDefaultBanner.setTransitionEffect(TransitionEffect.Rotate);
213 | break;
214 | case R.id.tv_main_alpha:
215 | mDefaultBanner.setTransitionEffect(TransitionEffect.Alpha);
216 | break;
217 | case R.id.tv_main_listview_demo:
218 | startActivity(new Intent(this, ListViewDemoActivity.class));
219 | break;
220 | case R.id.tv_main_recyclerview_demo:
221 | startActivity(new Intent(this, RecyclerViewDemoActivity.class));
222 | break;
223 | case R.id.tv_main_fresco:
224 | startActivity(new Intent(this, FrescoDemoActivity.class));
225 | break;
226 |
227 | default:
228 | break;
229 | }
230 | }
231 | }
232 |
--------------------------------------------------------------------------------
/demo/src/main/java/cn/bingoogolapple/bgabanner/demo/ui/activity/RecyclerViewDemoActivity.java:
--------------------------------------------------------------------------------
1 | package cn.bingoogolapple.bgabanner.demo.ui.activity;
2 |
3 | import android.graphics.Rect;
4 | import android.os.Bundle;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import android.widget.ImageView;
8 | import android.widget.Toast;
9 |
10 | import com.bumptech.glide.Glide;
11 | import com.bumptech.glide.request.RequestOptions;
12 |
13 | import java.util.List;
14 |
15 | import androidx.appcompat.app.AppCompatActivity;
16 | import androidx.recyclerview.widget.GridLayoutManager;
17 | import androidx.recyclerview.widget.RecyclerView;
18 | import cn.bingoogolapple.baseadapter.BGAOnRVItemClickListener;
19 | import cn.bingoogolapple.baseadapter.BGARecyclerViewAdapter;
20 | import cn.bingoogolapple.baseadapter.BGAViewHolderHelper;
21 | import cn.bingoogolapple.bgabanner.BGABanner;
22 | import cn.bingoogolapple.bgabanner.BGABannerUtil;
23 | import cn.bingoogolapple.bgabanner.demo.App;
24 | import cn.bingoogolapple.bgabanner.demo.R;
25 | import cn.bingoogolapple.bgabanner.demo.engine.Engine;
26 | import cn.bingoogolapple.bgabanner.demo.model.BannerModel;
27 | import cn.bingoogolapple.bgabanner.demo.model.RefreshModel;
28 | import retrofit2.Call;
29 | import retrofit2.Callback;
30 | import retrofit2.Response;
31 |
32 | /**
33 | * 作者:王浩 邮件:bingoogolapple@gmail.com
34 | * 创建时间:16/7/21 下午8:26
35 | * 描述:
36 | */
37 | public class RecyclerViewDemoActivity extends AppCompatActivity implements BGABanner.Adapter, BGABanner.Delegate {
38 | private RecyclerView mContentRv;
39 | private BGABanner mBanner;
40 | private ContentAdapter mContentAdapter;
41 |
42 | private Engine mEngine;
43 |
44 | @Override
45 | protected void onCreate(Bundle savedInstanceState) {
46 | super.onCreate(savedInstanceState);
47 | setContentView(R.layout.activity_recyclerview_demo);
48 | mContentRv = findViewById(R.id.rv_content);
49 |
50 | setTitle("RecyclerViewDemo");
51 | mEngine = App.getInstance().getEngine();
52 |
53 | initRecyclerView();
54 |
55 |
56 | loadBannerData();
57 | loadContentData();
58 | }
59 |
60 | /**
61 | * 初始化RecyclerView
62 | */
63 | private void initRecyclerView() {
64 | // 初始化适配器
65 | mContentAdapter = new ContentAdapter(mContentRv);
66 | // 测试 item 点击事件
67 | mContentAdapter.setOnRVItemClickListener(new BGAOnRVItemClickListener() {
68 | @Override
69 | public void onRVItemClick(ViewGroup parent, View itemView, int position) {
70 | // 注意:即使加了 HeaderView,这里返回的 position 也是从 0 开始的,在 BGARecyclerViewAdapter 的内部已经帮开发者减去了 HeaderView
71 | Toast.makeText(itemView.getContext(), "position = " + position + " " + mContentAdapter.getItem(position).title, Toast.LENGTH_SHORT).show();
72 | }
73 | });
74 | // 添加 HeaderView
75 | mContentAdapter.addHeaderView(getHeaderView());
76 |
77 | RecyclerView.LayoutManager layoutManager;
78 |
79 | // 测试 LinearLayoutManager 的情况
80 | // layoutManager = new LinearLayoutManager(this);
81 |
82 | // 测试 GridLayoutManager 的情况
83 | layoutManager = new GridLayoutManager(this, 2);
84 |
85 | mContentRv.setLayoutManager(layoutManager);
86 |
87 | // 测试添加分割间隙
88 | mContentRv.addItemDecoration(new RecyclerView.ItemDecoration() {
89 | @Override
90 | public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
91 | int position = parent.getChildAdapterPosition(view);
92 | // 注意:由于加了一个 HeaderView,所以是大于 0 时才加分隔间隙。onCanvas 就不演示了
93 | if (position > 0) {
94 | int halfPadding = BGABannerUtil.dp2px(view.getContext(), 4);
95 | outRect.set(halfPadding, halfPadding, halfPadding, halfPadding);
96 | }
97 | }
98 | });
99 |
100 | // 注意:这里调用了 getHeaderAndFooterAdapter 方法
101 | mContentRv.setAdapter(mContentAdapter.getHeaderAndFooterAdapter());
102 | }
103 |
104 | /**
105 | * 初始化 HeaderView
106 | *
107 | * @return
108 | */
109 | private View getHeaderView() {
110 | View headerView = View.inflate(this, R.layout.layout_header, null);
111 | mBanner = headerView.findViewById(R.id.banner);
112 | mBanner.setAdapter(this);
113 | mBanner.setDelegate(this);
114 | return headerView;
115 | }
116 |
117 | @Override
118 | public void fillBannerItem(BGABanner banner, ImageView itemView, String model, int position) {
119 | Glide.with(this)
120 | .load(model)
121 | .apply(new RequestOptions().placeholder(R.drawable.holder).error(R.drawable.holder).dontAnimate().centerCrop())
122 | .into(itemView);
123 | }
124 |
125 | @Override
126 | public void onBannerItemClick(BGABanner banner, ImageView imageView, String model, int position) {
127 | Toast.makeText(this, "点击了第" + (position + 1) + "页", Toast.LENGTH_SHORT).show();
128 | }
129 |
130 | /**
131 | * 加载头部广告条的数据
132 | */
133 | private void loadBannerData() {
134 | mEngine.fetchItemsWithItemCount(5).enqueue(new Callback() {
135 | @Override
136 | public void onResponse(Call call, Response response) {
137 | BannerModel bannerModel = response.body();
138 | mBanner.setData(bannerModel.imgs, bannerModel.tips);
139 | }
140 |
141 | @Override
142 | public void onFailure(Call call, Throwable t) {
143 | Toast.makeText(App.getInstance(), "加载广告条数据失败", Toast.LENGTH_SHORT).show();
144 | }
145 | });
146 | }
147 |
148 | /**
149 | * 加载内容列表数据
150 | */
151 | private void loadContentData() {
152 | mEngine.loadContentData("http://bgashare.bingoogolapple.cn/refreshlayout/api/defaultdata.json").enqueue(new Callback>() {
153 | @Override
154 | public void onResponse(Call> call, Response> response) {
155 | mContentAdapter.setData(response.body());
156 | }
157 |
158 | @Override
159 | public void onFailure(Call> call, Throwable t) {
160 | Toast.makeText(App.getInstance(), "加载内容数据失败", Toast.LENGTH_SHORT).show();
161 | }
162 | });
163 | }
164 |
165 | private class ContentAdapter extends BGARecyclerViewAdapter {
166 |
167 | public ContentAdapter(RecyclerView recyclerView) {
168 | super(recyclerView, R.layout.item_normal);
169 | }
170 |
171 | @Override
172 | protected void fillData(BGAViewHolderHelper helper, int position, RefreshModel model) {
173 | helper.setText(R.id.tv_item_normal_title, model.title).setText(R.id.tv_item_normal_detail, model.detail);
174 | }
175 | }
176 | }
177 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-hdpi/holder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bingoogolapple/BGABanner-Android/a328a9eb2e49bda75db0003b76be74524da66708/demo/src/main/res/drawable-hdpi/holder.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bingoogolapple/BGABanner-Android/a328a9eb2e49bda75db0003b76be74524da66708/demo/src/main/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-hdpi/point_focused.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bingoogolapple/BGABanner-Android/a328a9eb2e49bda75db0003b76be74524da66708/demo/src/main/res/drawable-hdpi/point_focused.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-hdpi/point_focused_big.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bingoogolapple/BGABanner-Android/a328a9eb2e49bda75db0003b76be74524da66708/demo/src/main/res/drawable-hdpi/point_focused_big.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-hdpi/point_unfocused.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bingoogolapple/BGABanner-Android/a328a9eb2e49bda75db0003b76be74524da66708/demo/src/main/res/drawable-hdpi/point_unfocused.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-hdpi/point_unfocused_small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bingoogolapple/BGABanner-Android/a328a9eb2e49bda75db0003b76be74524da66708/demo/src/main/res/drawable-hdpi/point_unfocused_small.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bingoogolapple/BGABanner-Android/a328a9eb2e49bda75db0003b76be74524da66708/demo/src/main/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bingoogolapple/BGABanner-Android/a328a9eb2e49bda75db0003b76be74524da66708/demo/src/main/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-xhdpi/uoko_guide_background_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bingoogolapple/BGABanner-Android/a328a9eb2e49bda75db0003b76be74524da66708/demo/src/main/res/drawable-xhdpi/uoko_guide_background_1.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-xhdpi/uoko_guide_background_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bingoogolapple/BGABanner-Android/a328a9eb2e49bda75db0003b76be74524da66708/demo/src/main/res/drawable-xhdpi/uoko_guide_background_2.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-xhdpi/uoko_guide_background_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bingoogolapple/BGABanner-Android/a328a9eb2e49bda75db0003b76be74524da66708/demo/src/main/res/drawable-xhdpi/uoko_guide_background_3.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-xhdpi/uoko_guide_foreground_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bingoogolapple/BGABanner-Android/a328a9eb2e49bda75db0003b76be74524da66708/demo/src/main/res/drawable-xhdpi/uoko_guide_foreground_1.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-xhdpi/uoko_guide_foreground_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bingoogolapple/BGABanner-Android/a328a9eb2e49bda75db0003b76be74524da66708/demo/src/main/res/drawable-xhdpi/uoko_guide_foreground_2.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-xhdpi/uoko_guide_foreground_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bingoogolapple/BGABanner-Android/a328a9eb2e49bda75db0003b76be74524da66708/demo/src/main/res/drawable-xhdpi/uoko_guide_foreground_3.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bingoogolapple/BGABanner-Android/a328a9eb2e49bda75db0003b76be74524da66708/demo/src/main/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/selector_banner_point.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/selector_banner_unequal.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/selector_btn_test.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
8 |
9 | -
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/shape_number_indicator_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
10 |
11 |
--------------------------------------------------------------------------------
/demo/src/main/res/layout/activity_fresco_demo.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
24 |
--------------------------------------------------------------------------------
/demo/src/main/res/layout/activity_guide.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
18 |
19 |
28 |
29 |
30 |
41 |
42 |
55 |
--------------------------------------------------------------------------------
/demo/src/main/res/layout/activity_listview_demo.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/demo/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
22 |
23 |
36 |
37 |
50 |
51 |
52 |
53 |
57 |
58 |
62 |
63 |
67 |
68 |
72 |
73 |
74 |
75 |
76 |
80 |
81 |
85 |
86 |
90 |
91 |
95 |
96 |
97 |
98 |
99 |
103 |
104 |
108 |
109 |
113 |
114 |
118 |
119 |
123 |
124 |
128 |
129 |
133 |
134 |
135 |
136 |
137 |
141 |
142 |
146 |
147 |
151 |
152 |
156 |
157 |
161 |
162 |
163 |
164 |
165 |
169 |
170 |
174 |
175 |
179 |
180 |
184 |
185 |
189 |
190 |
191 |
204 |
205 |
211 |
212 |
217 |
218 |
224 |
225 |
230 |
231 |
236 |
237 |
241 |
242 |
246 |
247 |
252 |
253 |
257 |
258 |
263 |
264 |
269 |
270 |
274 |
275 |
--------------------------------------------------------------------------------
/demo/src/main/res/layout/activity_recyclerview_demo.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/demo/src/main/res/layout/item_fresco.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
16 |
--------------------------------------------------------------------------------
/demo/src/main/res/layout/item_normal.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
14 |
15 |
23 |
--------------------------------------------------------------------------------
/demo/src/main/res/layout/layout_header.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
18 |
19 |
--------------------------------------------------------------------------------
/demo/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #5DA49F
4 | #6BBEB8
5 | @android:color/white
6 |
--------------------------------------------------------------------------------
/demo/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/demo/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | BGABannerDemo
5 | Hello world!
6 | Settings
7 |
8 |
9 |
--------------------------------------------------------------------------------
/demo/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
15 |
16 |
46 |
47 |
59 |
60 |
--------------------------------------------------------------------------------
/demo/src/main/res/values/styles_base.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
13 |
14 |
18 |
19 |
23 |
24 |
29 |
30 |
35 |
36 |
41 |
42 |
47 |
48 |
51 |
52 |
55 |
56 |
59 |
60 |
63 |
64 |
67 |
68 |
71 |
72 |
75 |
76 |
79 |
80 |
83 |
84 |
87 |
88 |
91 |
92 |
95 |
96 |
99 |
100 |
103 |
104 |
107 |
108 |
111 |
112 |
116 |
117 |
121 |
--------------------------------------------------------------------------------
/demo/src/main/res/xml/network_security_config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | ANDROID_BUILD_MIN_SDK_VERSION=14
2 | ANDROID_BUILD_TARGET_SDK_VERSION=29
3 | ANDROID_BUILD_SDK_VERSION=29
4 |
5 | VERSION_NAME=3.0.1
6 | VERSION_CODE=301
7 |
8 | # 设置为 true,Android 插件会使用相应的 AndroidX 库,而非支持库
9 | android.useAndroidX=true
10 | # 设置为 true,Android 插件会重写其二进制文件,自动迁移现有的第三方库以使用 AndroidX
11 | android.enableJetifier=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bingoogolapple/BGABanner-Android/a328a9eb2e49bda75db0003b76be74524da66708/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sun Nov 10 17:04:31 CST 2019
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/library/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'com.github.dcendents.android-maven'
3 |
4 | android {
5 | compileSdkVersion ANDROID_BUILD_SDK_VERSION as int
6 |
7 | defaultConfig {
8 | minSdkVersion ANDROID_BUILD_MIN_SDK_VERSION as int
9 | targetSdkVersion ANDROID_BUILD_TARGET_SDK_VERSION as int
10 | consumerProguardFiles 'consumer-proguard-rules.pro'
11 | }
12 | }
13 |
14 | dependencies {
15 | compileOnly 'androidx.legacy:legacy-support-v4:1.0.0'
16 | }
17 |
--------------------------------------------------------------------------------
/library/consumer-proguard-rules.pro:
--------------------------------------------------------------------------------
1 | -keep class cn.bingoogolapple.bgabanner.BGAViewPager { *; }
--------------------------------------------------------------------------------
/library/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/library/src/main/java/cn/bingoogolapple/bgabanner/BGABanner.java:
--------------------------------------------------------------------------------
1 | package cn.bingoogolapple.bgabanner;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.content.res.TypedArray;
6 | import android.graphics.Color;
7 | import android.graphics.drawable.ColorDrawable;
8 | import android.graphics.drawable.Drawable;
9 | import android.os.Build;
10 | import android.text.TextUtils;
11 | import android.util.AttributeSet;
12 | import android.util.TypedValue;
13 | import android.view.Gravity;
14 | import android.view.MotionEvent;
15 | import android.view.View;
16 | import android.view.ViewGroup;
17 | import android.view.ViewParent;
18 | import android.widget.ImageView;
19 | import android.widget.LinearLayout;
20 | import android.widget.RelativeLayout;
21 | import android.widget.TextView;
22 |
23 | import java.lang.ref.WeakReference;
24 | import java.util.ArrayList;
25 | import java.util.List;
26 |
27 | import androidx.annotation.DimenRes;
28 | import androidx.annotation.DrawableRes;
29 | import androidx.annotation.LayoutRes;
30 | import androidx.annotation.Nullable;
31 | import androidx.core.view.ViewCompat;
32 | import androidx.viewpager.widget.PagerAdapter;
33 | import androidx.viewpager.widget.ViewPager;
34 | import cn.bingoogolapple.bgabanner.transformer.BGAPageTransformer;
35 | import cn.bingoogolapple.bgabanner.transformer.TransitionEffect;
36 |
37 | public class BGABanner extends RelativeLayout implements BGAViewPager.AutoPlayDelegate, ViewPager.OnPageChangeListener {
38 | private static final int RMP = RelativeLayout.LayoutParams.MATCH_PARENT;
39 | private static final int RWC = RelativeLayout.LayoutParams.WRAP_CONTENT;
40 | private static final int LWC = LinearLayout.LayoutParams.WRAP_CONTENT;
41 | private static final int NO_PLACEHOLDER_DRAWABLE = -1;
42 | private static final int VEL_THRESHOLD = 400;
43 | private BGAViewPager mViewPager;
44 | private List mHackyViews;
45 | private List mViews;
46 | private List mTips;
47 | private LinearLayout mPointRealContainerLl;
48 | private TextView mTipTv;
49 | private boolean mAutoPlayAble = true;
50 | private int mAutoPlayInterval = 3000;
51 | private int mPageChangeDuration = 800;
52 | private int mPointGravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
53 | private int mPointLeftRightMargin;
54 | private int mPointTopBottomMargin;
55 | private int mPointContainerLeftRightPadding;
56 | private int mTipTextSize;
57 | private int mTipTextColor = Color.WHITE;
58 | private int mPointDrawableResId = R.drawable.bga_banner_selector_point_solid;
59 | private Drawable mPointContainerBackgroundDrawable;
60 | private AutoPlayTask mAutoPlayTask;
61 | private int mPageScrollPosition;
62 | private float mPageScrollPositionOffset;
63 | private TransitionEffect mTransitionEffect;
64 | private ImageView mPlaceholderIv;
65 | private ImageView.ScaleType mScaleType = ImageView.ScaleType.CENTER_CROP;
66 | private int mPlaceholderDrawableResId = NO_PLACEHOLDER_DRAWABLE;
67 | private List extends Object> mModels;
68 | private Delegate mDelegate;
69 | private Adapter mAdapter;
70 | private int mOverScrollMode = OVER_SCROLL_NEVER;
71 | private ViewPager.OnPageChangeListener mOnPageChangeListener;
72 | private RelativeLayout mPointContainerRl;
73 | private boolean mIsNumberIndicator = false;
74 | private TextView mNumberIndicatorTv;
75 | private int mNumberIndicatorTextColor = Color.WHITE;
76 | private int mNumberIndicatorTextSize;
77 | private Drawable mNumberIndicatorBackground;
78 | private boolean mIsNeedShowIndicatorOnOnlyOnePage;
79 | private int mContentBottomMargin;
80 | private float mAspectRatio;
81 | private boolean mAllowUserScrollable = true;
82 | private View mSkipView;
83 | private View mEnterView;
84 | private GuideDelegate mGuideDelegate;
85 | private boolean mIsFirstInvisible = true;
86 |
87 | private static final ImageView.ScaleType[] sScaleTypeArray = {
88 | ImageView.ScaleType.MATRIX,
89 | ImageView.ScaleType.FIT_XY,
90 | ImageView.ScaleType.FIT_START,
91 | ImageView.ScaleType.FIT_CENTER,
92 | ImageView.ScaleType.FIT_END,
93 | ImageView.ScaleType.CENTER,
94 | ImageView.ScaleType.CENTER_CROP,
95 | ImageView.ScaleType.CENTER_INSIDE
96 | };
97 |
98 | private BGAOnNoDoubleClickListener mGuideOnNoDoubleClickListener = new BGAOnNoDoubleClickListener() {
99 | @Override
100 | public void onNoDoubleClick(View v) {
101 | if (mGuideDelegate != null) {
102 | mGuideDelegate.onClickEnterOrSkip();
103 | }
104 | }
105 | };
106 |
107 | public BGABanner(Context context, AttributeSet attrs) {
108 | this(context, attrs, 0);
109 | }
110 |
111 | public BGABanner(Context context, AttributeSet attrs, int defStyle) {
112 | super(context, attrs, defStyle);
113 | initDefaultAttrs(context);
114 | initCustomAttrs(context, attrs);
115 | initView(context);
116 | }
117 |
118 | private void initDefaultAttrs(Context context) {
119 | mAutoPlayTask = new AutoPlayTask(this);
120 |
121 | mPointLeftRightMargin = BGABannerUtil.dp2px(context, 3);
122 | mPointTopBottomMargin = BGABannerUtil.dp2px(context, 6);
123 | mPointContainerLeftRightPadding = BGABannerUtil.dp2px(context, 10);
124 | mTipTextSize = BGABannerUtil.sp2px(context, 10);
125 | mPointContainerBackgroundDrawable = new ColorDrawable(Color.parseColor("#44aaaaaa"));
126 | mTransitionEffect = TransitionEffect.Default;
127 | mNumberIndicatorTextSize = BGABannerUtil.sp2px(context, 10);
128 |
129 | mContentBottomMargin = 0;
130 | mAspectRatio = 0;
131 | }
132 |
133 | private void initCustomAttrs(Context context, AttributeSet attrs) {
134 | TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.BGABanner);
135 | final int N = typedArray.getIndexCount();
136 | for (int i = 0; i < N; i++) {
137 | initCustomAttr(typedArray.getIndex(i), typedArray);
138 | }
139 | typedArray.recycle();
140 | }
141 |
142 | private void initCustomAttr(int attr, TypedArray typedArray) {
143 | if (attr == R.styleable.BGABanner_banner_pointDrawable) {
144 | mPointDrawableResId = typedArray.getResourceId(attr, R.drawable.bga_banner_selector_point_solid);
145 | } else if (attr == R.styleable.BGABanner_banner_pointContainerBackground) {
146 | mPointContainerBackgroundDrawable = typedArray.getDrawable(attr);
147 | } else if (attr == R.styleable.BGABanner_banner_pointLeftRightMargin) {
148 | mPointLeftRightMargin = typedArray.getDimensionPixelSize(attr, mPointLeftRightMargin);
149 | } else if (attr == R.styleable.BGABanner_banner_pointContainerLeftRightPadding) {
150 | mPointContainerLeftRightPadding = typedArray.getDimensionPixelSize(attr, mPointContainerLeftRightPadding);
151 | } else if (attr == R.styleable.BGABanner_banner_pointTopBottomMargin) {
152 | mPointTopBottomMargin = typedArray.getDimensionPixelSize(attr, mPointTopBottomMargin);
153 | } else if (attr == R.styleable.BGABanner_banner_indicatorGravity) {
154 | mPointGravity = typedArray.getInt(attr, mPointGravity);
155 | } else if (attr == R.styleable.BGABanner_banner_pointAutoPlayAble) {
156 | mAutoPlayAble = typedArray.getBoolean(attr, mAutoPlayAble);
157 | } else if (attr == R.styleable.BGABanner_banner_pointAutoPlayInterval) {
158 | mAutoPlayInterval = typedArray.getInteger(attr, mAutoPlayInterval);
159 | } else if (attr == R.styleable.BGABanner_banner_pageChangeDuration) {
160 | mPageChangeDuration = typedArray.getInteger(attr, mPageChangeDuration);
161 | } else if (attr == R.styleable.BGABanner_banner_transitionEffect) {
162 | int ordinal = typedArray.getInt(attr, TransitionEffect.Accordion.ordinal());
163 | mTransitionEffect = TransitionEffect.values()[ordinal];
164 | } else if (attr == R.styleable.BGABanner_banner_tipTextColor) {
165 | mTipTextColor = typedArray.getColor(attr, mTipTextColor);
166 | } else if (attr == R.styleable.BGABanner_banner_tipTextSize) {
167 | mTipTextSize = typedArray.getDimensionPixelSize(attr, mTipTextSize);
168 | } else if (attr == R.styleable.BGABanner_banner_placeholderDrawable) {
169 | mPlaceholderDrawableResId = typedArray.getResourceId(attr, mPlaceholderDrawableResId);
170 | } else if (attr == R.styleable.BGABanner_banner_isNumberIndicator) {
171 | mIsNumberIndicator = typedArray.getBoolean(attr, mIsNumberIndicator);
172 | } else if (attr == R.styleable.BGABanner_banner_numberIndicatorTextColor) {
173 | mNumberIndicatorTextColor = typedArray.getColor(attr, mNumberIndicatorTextColor);
174 | } else if (attr == R.styleable.BGABanner_banner_numberIndicatorTextSize) {
175 | mNumberIndicatorTextSize = typedArray.getDimensionPixelSize(attr, mNumberIndicatorTextSize);
176 | } else if (attr == R.styleable.BGABanner_banner_numberIndicatorBackground) {
177 | mNumberIndicatorBackground = typedArray.getDrawable(attr);
178 | } else if (attr == R.styleable.BGABanner_banner_isNeedShowIndicatorOnOnlyOnePage) {
179 | mIsNeedShowIndicatorOnOnlyOnePage = typedArray.getBoolean(attr, mIsNeedShowIndicatorOnOnlyOnePage);
180 | } else if (attr == R.styleable.BGABanner_banner_contentBottomMargin) {
181 | mContentBottomMargin = typedArray.getDimensionPixelSize(attr, mContentBottomMargin);
182 | } else if (attr == R.styleable.BGABanner_banner_aspectRatio) {
183 | mAspectRatio = typedArray.getFloat(attr, mAspectRatio);
184 | } else if (attr == R.styleable.BGABanner_android_scaleType) {
185 | final int index = typedArray.getInt(attr, -1);
186 | if (index >= 0 && index < sScaleTypeArray.length) {
187 | mScaleType = sScaleTypeArray[index];
188 | }
189 | }
190 | }
191 |
192 | private void initView(Context context) {
193 | mPointContainerRl = new RelativeLayout(context);
194 | if (Build.VERSION.SDK_INT >= 16) {
195 | mPointContainerRl.setBackground(mPointContainerBackgroundDrawable);
196 | } else {
197 | mPointContainerRl.setBackgroundDrawable(mPointContainerBackgroundDrawable);
198 | }
199 | mPointContainerRl.setPadding(mPointContainerLeftRightPadding, mPointTopBottomMargin, mPointContainerLeftRightPadding, mPointTopBottomMargin);
200 | RelativeLayout.LayoutParams pointContainerLp = new RelativeLayout.LayoutParams(RMP, RWC);
201 | // 处理圆点在顶部还是底部
202 | if ((mPointGravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.TOP) {
203 | pointContainerLp.addRule(RelativeLayout.ALIGN_PARENT_TOP);
204 | } else {
205 | pointContainerLp.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
206 | }
207 | addView(mPointContainerRl, pointContainerLp);
208 |
209 |
210 | RelativeLayout.LayoutParams indicatorLp = new RelativeLayout.LayoutParams(RWC, RWC);
211 | indicatorLp.addRule(CENTER_VERTICAL);
212 | if (mIsNumberIndicator) {
213 | mNumberIndicatorTv = new TextView(context);
214 | mNumberIndicatorTv.setId(R.id.banner_indicatorId);
215 | mNumberIndicatorTv.setGravity(Gravity.CENTER_VERTICAL);
216 | mNumberIndicatorTv.setSingleLine(true);
217 | mNumberIndicatorTv.setEllipsize(TextUtils.TruncateAt.END);
218 | mNumberIndicatorTv.setTextColor(mNumberIndicatorTextColor);
219 | mNumberIndicatorTv.setTextSize(TypedValue.COMPLEX_UNIT_PX, mNumberIndicatorTextSize);
220 | mNumberIndicatorTv.setVisibility(View.INVISIBLE);
221 | if (mNumberIndicatorBackground != null) {
222 | if (Build.VERSION.SDK_INT >= 16) {
223 | mNumberIndicatorTv.setBackground(mNumberIndicatorBackground);
224 | } else {
225 | mNumberIndicatorTv.setBackgroundDrawable(mNumberIndicatorBackground);
226 | }
227 | }
228 | mPointContainerRl.addView(mNumberIndicatorTv, indicatorLp);
229 | } else {
230 | mPointRealContainerLl = new LinearLayout(context);
231 | mPointRealContainerLl.setId(R.id.banner_indicatorId);
232 | mPointRealContainerLl.setOrientation(LinearLayout.HORIZONTAL);
233 | mPointRealContainerLl.setGravity(Gravity.CENTER_VERTICAL);
234 | mPointContainerRl.addView(mPointRealContainerLl, indicatorLp);
235 | }
236 |
237 | RelativeLayout.LayoutParams tipLp = new RelativeLayout.LayoutParams(RMP, RWC);
238 | tipLp.addRule(CENTER_VERTICAL);
239 | mTipTv = new TextView(context);
240 | mTipTv.setGravity(Gravity.CENTER_VERTICAL);
241 | mTipTv.setSingleLine(true);
242 | mTipTv.setEllipsize(TextUtils.TruncateAt.END);
243 | mTipTv.setTextColor(mTipTextColor);
244 | mTipTv.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTipTextSize);
245 | mPointContainerRl.addView(mTipTv, tipLp);
246 |
247 | int horizontalGravity = mPointGravity & Gravity.HORIZONTAL_GRAVITY_MASK;
248 | // 处理圆点在左边、右边还是水平居中
249 | if (horizontalGravity == Gravity.LEFT) {
250 | indicatorLp.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
251 | tipLp.addRule(RelativeLayout.RIGHT_OF, R.id.banner_indicatorId);
252 | mTipTv.setGravity(Gravity.CENTER_VERTICAL | Gravity.RIGHT);
253 | } else if (horizontalGravity == Gravity.RIGHT) {
254 | indicatorLp.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
255 | tipLp.addRule(RelativeLayout.LEFT_OF, R.id.banner_indicatorId);
256 | } else {
257 | indicatorLp.addRule(RelativeLayout.CENTER_HORIZONTAL);
258 | tipLp.addRule(RelativeLayout.LEFT_OF, R.id.banner_indicatorId);
259 | }
260 |
261 | showPlaceholder();
262 | }
263 |
264 | public void showPlaceholder() {
265 | if (mPlaceholderIv == null && mPlaceholderDrawableResId != NO_PLACEHOLDER_DRAWABLE) {
266 | mPlaceholderIv = BGABannerUtil.getItemImageView(getContext(), mPlaceholderDrawableResId, new BGALocalImageSize(720, 360, 640, 320), mScaleType);
267 | RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RMP, RMP);
268 | layoutParams.setMargins(0, 0, 0, mContentBottomMargin);
269 | addView(mPlaceholderIv, layoutParams);
270 | }
271 | }
272 |
273 | /**
274 | * 设置页码切换过程的时间长度
275 | *
276 | * @param duration 页码切换过程的时间长度
277 | */
278 | public void setPageChangeDuration(int duration) {
279 | if (duration >= 0 && duration <= 2000) {
280 | mPageChangeDuration = duration;
281 | if (mViewPager != null) {
282 | mViewPager.setPageChangeDuration(duration);
283 | }
284 | }
285 | }
286 |
287 | /**
288 | * 设置是否开启自动轮播,需要在 setData 方法之前调用,并且调了该方法后必须再调用一次 setData 方法
289 | * 例如根据图片当图片数量大于 1 时开启自动轮播,等于 1 时不开启自动轮播
290 | */
291 | public void setAutoPlayAble(boolean autoPlayAble) {
292 | mAutoPlayAble = autoPlayAble;
293 |
294 | stopAutoPlay();
295 |
296 | if (mViewPager != null && mViewPager.getAdapter() != null) {
297 | mViewPager.getAdapter().notifyDataSetChanged();
298 | }
299 | }
300 |
301 | /**
302 | * 设置自动轮播的时间间隔
303 | */
304 | public void setAutoPlayInterval(int autoPlayInterval) {
305 | mAutoPlayInterval = autoPlayInterval;
306 | }
307 |
308 | /**
309 | * 设置每一页的控件、数据模型和文案
310 | *
311 | * @param views 每一页的控件集合
312 | * @param models 每一页的数据模型集合
313 | * @param tips 每一页的提示文案集合
314 | */
315 | public void setData(List views, List extends Object> models, List tips) {
316 | if (BGABannerUtil.isCollectionEmpty(views)) {
317 | mAutoPlayAble = false;
318 | views = new ArrayList<>();
319 | models = new ArrayList<>();
320 | tips = new ArrayList<>();
321 | }
322 | if (mAutoPlayAble && views.size() < 3 && mHackyViews == null) {
323 | mAutoPlayAble = false;
324 | }
325 |
326 | mModels = models;
327 | mViews = views;
328 | mTips = tips;
329 |
330 | initIndicator();
331 | initViewPager();
332 | removePlaceholder();
333 | handleGuideViewVisibility(0, 0);
334 | }
335 |
336 | /**
337 | * 设置布局资源id、数据模型和文案
338 | *
339 | * @param layoutResId item布局文件资源id
340 | * @param models 每一页的数据模型集合
341 | * @param tips 每一页的提示文案集合
342 | */
343 | public void setData(@LayoutRes int layoutResId, List extends Object> models, List tips) {
344 | mViews = new ArrayList<>();
345 | if (models == null) {
346 | models = new ArrayList<>();
347 | tips = new ArrayList<>();
348 | }
349 | for (int i = 0; i < models.size(); i++) {
350 | mViews.add(inflateItemView(layoutResId));
351 | }
352 | if (mAutoPlayAble && mViews.size() < 3) {
353 | mHackyViews = new ArrayList<>(mViews);
354 | mHackyViews.add(inflateItemView(layoutResId));
355 | if (mHackyViews.size() == 2) {
356 | mHackyViews.add(inflateItemView(layoutResId));
357 | }
358 | }
359 | setData(mViews, models, tips);
360 | }
361 |
362 | private View inflateItemView(@LayoutRes int layoutResId) {
363 | View itemView = View.inflate(getContext(), layoutResId, null);
364 | if (itemView instanceof ImageView) {
365 | ((ImageView) itemView).setScaleType(mScaleType);
366 | }
367 | return itemView;
368 | }
369 |
370 | /**
371 | * 设置数据模型和文案,布局资源默认为 ImageView
372 | *
373 | * @param models 每一页的数据模型集合
374 | * @param tips 每一页的提示文案集合
375 | */
376 | public void setData(List extends Object> models, List tips) {
377 | setData(R.layout.bga_banner_item_image, models, tips);
378 | }
379 |
380 | /**
381 | * 设置每一页的控件集合,主要针对引导页的情况
382 | *
383 | * @param views 每一页的控件集合
384 | */
385 | public void setData(List views) {
386 | setData(views, null, null);
387 | }
388 |
389 | /**
390 | * 设置每一页图片的资源 id,主要针对引导页的情况
391 | *
392 | * @param localImageSize 内存优化,Bitmap 的宽高在 maxWidth maxHeight 和 minWidth minHeight 之间,传 null 的话默认为 720, 1280, 320, 640
393 | * @param scaleType 图片缩放模式,传 null 的话默认为 CENTER_CROP
394 | * @param resIds 每一页图片资源 id
395 | */
396 | public void setData(@Nullable BGALocalImageSize localImageSize, @Nullable ImageView.ScaleType scaleType, @DrawableRes int... resIds) {
397 | if (localImageSize == null) {
398 | localImageSize = new BGALocalImageSize(720, 1280, 320, 640);
399 | }
400 | if (scaleType != null) {
401 | mScaleType = scaleType;
402 | }
403 | List views = new ArrayList<>();
404 | for (int resId : resIds) {
405 | views.add(BGABannerUtil.getItemImageView(getContext(), resId, localImageSize, mScaleType));
406 | }
407 | setData(views);
408 | }
409 |
410 | /**
411 | * 设置是否允许用户手指滑动
412 | *
413 | * @param allowUserScrollable true表示允许跟随用户触摸滑动,false反之
414 | */
415 | public void setAllowUserScrollable(boolean allowUserScrollable) {
416 | mAllowUserScrollable = allowUserScrollable;
417 | if (mViewPager != null) {
418 | mViewPager.setAllowUserScrollable(mAllowUserScrollable);
419 | }
420 | }
421 |
422 | /**
423 | * 添加ViewPager滚动监听器
424 | */
425 | public void setOnPageChangeListener(ViewPager.OnPageChangeListener onPageChangeListener) {
426 | mOnPageChangeListener = onPageChangeListener;
427 | }
428 |
429 | /**
430 | * 设置进入按钮和跳过按钮控件资源 id,需要开发者自己处理这两个按钮的点击事件
431 | *
432 | * @param enterResId 进入按钮控件
433 | * @param skipResId 跳过按钮控件
434 | */
435 | public void setEnterSkipViewId(int enterResId, int skipResId) {
436 | if (enterResId != 0) {
437 | mEnterView = ((Activity) getContext()).findViewById(enterResId);
438 | }
439 | if (skipResId != 0) {
440 | mSkipView = ((Activity) getContext()).findViewById(skipResId);
441 | }
442 | }
443 |
444 | /**
445 | * 设置进入按钮和跳过按钮控件资源 id 及其点击事件监听器
446 | * 如果进入按钮和跳过按钮有一个不存在的话就传 0
447 | * 在 BGABanner 里已经帮开发者处理了重复点击事件
448 | * 在 BGABanner 里已经帮开发者处理了「跳过按钮」和「进入按钮」的显示与隐藏
449 | *
450 | * @param enterResId 进入按钮控件资源 id,没有的话就传 0
451 | * @param skipResId 跳过按钮控件资源 id,没有的话就传 0
452 | * @param guideDelegate 引导页「进入」和「跳过」按钮点击事件监听器
453 | */
454 | public void setEnterSkipViewIdAndDelegate(int enterResId, int skipResId, GuideDelegate guideDelegate) {
455 | if (guideDelegate != null) {
456 | mGuideDelegate = guideDelegate;
457 | if (enterResId != 0) {
458 | mEnterView = ((Activity) getContext()).findViewById(enterResId);
459 | mEnterView.setOnClickListener(mGuideOnNoDoubleClickListener);
460 | }
461 | if (skipResId != 0) {
462 | mSkipView = ((Activity) getContext()).findViewById(skipResId);
463 | mSkipView.setOnClickListener(mGuideOnNoDoubleClickListener);
464 | }
465 | }
466 | handleGuideViewVisibility(0, 0);
467 | }
468 |
469 | /**
470 | * 获取当前选中界面索引
471 | */
472 | public int getCurrentItem() {
473 | if (mViewPager == null || BGABannerUtil.isCollectionEmpty(mViews)) {
474 | return -1;
475 | } else {
476 | return mViewPager.getCurrentItem() % mViews.size();
477 | }
478 | }
479 |
480 | /**
481 | * 获取广告页面总个数
482 | */
483 | public int getItemCount() {
484 | return mViews == null ? 0 : mViews.size();
485 | }
486 |
487 | public List extends View> getViews() {
488 | return mViews;
489 | }
490 |
491 | public VT getItemView(int position) {
492 | return mViews == null ? null : (VT) mViews.get(position);
493 | }
494 |
495 | public ImageView getItemImageView(int position) {
496 | return getItemView(position);
497 | }
498 |
499 | public List getTips() {
500 | return mTips;
501 | }
502 |
503 | public BGAViewPager getViewPager() {
504 | return mViewPager;
505 | }
506 |
507 | public void setOverScrollMode(int overScrollMode) {
508 | mOverScrollMode = overScrollMode;
509 | if (mViewPager != null) {
510 | mViewPager.setOverScrollMode(mOverScrollMode);
511 | }
512 | }
513 |
514 | public void setIndicatorVisibility(boolean visible) {
515 | mPointContainerRl.setVisibility(visible ? VISIBLE : GONE);
516 | }
517 |
518 | public void setIndicatorTopBottomMarginDp(int marginDp) {
519 | setIndicatorTopBottomMarginPx(BGABannerUtil.dp2px(getContext(), marginDp));
520 | }
521 |
522 | public void setIndicatorTopBottomMarginRes(@DimenRes int resId) {
523 | setIndicatorTopBottomMarginPx(getResources().getDimensionPixelOffset(resId));
524 | }
525 |
526 | public void setIndicatorTopBottomMarginPx(int marginPx) {
527 | mPointTopBottomMargin = marginPx;
528 | mPointContainerRl.setPadding(mPointContainerLeftRightPadding, mPointTopBottomMargin, mPointContainerLeftRightPadding, mPointTopBottomMargin);
529 | }
530 |
531 | private void initIndicator() {
532 | if (mPointRealContainerLl != null) {
533 | mPointRealContainerLl.removeAllViews();
534 |
535 | if (mIsNeedShowIndicatorOnOnlyOnePage || (!mIsNeedShowIndicatorOnOnlyOnePage && mViews.size() > 1)) {
536 | LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LWC, LWC);
537 | lp.setMargins(mPointLeftRightMargin, 0, mPointLeftRightMargin, 0);
538 | ImageView imageView;
539 | for (int i = 0; i < mViews.size(); i++) {
540 | imageView = new ImageView(getContext());
541 | imageView.setLayoutParams(lp);
542 | imageView.setImageResource(mPointDrawableResId);
543 | mPointRealContainerLl.addView(imageView);
544 | }
545 | }
546 | }
547 | if (mNumberIndicatorTv != null) {
548 | if (mIsNeedShowIndicatorOnOnlyOnePage || (!mIsNeedShowIndicatorOnOnlyOnePage && mViews.size() > 1)) {
549 | mNumberIndicatorTv.setVisibility(View.VISIBLE);
550 | } else {
551 | mNumberIndicatorTv.setVisibility(View.INVISIBLE);
552 | }
553 | }
554 | }
555 |
556 | private void initViewPager() {
557 | if (mViewPager != null && this.equals(mViewPager.getParent())) {
558 | this.removeView(mViewPager);
559 | mViewPager = null;
560 | }
561 |
562 | mViewPager = new BGAViewPager(getContext());
563 | mViewPager.setOffscreenPageLimit(1);
564 | mViewPager.setAdapter(new PageAdapter());
565 | mViewPager.addOnPageChangeListener(this);
566 | mViewPager.setOverScrollMode(mOverScrollMode);
567 | mViewPager.setAllowUserScrollable(mAllowUserScrollable);
568 | mViewPager.setPageTransformer(true, BGAPageTransformer.getPageTransformer(mTransitionEffect));
569 | setPageChangeDuration(mPageChangeDuration);
570 |
571 | RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RMP, RMP);
572 | layoutParams.setMargins(0, 0, 0, mContentBottomMargin);
573 | addView(mViewPager, 0, layoutParams);
574 |
575 | if (mAutoPlayAble && !BGABannerUtil.isCollectionEmpty(mViews)) {
576 | mViewPager.setAutoPlayDelegate(this);
577 |
578 | int zeroItem = Integer.MAX_VALUE / 2 - (Integer.MAX_VALUE / 2) % mViews.size();
579 | mViewPager.setCurrentItem(zeroItem);
580 |
581 | startAutoPlay();
582 | } else {
583 | switchToPoint(0);
584 | }
585 | }
586 |
587 | public void removePlaceholder() {
588 | if (mPlaceholderIv != null && this.equals(mPlaceholderIv.getParent())) {
589 | removeView(mPlaceholderIv);
590 | mPlaceholderIv = null;
591 | }
592 | }
593 |
594 | /**
595 | * 设置宽高比例,如果大于 0,则会根据宽度来计算高度,否则使用 android:layout_height 指定的高度
596 | */
597 | public void setAspectRatio(float aspectRatio) {
598 | mAspectRatio = aspectRatio;
599 | requestLayout();
600 | }
601 |
602 | @Override
603 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
604 | if (mAspectRatio > 0) {
605 | int width = MeasureSpec.getSize(widthMeasureSpec);
606 | int height = (int) (width / mAspectRatio);
607 | heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
608 | }
609 |
610 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
611 | }
612 |
613 | @Override
614 | public boolean dispatchTouchEvent(MotionEvent ev) {
615 | if (mAutoPlayAble) {
616 | switch (ev.getAction()) {
617 | case MotionEvent.ACTION_DOWN:
618 | stopAutoPlay();
619 | break;
620 | case MotionEvent.ACTION_UP:
621 | case MotionEvent.ACTION_CANCEL:
622 | startAutoPlay();
623 | break;
624 | }
625 | }
626 | return super.dispatchTouchEvent(ev);
627 | }
628 |
629 | /**
630 | * 设置当只有一页数据时是否显示指示器
631 | */
632 | public void setIsNeedShowIndicatorOnOnlyOnePage(boolean isNeedShowIndicatorOnOnlyOnePage) {
633 | mIsNeedShowIndicatorOnOnlyOnePage = isNeedShowIndicatorOnOnlyOnePage;
634 | }
635 |
636 | public void setCurrentItem(int item) {
637 | if (mViewPager == null || mViews == null || item > getItemCount() - 1) {
638 | return;
639 | }
640 |
641 | if (mAutoPlayAble) {
642 | int realCurrentItem = mViewPager.getCurrentItem();
643 | int currentItem = realCurrentItem % mViews.size();
644 | int offset = item - currentItem;
645 |
646 | // 这里要使用循环递增或递减设置,否则会ANR
647 | if (offset < 0) {
648 | for (int i = -1; i >= offset; i--) {
649 | mViewPager.setCurrentItem(realCurrentItem + i, false);
650 | }
651 | } else if (offset > 0) {
652 | for (int i = 1; i <= offset; i++) {
653 | mViewPager.setCurrentItem(realCurrentItem + i, false);
654 | }
655 | }
656 |
657 | startAutoPlay();
658 | } else {
659 | mViewPager.setCurrentItem(item, false);
660 | }
661 | }
662 |
663 | @Override
664 | protected void onVisibilityChanged(View changedView, int visibility) {
665 | super.onVisibilityChanged(changedView, visibility);
666 | if (visibility == VISIBLE) {
667 | startAutoPlay();
668 | } else if (visibility == INVISIBLE || visibility == GONE) {
669 | onInvisibleToUser();
670 | }
671 | }
672 |
673 | private void onInvisibleToUser() {
674 | stopAutoPlay();
675 |
676 | // 处理 RecyclerView 中从对用户不可见变为可见时卡顿的问题
677 | if (!mIsFirstInvisible && mAutoPlayAble && mViewPager != null && getItemCount() > 0 && mPageScrollPositionOffset != 0) {
678 | mViewPager.setCurrentItem(mViewPager.getCurrentItem() - 1);
679 | mViewPager.setCurrentItem(mViewPager.getCurrentItem() + 1);
680 | }
681 | mIsFirstInvisible = false;
682 | }
683 |
684 | @Override
685 | protected void onDetachedFromWindow() {
686 | super.onDetachedFromWindow();
687 | onInvisibleToUser();
688 | }
689 |
690 | @Override
691 | protected void onAttachedToWindow() {
692 | super.onAttachedToWindow();
693 | startAutoPlay();
694 | }
695 |
696 | public void startAutoPlay() {
697 | stopAutoPlay();
698 | if (mAutoPlayAble) {
699 | postDelayed(mAutoPlayTask, mAutoPlayInterval);
700 | }
701 | }
702 |
703 | public void stopAutoPlay() {
704 | if (mAutoPlayTask != null) {
705 | removeCallbacks(mAutoPlayTask);
706 | }
707 | }
708 |
709 | private void switchToPoint(int newCurrentPoint) {
710 | if (mTipTv != null) {
711 | if (mTips == null || mTips.size() < 1 || newCurrentPoint >= mTips.size()) {
712 | mTipTv.setVisibility(View.GONE);
713 | } else {
714 | mTipTv.setVisibility(View.VISIBLE);
715 | mTipTv.setText(mTips.get(newCurrentPoint));
716 | }
717 | }
718 |
719 | if (mPointRealContainerLl != null) {
720 | if (mViews != null && mViews.size() > 0 && newCurrentPoint < mViews.size() && ((mIsNeedShowIndicatorOnOnlyOnePage || (
721 | !mIsNeedShowIndicatorOnOnlyOnePage && mViews.size() > 1)))) {
722 | mPointRealContainerLl.setVisibility(View.VISIBLE);
723 | for (int i = 0; i < mPointRealContainerLl.getChildCount(); i++) {
724 | mPointRealContainerLl.getChildAt(i).setSelected(i == newCurrentPoint);
725 | // 处理指示器选中和未选中状态图片尺寸不相等
726 | mPointRealContainerLl.getChildAt(i).requestLayout();
727 | }
728 | } else {
729 | mPointRealContainerLl.setVisibility(View.GONE);
730 | }
731 | }
732 |
733 | if (mNumberIndicatorTv != null) {
734 | if (mViews != null && mViews.size() > 0 && newCurrentPoint < mViews.size() && ((mIsNeedShowIndicatorOnOnlyOnePage || (
735 | !mIsNeedShowIndicatorOnOnlyOnePage && mViews.size() > 1)))) {
736 | mNumberIndicatorTv.setVisibility(View.VISIBLE);
737 | mNumberIndicatorTv.setText((newCurrentPoint + 1) + "/" + mViews.size());
738 | } else {
739 | mNumberIndicatorTv.setVisibility(View.GONE);
740 | }
741 | }
742 | }
743 |
744 | /**
745 | * 设置页面切换换动画
746 | */
747 | public void setTransitionEffect(TransitionEffect effect) {
748 | mTransitionEffect = effect;
749 | if (mViewPager != null) {
750 | initViewPager();
751 | if (mHackyViews == null) {
752 | BGABannerUtil.resetPageTransformer(mViews);
753 | } else {
754 | BGABannerUtil.resetPageTransformer(mHackyViews);
755 | }
756 | }
757 | }
758 |
759 | /**
760 | * 设置自定义页面切换动画
761 | */
762 | public void setPageTransformer(ViewPager.PageTransformer transformer) {
763 | if (transformer != null && mViewPager != null) {
764 | mViewPager.setPageTransformer(true, transformer);
765 | }
766 | }
767 |
768 | /**
769 | * 切换到下一页
770 | */
771 | private void switchToNextPage() {
772 | if (mViewPager != null) {
773 | mViewPager.setCurrentItem(mViewPager.getCurrentItem() + 1);
774 | }
775 | }
776 |
777 | @Override
778 | public void handleAutoPlayActionUpOrCancel(float xVelocity) {
779 | if (mViewPager != null) {
780 | if (mPageScrollPosition < mViewPager.getCurrentItem()) { // 往右滑
781 | if (xVelocity > VEL_THRESHOLD || (mPageScrollPositionOffset < 0.7f && xVelocity > -VEL_THRESHOLD)) {
782 | // 已达到右滑到接下来展示左边一页的条件,展示左边一页
783 | mViewPager.setBannerCurrentItemInternal(mPageScrollPosition, true);
784 | } else {
785 | // 未达到右滑到接下来展示左边一页的条件,展示当前页
786 | mViewPager.setBannerCurrentItemInternal(mPageScrollPosition + 1, true);
787 | }
788 | } else if (mPageScrollPosition == mViewPager.getCurrentItem()) { // 往左滑
789 | if (xVelocity < -VEL_THRESHOLD || (mPageScrollPositionOffset > 0.3f && xVelocity < VEL_THRESHOLD)) {
790 | // 已达到左滑到接下来展示右边一页的条件,展示右边一页
791 | mViewPager.setBannerCurrentItemInternal(mPageScrollPosition + 1, true);
792 | } else {
793 | // 未达到左滑到接下来展示右边一页的条件,展示当前页
794 | mViewPager.setBannerCurrentItemInternal(mPageScrollPosition, true);
795 | }
796 | } else {
797 | // 快速左滑优化异常场景。感谢 https://blog.csdn.net/lylddingHFFW/article/details/89212664
798 | mViewPager.setBannerCurrentItemInternal(mPageScrollPosition, true);
799 | }
800 | }
801 | }
802 |
803 | @Override
804 | public void onPageSelected(int position) {
805 | if (BGABannerUtil.isCollectionEmpty(mViews)) {
806 | return;
807 | }
808 | position = position % mViews.size();
809 | switchToPoint(position);
810 |
811 | if (mOnPageChangeListener != null) {
812 | mOnPageChangeListener.onPageSelected(position);
813 | }
814 | }
815 |
816 | @Override
817 | public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
818 | if (BGABannerUtil.isCollectionEmpty(mViews)) {
819 | return;
820 | }
821 | handleGuideViewVisibility(position % mViews.size(), positionOffset);
822 |
823 | mPageScrollPosition = position;
824 | mPageScrollPositionOffset = positionOffset;
825 |
826 | if (mTipTv != null) {
827 | if (BGABannerUtil.isCollectionNotEmpty(mTips)) {
828 | mTipTv.setVisibility(View.VISIBLE);
829 |
830 | int leftPosition = position % mTips.size();
831 | int rightPosition = (position + 1) % mTips.size();
832 | if (rightPosition < mTips.size() && leftPosition < mTips.size()) {
833 | if (positionOffset > 0.5) {
834 | mTipTv.setText(mTips.get(rightPosition));
835 | ViewCompat.setAlpha(mTipTv, positionOffset);
836 | } else {
837 | ViewCompat.setAlpha(mTipTv, 1 - positionOffset);
838 | mTipTv.setText(mTips.get(leftPosition));
839 | }
840 | }
841 | } else {
842 | mTipTv.setVisibility(View.GONE);
843 | }
844 | }
845 |
846 | if (mOnPageChangeListener != null) {
847 | mOnPageChangeListener.onPageScrolled(position % mViews.size(), positionOffset, positionOffsetPixels);
848 | }
849 | }
850 |
851 | @Override
852 | public void onPageScrollStateChanged(int state) {
853 | if (mOnPageChangeListener != null) {
854 | mOnPageChangeListener.onPageScrollStateChanged(state);
855 | }
856 | }
857 |
858 | private void handleGuideViewVisibility(int position, float positionOffset) {
859 | if (mEnterView == null && mSkipView == null) {
860 | return;
861 | }
862 | if (getItemCount() < 2) { // 只有一页时,有进入按钮则显示进入按钮并隐藏跳过按钮,没有进入按钮则显示跳过按钮
863 | if (mEnterView != null) {
864 | mEnterView.setVisibility(VISIBLE);
865 | if (mSkipView != null) {
866 | mSkipView.setVisibility(GONE);
867 | }
868 | return;
869 | }
870 | if (mSkipView != null) {
871 | mSkipView.setVisibility(VISIBLE);
872 | return;
873 | }
874 | }
875 |
876 | if (position == getItemCount() - 2) {
877 | if (mEnterView != null) {
878 | ViewCompat.setAlpha(mEnterView, positionOffset);
879 | }
880 | if (mSkipView != null) {
881 | ViewCompat.setAlpha(mSkipView, 1.0f - positionOffset);
882 | }
883 |
884 | if (positionOffset > 0.5f) {
885 | if (mEnterView != null) {
886 | mEnterView.setVisibility(View.VISIBLE);
887 | }
888 | if (mSkipView != null) {
889 | mSkipView.setVisibility(View.GONE);
890 | }
891 | } else {
892 | if (mEnterView != null) {
893 | mEnterView.setVisibility(View.GONE);
894 | }
895 | if (mSkipView != null) {
896 | mSkipView.setVisibility(View.VISIBLE);
897 | }
898 | }
899 | } else if (position == getItemCount() - 1) {
900 | if (mEnterView != null) {
901 | ViewCompat.setAlpha(mEnterView, 1.0f - positionOffset);
902 | }
903 | if (mSkipView != null) {
904 | ViewCompat.setAlpha(mSkipView, positionOffset);
905 | }
906 |
907 | if (positionOffset < 0.5f) {
908 | if (mEnterView != null) {
909 | mEnterView.setVisibility(View.VISIBLE);
910 | }
911 | if (mSkipView != null) {
912 | mSkipView.setVisibility(View.GONE);
913 | }
914 | } else {
915 | if (mEnterView != null) {
916 | mEnterView.setVisibility(View.GONE);
917 | }
918 | if (mSkipView != null) {
919 | mSkipView.setVisibility(View.VISIBLE);
920 | }
921 | }
922 | } else {
923 | if (mSkipView != null) {
924 | mSkipView.setVisibility(View.VISIBLE);
925 | ViewCompat.setAlpha(mSkipView, 1.0f);
926 | }
927 | if (mEnterView != null) {
928 | mEnterView.setVisibility(View.GONE);
929 | }
930 | }
931 | }
932 |
933 | public void setDelegate(Delegate delegate) {
934 | mDelegate = delegate;
935 | }
936 |
937 | public void setAdapter(Adapter adapter) {
938 | mAdapter = adapter;
939 | }
940 |
941 | private class PageAdapter extends PagerAdapter {
942 |
943 | @Override
944 | public int getCount() {
945 | return mViews == null ? 0 : (mAutoPlayAble ? Integer.MAX_VALUE : mViews.size());
946 | }
947 |
948 | @Override
949 | public Object instantiateItem(ViewGroup container, int position) {
950 | if (BGABannerUtil.isCollectionEmpty(mViews)) {
951 | return null;
952 | }
953 |
954 | final int finalPosition = position % mViews.size();
955 |
956 | View view;
957 | if (mHackyViews == null) {
958 | view = mViews.get(finalPosition);
959 | } else {
960 | view = mHackyViews.get(position % mHackyViews.size());
961 | }
962 |
963 | if (mDelegate != null) {
964 | view.setOnClickListener(new BGAOnNoDoubleClickListener() {
965 | @Override
966 | public void onNoDoubleClick(View view) {
967 | int currentPosition = mViewPager.getCurrentItem() % mViews.size();
968 |
969 | if (BGABannerUtil.isIndexNotOutOfBounds(currentPosition, mModels)) {
970 | mDelegate.onBannerItemClick(BGABanner.this, view, mModels.get(currentPosition), currentPosition);
971 | } else if (BGABannerUtil.isCollectionEmpty(mModels)) {
972 | mDelegate.onBannerItemClick(BGABanner.this, view, null, currentPosition);
973 | }
974 | }
975 | });
976 | }
977 |
978 | if (mAdapter != null) {
979 | if (BGABannerUtil.isIndexNotOutOfBounds(finalPosition, mModels)) {
980 | mAdapter.fillBannerItem(BGABanner.this, view, mModels.get(finalPosition), finalPosition);
981 | } else if (BGABannerUtil.isCollectionEmpty(mModels)) {
982 | mAdapter.fillBannerItem(BGABanner.this, view, null, finalPosition);
983 | }
984 | }
985 |
986 | ViewParent viewParent = view.getParent();
987 | if (viewParent != null) {
988 | ((ViewGroup) viewParent).removeView(view);
989 | }
990 |
991 | container.addView(view);
992 | return view;
993 | }
994 |
995 | @Override
996 | public void destroyItem(ViewGroup container, int position, Object object) {
997 | }
998 |
999 | @Override
1000 | public boolean isViewFromObject(View view, Object object) {
1001 | return view == object;
1002 | }
1003 |
1004 | @Override
1005 | public int getItemPosition(Object object) {
1006 | return POSITION_NONE;
1007 | }
1008 | }
1009 |
1010 | private static class AutoPlayTask implements Runnable {
1011 | private final WeakReference mBanner;
1012 |
1013 | private AutoPlayTask(BGABanner banner) {
1014 | mBanner = new WeakReference<>(banner);
1015 | }
1016 |
1017 | @Override
1018 | public void run() {
1019 | BGABanner banner = mBanner.get();
1020 | if (banner != null) {
1021 | banner.startAutoPlay();
1022 | banner.switchToNextPage();
1023 | }
1024 | }
1025 | }
1026 |
1027 | /**
1028 | * item 点击事件监听器,在 BGABanner 里已经帮开发者处理了防止重复点击事件
1029 | *
1030 | * @param item 视图类型,如果没有在 setData 方法里指定自定义的 item 布局资源文件的话,这里的 V 就是 ImageView
1031 | * @param item 数据模型
1032 | */
1033 | public interface Delegate {
1034 | void onBannerItemClick(BGABanner banner, V itemView, @Nullable M model, int position);
1035 | }
1036 |
1037 | /**
1038 | * 适配器,在 fillBannerItem 方法中填充数据,加载网络图片等
1039 | *
1040 | * @param item 视图类型,如果没有在 setData 方法里指定自定义的 item 布局资源文件的话,这里的 V 就是 ImageView
1041 | * @param item 数据模型
1042 | */
1043 | public interface Adapter {
1044 | void fillBannerItem(BGABanner banner, V itemView, @Nullable M model, int position);
1045 | }
1046 |
1047 | /**
1048 | * 引导页「进入」和「跳过」按钮点击事件监听器,在 BGABanner 里已经帮开发者处理了防止重复点击事件
1049 | */
1050 | public interface GuideDelegate {
1051 | void onClickEnterOrSkip();
1052 | }
1053 | }
--------------------------------------------------------------------------------
/library/src/main/java/cn/bingoogolapple/bgabanner/BGABannerScroller.java:
--------------------------------------------------------------------------------
1 | package cn.bingoogolapple.bgabanner;
2 |
3 | import android.content.Context;
4 | import android.widget.Scroller;
5 |
6 | /**
7 | * 作者:王浩 邮件:bingoogolapple@gmail.com
8 | * 创建时间:15/6/19 下午11:59
9 | * 描述:
10 | */
11 | public class BGABannerScroller extends Scroller {
12 | private int mDuration = 1000;
13 |
14 | public BGABannerScroller(Context context, int duration) {
15 | super(context);
16 | mDuration = duration;
17 | }
18 |
19 | @Override
20 | public void startScroll(int startX, int startY, int dx, int dy) {
21 | super.startScroll(startX, startY, dx, dy, mDuration);
22 | }
23 |
24 | @Override
25 | public void startScroll(int startX, int startY, int dx, int dy, int duration) {
26 | super.startScroll(startX, startY, dx, dy, mDuration);
27 | }
28 | }
--------------------------------------------------------------------------------
/library/src/main/java/cn/bingoogolapple/bgabanner/BGABannerUtil.java:
--------------------------------------------------------------------------------
1 | package cn.bingoogolapple.bgabanner;
2 |
3 | import android.content.Context;
4 | import android.graphics.Bitmap;
5 | import android.graphics.BitmapFactory;
6 | import androidx.annotation.DrawableRes;
7 | import androidx.annotation.NonNull;
8 | import androidx.annotation.Nullable;
9 | import androidx.core.util.Pair;
10 | import androidx.core.view.ViewCompat;
11 | import android.util.TypedValue;
12 | import android.view.View;
13 | import android.widget.ImageView;
14 |
15 | import java.io.IOException;
16 | import java.io.InputStream;
17 | import java.util.Collection;
18 | import java.util.List;
19 |
20 | /**
21 | * 作者:王浩 邮件:bingoogolapple@gmail.com
22 | * 创建时间:16/7/5 上午11:34
23 | * 描述:
24 | */
25 | public class BGABannerUtil {
26 |
27 | private BGABannerUtil() {
28 | }
29 |
30 | public static int dp2px(Context context, float dpValue) {
31 | return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpValue, context.getResources().getDisplayMetrics());
32 | }
33 |
34 | public static int sp2px(Context context, float spValue) {
35 | return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, spValue, context.getResources().getDisplayMetrics());
36 | }
37 |
38 | public static ImageView getItemImageView(Context context, @DrawableRes int resId, BGALocalImageSize localImageSize, ImageView.ScaleType scaleType) {
39 | ImageView imageView = new ImageView(context);
40 | imageView.setImageBitmap(getScaledImageFromResource(context, resId, localImageSize.getMaxWidth(), localImageSize.getMaxHeight(), localImageSize.getMinWidth(), localImageSize.getMinHeight()));
41 | imageView.setClickable(true);
42 | imageView.setScaleType(scaleType);
43 | return imageView;
44 | }
45 |
46 | public static void resetPageTransformer(List extends View> views) {
47 | if (views == null) {
48 | return;
49 | }
50 |
51 | for (View view : views) {
52 | view.setVisibility(View.VISIBLE);
53 | ViewCompat.setAlpha(view, 1);
54 | ViewCompat.setPivotX(view, view.getMeasuredWidth() * 0.5f);
55 | ViewCompat.setPivotY(view, view.getMeasuredHeight() * 0.5f);
56 | ViewCompat.setTranslationX(view, 0);
57 | ViewCompat.setTranslationY(view, 0);
58 | ViewCompat.setScaleX(view, 1);
59 | ViewCompat.setScaleY(view, 1);
60 | ViewCompat.setRotationX(view, 0);
61 | ViewCompat.setRotationY(view, 0);
62 | ViewCompat.setRotation(view, 0);
63 | }
64 | }
65 |
66 | public static boolean isIndexNotOutOfBounds(int position, Collection collection) {
67 | return isCollectionNotEmpty(collection) && position < collection.size();
68 | }
69 |
70 | public static boolean isCollectionEmpty(Collection collection, Collection... args) {
71 | if (collection == null || collection.isEmpty()) {
72 | return true;
73 | }
74 | for (Collection arg : args) {
75 | if (arg == null || arg.isEmpty()) {
76 | return true;
77 | }
78 | }
79 | return false;
80 | }
81 |
82 | public static boolean isCollectionNotEmpty(Collection collection, Collection... args) {
83 | return !isCollectionEmpty(collection, args);
84 | }
85 |
86 | /**
87 | * 从资源获取 Bitmap
88 | * bitmap 的宽高在 maxWidth maxHeight 和 minWidth minHeight 之间
89 | */
90 | @Nullable
91 | public static Bitmap getScaledImageFromResource(@NonNull Context context, int resId, int maxWidth, int maxHeight, float minWidth, float minHeight) {
92 | LoadBitmapPair result;
93 | do {
94 | result = getImageFromResource(context, resId, maxWidth, maxHeight);
95 | if (result != null && (result.first != null)) {
96 | break;
97 | }
98 | maxWidth /= 2;
99 | maxHeight /= 2;
100 | } while (result != null && result.second instanceof OutOfMemoryError && maxWidth > minWidth && maxHeight > minHeight);
101 |
102 | if (result == null) {
103 | return null;
104 | } else {
105 | return result.first;
106 | }
107 | }
108 |
109 | /**
110 | * 从资源获取Bitmap
111 | * 最大宽高为 maxWidth maxHeight
112 | */
113 | public static LoadBitmapPair getImageFromResource(@NonNull Context context, int resId, int maxWidth, int maxHeight) {
114 | LoadBitmapPair result;
115 | BitmapFactory.Options decodeOptions = new BitmapFactory.Options();
116 | Bitmap.Config preferredConfig = Bitmap.Config.RGB_565;
117 | InputStream is = null;
118 |
119 | try {
120 | if (maxWidth == 0 && maxHeight == 0) {
121 | decodeOptions.inPreferredConfig = preferredConfig;
122 | is = context.getResources().openRawResource(resId);
123 | result = new LoadBitmapPair<>(BitmapFactory.decodeStream(is, null, decodeOptions), null);
124 | is.close();
125 | } else {
126 | // If we have to resize this image, first get the natural
127 | // bounds.
128 | decodeOptions.inJustDecodeBounds = true;
129 | decodeOptions.inPreferredConfig = preferredConfig;
130 | is = context.getResources().openRawResource(resId);
131 | BitmapFactory.decodeStream(is, null, decodeOptions);
132 | is.reset();
133 | is.close();
134 |
135 | int actualWidth = decodeOptions.outWidth;
136 | int actualHeight = decodeOptions.outHeight;
137 |
138 | // Then compute the dimensions we would ideally like to decode to.
139 | int desiredWidth = getResizedDimension(maxWidth, maxHeight, actualWidth, actualHeight);
140 | int desiredHeight = getResizedDimension(maxHeight, maxWidth, actualHeight, actualWidth);
141 |
142 | // Decode to the nearest power of two scaling factor.
143 | decodeOptions.inJustDecodeBounds = false;
144 | // doesn't
145 | // support it?
146 | // decodeOptions.inPreferQualityOverSpeed =
147 | // PREFER_QUALITY_OVER_SPEED;
148 | decodeOptions.inSampleSize = calculateInSampleSize(decodeOptions, desiredWidth, desiredHeight);
149 | decodeOptions.inPreferredConfig = preferredConfig;
150 | is = context.getResources().openRawResource(resId);
151 | Bitmap tempBitmap = BitmapFactory.decodeStream(is, null, decodeOptions);
152 | is.close();
153 | // If necessary, scale down to the maximal acceptable size.
154 | if (tempBitmap != null && (tempBitmap.getWidth() > desiredWidth || tempBitmap.getHeight() > desiredHeight)) {
155 | result = new LoadBitmapPair<>(Bitmap.createScaledBitmap(tempBitmap, desiredWidth, desiredHeight, true), null);
156 | tempBitmap.recycle();
157 | } else {
158 | result = new LoadBitmapPair<>(tempBitmap, null);
159 | }
160 | }
161 | } catch (OutOfMemoryError exception) {
162 | exception.printStackTrace();
163 | result = new LoadBitmapPair(null, exception);
164 | } catch (Exception exception) {
165 | exception.printStackTrace();
166 | result = new LoadBitmapPair(null, exception);
167 | } finally {
168 | if (is != null) {
169 | try {
170 | is.close();
171 | } catch (IOException e) {
172 | e.printStackTrace();
173 | }
174 | }
175 | }
176 | return result;
177 | }
178 |
179 | private static class LoadBitmapPair extends Pair {
180 | LoadBitmapPair(@Nullable Bitmap first, @Nullable S second) {
181 | super(first, second);
182 | }
183 | }
184 |
185 | public static int getResizedDimension(int maxPrimary, int maxSecondary, int actualPrimary, int actualSecondary) {
186 | // If no dominant value at all, just return the actual.
187 | if (maxPrimary == 0 && maxSecondary == 0) {
188 | return actualPrimary;
189 | }
190 |
191 | // If primary is unspecified, scale primary to match secondary's scaling ratio.
192 | if (maxPrimary == 0) {
193 | double ratio = (double) maxSecondary / (double) actualSecondary;
194 | return (int) (actualPrimary * ratio);
195 | }
196 |
197 | if (maxSecondary == 0) {
198 | return maxPrimary;
199 | }
200 |
201 | double ratio = (double) actualSecondary / (double) actualPrimary;
202 | int resized = maxPrimary;
203 | if (resized * ratio > maxSecondary) {
204 | resized = (int) (maxSecondary / ratio);
205 | }
206 | return resized;
207 | }
208 |
209 | public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
210 | if (reqWidth == 0 || reqHeight == 0) {
211 | return 1;
212 | }
213 |
214 | // Raw height and width of image
215 | final int height = options.outHeight;
216 | final int width = options.outWidth;
217 | int inSampleSize = 1;
218 |
219 | if (height > reqHeight || width > reqWidth) {
220 |
221 | final int halfHeight = height / 2;
222 | final int halfWidth = width / 2;
223 |
224 | // Calculate the largest inSampleSize value that is a power of 2 and keeps both
225 | // height and width larger than the requested height and width.
226 | while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth) {
227 | inSampleSize *= 2;
228 | }
229 | }
230 |
231 | return inSampleSize;
232 | }
233 | }
--------------------------------------------------------------------------------
/library/src/main/java/cn/bingoogolapple/bgabanner/BGAGuideLinkageLayout.java:
--------------------------------------------------------------------------------
1 | package cn.bingoogolapple.bgabanner;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.view.MotionEvent;
6 | import android.view.View;
7 | import android.widget.FrameLayout;
8 |
9 | /**
10 | * 作者:王浩 邮件:bingoogolapple@gmail.com
11 | * 创建时间:16/8/7 上午11:39
12 | * 描述:引导界面联动布局,将每一个触摸事件分发给所有的子控件。
13 | */
14 | public class BGAGuideLinkageLayout extends FrameLayout {
15 | public BGAGuideLinkageLayout(Context context) {
16 | super(context);
17 | }
18 |
19 | public BGAGuideLinkageLayout(Context context, AttributeSet attrs) {
20 | super(context, attrs);
21 | }
22 |
23 | public BGAGuideLinkageLayout(Context context, AttributeSet attrs, int defStyleAttr) {
24 | super(context, attrs, defStyleAttr);
25 | }
26 |
27 | @Override
28 | public boolean dispatchTouchEvent(MotionEvent ev) {
29 | for (int i = 0; i < getChildCount(); i++) {
30 | View child = getChildAt(i);
31 | try {
32 | child.dispatchTouchEvent(ev);
33 | } catch (Exception e) {
34 | e.printStackTrace();
35 | }
36 | }
37 | return true;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/library/src/main/java/cn/bingoogolapple/bgabanner/BGALocalImageSize.java:
--------------------------------------------------------------------------------
1 | package cn.bingoogolapple.bgabanner;
2 |
3 | /**
4 | * 作者:王浩 邮件:bingoogolapple@gmail.com
5 | * 创建时间:2018/1/13
6 | * 描述:Bitmap 的宽高在 maxWidth maxHeight 和 minWidth minHeight 之间
7 | */
8 | public class BGALocalImageSize {
9 | private int maxWidth;
10 | private int maxHeight;
11 | private float minWidth;
12 | private float minHeight;
13 |
14 | public BGALocalImageSize(int maxWidth, int maxHeight, float minWidth, float minHeight) {
15 | this.maxWidth = maxWidth;
16 | this.maxHeight = maxHeight;
17 | this.minWidth = minWidth;
18 | this.minHeight = minHeight;
19 | }
20 |
21 | public int getMaxWidth() {
22 | return maxWidth;
23 | }
24 |
25 | public void setMaxWidth(int maxWidth) {
26 | this.maxWidth = maxWidth;
27 | }
28 |
29 | public int getMaxHeight() {
30 | return maxHeight;
31 | }
32 |
33 | public void setMaxHeight(int maxHeight) {
34 | this.maxHeight = maxHeight;
35 | }
36 |
37 | public float getMinWidth() {
38 | return minWidth;
39 | }
40 |
41 | public void setMinWidth(float minWidth) {
42 | this.minWidth = minWidth;
43 | }
44 |
45 | public float getMinHeight() {
46 | return minHeight;
47 | }
48 |
49 | public void setMinHeight(float minHeight) {
50 | this.minHeight = minHeight;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/library/src/main/java/cn/bingoogolapple/bgabanner/BGAOnNoDoubleClickListener.java:
--------------------------------------------------------------------------------
1 | package cn.bingoogolapple.bgabanner;
2 |
3 | import android.view.View;
4 |
5 | /**
6 | * 作者:王浩 邮件:bingoogolapple@gmail.com
7 | * 创建时间:16/12/7 下午9:13
8 | * 描述:
9 | */
10 | public abstract class BGAOnNoDoubleClickListener implements View.OnClickListener {
11 | private int mThrottleFirstTime = 1000;
12 | private long mLastClickTime = 0;
13 |
14 | public BGAOnNoDoubleClickListener() {
15 | }
16 |
17 | public BGAOnNoDoubleClickListener(int throttleFirstTime) {
18 | mThrottleFirstTime = throttleFirstTime;
19 | }
20 |
21 | @Override
22 | public void onClick(View v) {
23 | long currentTime = System.currentTimeMillis();
24 | if (currentTime - mLastClickTime > mThrottleFirstTime) {
25 | mLastClickTime = currentTime;
26 | onNoDoubleClick(v);
27 | }
28 | }
29 |
30 | public abstract void onNoDoubleClick(View v);
31 | }
32 |
--------------------------------------------------------------------------------
/library/src/main/java/cn/bingoogolapple/bgabanner/BGAViewPager.java:
--------------------------------------------------------------------------------
1 | package cn.bingoogolapple.bgabanner;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.view.MotionEvent;
6 | import android.view.VelocityTracker;
7 |
8 | import java.lang.reflect.Field;
9 | import java.lang.reflect.Method;
10 |
11 | import androidx.core.view.VelocityTrackerCompat;
12 | import androidx.core.view.ViewCompat;
13 | import androidx.viewpager.widget.ViewPager;
14 |
15 | /**
16 | * 作者:王浩 邮件:bingoogolapple@gmail.com
17 | * 创建时间:15/6/19 11:23
18 | * 描述:继承ViewPager,通过反射方式实现支持低版本上切换动画
19 | */
20 | public class BGAViewPager extends ViewPager {
21 | private boolean mAllowUserScrollable = true;
22 | private AutoPlayDelegate mAutoPlayDelegate;
23 |
24 | public BGAViewPager(Context context) {
25 | super(context);
26 | }
27 |
28 | public BGAViewPager(Context context, AttributeSet attrs) {
29 | super(context, attrs);
30 | }
31 |
32 | /**
33 | * 设置调用setCurrentItem(int item, boolean smoothScroll)方法时,page切换的时间长度
34 | *
35 | * @param duration page切换的时间长度
36 | */
37 | public void setPageChangeDuration(int duration) {
38 | try {
39 | Field scrollerField = ViewPager.class.getDeclaredField("mScroller");
40 | scrollerField.setAccessible(true);
41 | scrollerField.set(this, new BGABannerScroller(getContext(), duration));
42 | } catch (Exception e) {
43 | e.printStackTrace();
44 | }
45 | }
46 |
47 | /**
48 | * 切换到指定索引的页面,主要用于自动轮播
49 | *
50 | * @param position
51 | */
52 | public void setBannerCurrentItemInternal(int position, boolean smoothScroll) {
53 | Class viewpagerClass = ViewPager.class;
54 | try {
55 | Method setCurrentItemInternalMethod = viewpagerClass.getDeclaredMethod("setCurrentItemInternal", int.class, boolean.class, boolean.class);
56 | setCurrentItemInternalMethod.setAccessible(true);
57 | setCurrentItemInternalMethod.invoke(this, position, smoothScroll, true);
58 | ViewCompat.postInvalidateOnAnimation(this);
59 | } catch (Exception e) {
60 | e.printStackTrace();
61 | }
62 | }
63 |
64 | /**
65 | * 设置是否允许用户手指滑动
66 | *
67 | * @param allowUserScrollable true表示允许跟随用户触摸滑动,false反之
68 | */
69 | public void setAllowUserScrollable(boolean allowUserScrollable) {
70 | mAllowUserScrollable = allowUserScrollable;
71 | }
72 |
73 | @Override
74 | public boolean onInterceptTouchEvent(MotionEvent ev) {
75 | if (mAllowUserScrollable && getAdapter() != null && getAdapter().getCount() > 0) {
76 | return super.onInterceptTouchEvent(ev);
77 | } else {
78 | return false;
79 | }
80 | }
81 |
82 | @Override
83 | public boolean onTouchEvent(MotionEvent ev) {
84 | if (mAllowUserScrollable && getAdapter() != null && getAdapter().getCount() > 0) {
85 | if (mAutoPlayDelegate != null && (ev.getAction() == MotionEvent.ACTION_CANCEL || ev.getAction() == MotionEvent.ACTION_UP)) {
86 | mAutoPlayDelegate.handleAutoPlayActionUpOrCancel(getXVelocity());
87 | return false;
88 | } else {
89 | return super.onTouchEvent(ev);
90 | }
91 | } else {
92 | return false;
93 | }
94 | }
95 |
96 | private float getXVelocity() {
97 | float xVelocity = 0;
98 | Class viewpagerClass = ViewPager.class;
99 | try {
100 | Field velocityTrackerField = viewpagerClass.getDeclaredField("mVelocityTracker");
101 | velocityTrackerField.setAccessible(true);
102 | VelocityTracker velocityTracker = (VelocityTracker) velocityTrackerField.get(this);
103 |
104 | Field activePointerIdField = viewpagerClass.getDeclaredField("mActivePointerId");
105 | activePointerIdField.setAccessible(true);
106 |
107 | Field maximumVelocityField = viewpagerClass.getDeclaredField("mMaximumVelocity");
108 | maximumVelocityField.setAccessible(true);
109 | int maximumVelocity = maximumVelocityField.getInt(this);
110 |
111 | velocityTracker.computeCurrentVelocity(1000, maximumVelocity);
112 | xVelocity = VelocityTrackerCompat.getXVelocity(velocityTracker, activePointerIdField.getInt(this));
113 | } catch (Exception e) {
114 | }
115 | return xVelocity;
116 | }
117 |
118 | public void setAutoPlayDelegate(AutoPlayDelegate autoPlayDelegate) {
119 | mAutoPlayDelegate = autoPlayDelegate;
120 | }
121 |
122 | public interface AutoPlayDelegate {
123 | void handleAutoPlayActionUpOrCancel(float xVelocity);
124 | }
125 | }
--------------------------------------------------------------------------------
/library/src/main/java/cn/bingoogolapple/bgabanner/transformer/AccordionPageTransformer.java:
--------------------------------------------------------------------------------
1 | package cn.bingoogolapple.bgabanner.transformer;
2 |
3 | import androidx.core.view.ViewCompat;
4 | import android.view.View;
5 |
6 | /**
7 | * 作者:王浩 邮件:bingoogolapple@gmail.com
8 | * 创建时间:15/6/19 上午8:41
9 | * 描述:
10 | */
11 | public class AccordionPageTransformer extends BGAPageTransformer {
12 |
13 | @Override
14 | public void handleInvisiblePage(View view, float position) {
15 | }
16 |
17 | @Override
18 | public void handleLeftPage(View view, float position) {
19 | ViewCompat.setPivotX(view, view.getWidth());
20 | ViewCompat.setScaleX(view, 1.0f + position);
21 | }
22 |
23 | @Override
24 | public void handleRightPage(View view, float position) {
25 | ViewCompat.setPivotX(view, 0);
26 | ViewCompat.setScaleX(view, 1.0f - position);
27 | ViewCompat.setAlpha(view, 1);
28 | }
29 |
30 | }
--------------------------------------------------------------------------------
/library/src/main/java/cn/bingoogolapple/bgabanner/transformer/AlphaPageTransformer.java:
--------------------------------------------------------------------------------
1 | package cn.bingoogolapple.bgabanner.transformer;
2 |
3 | import androidx.core.view.ViewCompat;
4 | import android.view.View;
5 |
6 | /**
7 | * 作者:王浩 邮件:bingoogolapple@gmail.com
8 | * 创建时间:15/6/19 上午8:41
9 | * 描述:
10 | */
11 | public class AlphaPageTransformer extends BGAPageTransformer {
12 | private float mMinScale = 0.4f;
13 |
14 | public AlphaPageTransformer() {
15 | }
16 |
17 | public AlphaPageTransformer(float minScale) {
18 | setMinScale(minScale);
19 | }
20 |
21 | @Override
22 | public void handleInvisiblePage(View view, float position) {
23 | ViewCompat.setAlpha(view, 0);
24 | }
25 |
26 | @Override
27 | public void handleLeftPage(View view, float position) {
28 | ViewCompat.setAlpha(view, mMinScale + (1 - mMinScale) * (1 + position));
29 | }
30 |
31 | @Override
32 | public void handleRightPage(View view, float position) {
33 | ViewCompat.setAlpha(view, mMinScale + (1 - mMinScale) * (1 - position));
34 | }
35 |
36 | public void setMinScale(float minScale) {
37 | if (minScale >= 0.0f && minScale <= 1.0f) {
38 | mMinScale = minScale;
39 | }
40 | }
41 | }
--------------------------------------------------------------------------------
/library/src/main/java/cn/bingoogolapple/bgabanner/transformer/BGAPageTransformer.java:
--------------------------------------------------------------------------------
1 | package cn.bingoogolapple.bgabanner.transformer;
2 |
3 | import androidx.viewpager.widget.ViewPager;
4 | import android.view.View;
5 |
6 | /**
7 | * 作者:王浩 邮件:bingoogolapple@gmail.com
8 | * 创建时间:15/6/19 14:35
9 | * 描述:
10 | */
11 | public abstract class BGAPageTransformer implements ViewPager.PageTransformer {
12 |
13 | public void transformPage(View view, float position) {
14 | if (position < -1.0f) {
15 | // [-Infinity,-1)
16 | // This page is way off-screen to the left.
17 | handleInvisiblePage(view, position);
18 | } else if (position <= 0.0f) {
19 | // [-1,0]
20 | // Use the default slide transition when moving to the left page
21 | handleLeftPage(view, position);
22 | } else if (position <= 1.0f) {
23 | // (0,1]
24 | handleRightPage(view, position);
25 | } else {
26 | // (1,+Infinity]
27 | // This page is way off-screen to the right.
28 | handleInvisiblePage(view, position);
29 | }
30 | }
31 |
32 | public abstract void handleInvisiblePage(View view, float position);
33 |
34 | public abstract void handleLeftPage(View view, float position);
35 |
36 | public abstract void handleRightPage(View view, float position);
37 |
38 | public static BGAPageTransformer getPageTransformer(TransitionEffect effect) {
39 | switch (effect) {
40 | case Default:
41 | return new DefaultPageTransformer();
42 | case Alpha:
43 | return new AlphaPageTransformer();
44 | case Rotate:
45 | return new RotatePageTransformer();
46 | case Cube:
47 | return new CubePageTransformer();
48 | case Flip:
49 | return new FlipPageTransformer();
50 | case Accordion:
51 | return new AccordionPageTransformer();
52 | case ZoomFade:
53 | return new ZoomFadePageTransformer();
54 | case Fade:
55 | return new FadePageTransformer();
56 | case ZoomCenter:
57 | return new ZoomCenterPageTransformer();
58 | case ZoomStack:
59 | return new ZoomStackPageTransformer();
60 | case Stack:
61 | return new StackPageTransformer();
62 | case Depth:
63 | return new DepthPageTransformer();
64 | case Zoom:
65 | return new ZoomPageTransformer();
66 | default:
67 | return new DefaultPageTransformer();
68 | }
69 | }
70 | }
--------------------------------------------------------------------------------
/library/src/main/java/cn/bingoogolapple/bgabanner/transformer/CubePageTransformer.java:
--------------------------------------------------------------------------------
1 | package cn.bingoogolapple.bgabanner.transformer;
2 |
3 | import androidx.core.view.ViewCompat;
4 | import android.view.View;
5 |
6 | /**
7 | * 作者:王浩 邮件:bingoogolapple@gmail.com
8 | * 创建时间:15/6/19 17:39
9 | * 描述:
10 | */
11 | public class CubePageTransformer extends BGAPageTransformer {
12 | private float mMaxRotation = 90.0f;
13 |
14 | public CubePageTransformer() {
15 | }
16 |
17 | public CubePageTransformer(float maxRotation) {
18 | setMaxRotation(maxRotation);
19 | }
20 |
21 | @Override
22 | public void handleInvisiblePage(View view, float position) {
23 | ViewCompat.setPivotX(view, view.getMeasuredWidth());
24 | ViewCompat.setPivotY(view, view.getMeasuredHeight() * 0.5f);
25 | ViewCompat.setRotationY(view, 0);
26 | }
27 |
28 | @Override
29 | public void handleLeftPage(View view, float position) {
30 | ViewCompat.setPivotX(view, view.getMeasuredWidth());
31 | ViewCompat.setPivotY(view, view.getMeasuredHeight() * 0.5f);
32 | ViewCompat.setRotationY(view, mMaxRotation * position);
33 | }
34 |
35 | @Override
36 | public void handleRightPage(View view, float position) {
37 | ViewCompat.setPivotX(view, 0);
38 | ViewCompat.setPivotY(view, view.getMeasuredHeight() * 0.5f);
39 | ViewCompat.setRotationY(view, mMaxRotation * position);
40 | }
41 |
42 | public void setMaxRotation(float maxRotation) {
43 | if (maxRotation >= 0.0f && maxRotation <= 90.0f) {
44 | mMaxRotation = maxRotation;
45 | }
46 | }
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/library/src/main/java/cn/bingoogolapple/bgabanner/transformer/DefaultPageTransformer.java:
--------------------------------------------------------------------------------
1 | package cn.bingoogolapple.bgabanner.transformer;
2 |
3 | import android.view.View;
4 |
5 | /**
6 | * 作者:王浩 邮件:bingoogolapple@gmail.com
7 | * 创建时间:15/6/19 上午8:41
8 | * 描述:
9 | */
10 | public class DefaultPageTransformer extends BGAPageTransformer {
11 |
12 | @Override
13 | public void handleInvisiblePage(View view, float position) {
14 | }
15 |
16 | @Override
17 | public void handleLeftPage(View view, float position) {
18 | }
19 |
20 | @Override
21 | public void handleRightPage(View view, float position) {
22 | }
23 |
24 | }
--------------------------------------------------------------------------------
/library/src/main/java/cn/bingoogolapple/bgabanner/transformer/DepthPageTransformer.java:
--------------------------------------------------------------------------------
1 | package cn.bingoogolapple.bgabanner.transformer;
2 |
3 | import android.view.View;
4 |
5 | import androidx.core.view.ViewCompat;
6 |
7 | /**
8 | * 作者:王浩 邮件:bingoogolapple@gmail.com
9 | * 创建时间:15/6/19 上午8:41
10 | * 描述:
11 | */
12 | public class DepthPageTransformer extends BGAPageTransformer {
13 | private float mMinScale = 0.8f;
14 |
15 | public DepthPageTransformer() {
16 | }
17 |
18 | public DepthPageTransformer(float minScale) {
19 | setMinScale(minScale);
20 | }
21 |
22 | @Override
23 | public void handleInvisiblePage(View view, float position) {
24 | ViewCompat.setAlpha(view, 0);
25 | }
26 |
27 | @Override
28 | public void handleLeftPage(View view, float position) {
29 | ViewCompat.setAlpha(view, 1);
30 | ViewCompat.setTranslationX(view, 0);
31 | ViewCompat.setScaleX(view, 1);
32 | ViewCompat.setScaleY(view, 1);
33 | }
34 |
35 | @Override
36 | public void handleRightPage(View view, float position) {
37 | ViewCompat.setAlpha(view, 1 - position);
38 | ViewCompat.setTranslationX(view, -view.getWidth() * position);
39 | float scale = mMinScale + (1 - mMinScale) * (1 - position);
40 | ViewCompat.setScaleX(view, scale);
41 | ViewCompat.setScaleY(view, scale);
42 | }
43 |
44 | public void setMinScale(float minScale) {
45 | if (minScale >= 0.6f && minScale <= 1.0f) {
46 | mMinScale = minScale;
47 | }
48 | }
49 |
50 | }
--------------------------------------------------------------------------------
/library/src/main/java/cn/bingoogolapple/bgabanner/transformer/FadePageTransformer.java:
--------------------------------------------------------------------------------
1 | package cn.bingoogolapple.bgabanner.transformer;
2 |
3 | import androidx.core.view.ViewCompat;
4 | import android.view.View;
5 |
6 | /**
7 | * 作者:王浩 邮件:bingoogolapple@gmail.com
8 | * 创建时间:15/6/19 上午8:41
9 | * 描述:
10 | */
11 | public class FadePageTransformer extends BGAPageTransformer {
12 |
13 | @Override
14 | public void handleInvisiblePage(View view, float position) {
15 | }
16 |
17 | @Override
18 | public void handleLeftPage(View view, float position) {
19 | ViewCompat.setTranslationX(view, -view.getWidth() * position);
20 | ViewCompat.setAlpha(view, 1 + position);
21 | }
22 |
23 | @Override
24 | public void handleRightPage(View view, float position) {
25 | ViewCompat.setTranslationX(view, -view.getWidth() * position);
26 | ViewCompat.setAlpha(view, 1 - position);
27 | }
28 |
29 | }
--------------------------------------------------------------------------------
/library/src/main/java/cn/bingoogolapple/bgabanner/transformer/FlipPageTransformer.java:
--------------------------------------------------------------------------------
1 | package cn.bingoogolapple.bgabanner.transformer;
2 |
3 | import androidx.core.view.ViewCompat;
4 | import android.view.View;
5 |
6 | /**
7 | * 作者:王浩 邮件:bingoogolapple@gmail.com
8 | * 创建时间:15/6/19 上午8:41
9 | * 描述:
10 | */
11 | public class FlipPageTransformer extends BGAPageTransformer {
12 | private static final float ROTATION = 180.0f;
13 |
14 | @Override
15 | public void handleInvisiblePage(View view, float position) {
16 | }
17 |
18 | @Override
19 | public void handleLeftPage(View view, float position) {
20 | ViewCompat.setTranslationX(view, -view.getWidth() * position);
21 | float rotation = (ROTATION * position);
22 | ViewCompat.setRotationY(view, rotation);
23 |
24 | if (position > -0.5) {
25 | view.setVisibility(View.VISIBLE);
26 | } else {
27 | view.setVisibility(View.INVISIBLE);
28 | }
29 | }
30 |
31 | @Override
32 | public void handleRightPage(View view, float position) {
33 | ViewCompat.setTranslationX(view, -view.getWidth() * position);
34 | float rotation = (ROTATION * position);
35 | ViewCompat.setRotationY(view, rotation);
36 |
37 | if (position < 0.5) {
38 | view.setVisibility(View.VISIBLE);
39 | } else {
40 | view.setVisibility(View.INVISIBLE);
41 | }
42 | }
43 |
44 | }
--------------------------------------------------------------------------------
/library/src/main/java/cn/bingoogolapple/bgabanner/transformer/RotatePageTransformer.java:
--------------------------------------------------------------------------------
1 | package cn.bingoogolapple.bgabanner.transformer;
2 |
3 | import androidx.core.view.ViewCompat;
4 | import android.view.View;
5 |
6 | /**
7 | * 作者:王浩 邮件:bingoogolapple@gmail.com
8 | * 创建时间:15/6/19 上午8:41
9 | * 描述:
10 | */
11 | public class RotatePageTransformer extends BGAPageTransformer {
12 | private float mMaxRotation = 15.0f;
13 |
14 | public RotatePageTransformer() {
15 | }
16 |
17 | public RotatePageTransformer(float maxRotation) {
18 | setMaxRotation(maxRotation);
19 | }
20 |
21 | @Override
22 | public void handleInvisiblePage(View view, float position) {
23 | ViewCompat.setPivotX(view, view.getMeasuredWidth() * 0.5f);
24 | ViewCompat.setPivotY(view, view.getMeasuredHeight());
25 | ViewCompat.setRotation(view, 0);
26 | }
27 |
28 | @Override
29 | public void handleLeftPage(View view, float position) {
30 | float rotation = (mMaxRotation * position);
31 | ViewCompat.setPivotX(view, view.getMeasuredWidth() * 0.5f);
32 | ViewCompat.setPivotY(view, view.getMeasuredHeight());
33 | ViewCompat.setRotation(view, rotation);
34 | }
35 |
36 | @Override
37 | public void handleRightPage(View view, float position) {
38 | handleLeftPage(view, position);
39 | }
40 |
41 | public void setMaxRotation(float maxRotation) {
42 | if (maxRotation >= 0.0f && maxRotation <= 40.0f) {
43 | mMaxRotation = maxRotation;
44 | }
45 | }
46 | }
--------------------------------------------------------------------------------
/library/src/main/java/cn/bingoogolapple/bgabanner/transformer/StackPageTransformer.java:
--------------------------------------------------------------------------------
1 | package cn.bingoogolapple.bgabanner.transformer;
2 |
3 | import androidx.core.view.ViewCompat;
4 | import android.view.View;
5 |
6 | /**
7 | * 作者:王浩 邮件:bingoogolapple@gmail.com
8 | * 创建时间:15/6/19 上午8:41
9 | * 描述:
10 | */
11 | public class StackPageTransformer extends BGAPageTransformer {
12 |
13 | @Override
14 | public void handleInvisiblePage(View view, float position) {
15 | }
16 |
17 | @Override
18 | public void handleLeftPage(View view, float position) {
19 | }
20 |
21 | @Override
22 | public void handleRightPage(View view, float position) {
23 | ViewCompat.setTranslationX(view, -view.getWidth() * position);
24 | }
25 |
26 | }
--------------------------------------------------------------------------------
/library/src/main/java/cn/bingoogolapple/bgabanner/transformer/TransitionEffect.java:
--------------------------------------------------------------------------------
1 | package cn.bingoogolapple.bgabanner.transformer;
2 |
3 | /**
4 | * 作者:王浩 邮件:bingoogolapple@gmail.com
5 | * 创建时间:16/7/5 下午4:39
6 | * 描述:
7 | */
8 | public enum TransitionEffect {
9 | Default,
10 | Alpha,
11 | Rotate,
12 | Cube,
13 | Flip,
14 | Accordion,
15 | ZoomFade,
16 | Fade,
17 | ZoomCenter,
18 | ZoomStack,
19 | Stack,
20 | Depth,
21 | Zoom
22 | }
--------------------------------------------------------------------------------
/library/src/main/java/cn/bingoogolapple/bgabanner/transformer/ZoomCenterPageTransformer.java:
--------------------------------------------------------------------------------
1 | package cn.bingoogolapple.bgabanner.transformer;
2 |
3 | import androidx.core.view.ViewCompat;
4 | import android.view.View;
5 |
6 | /**
7 | * 作者:王浩 邮件:bingoogolapple@gmail.com
8 | * 创建时间:15/6/19 上午8:41
9 | * 描述:
10 | */
11 | public class ZoomCenterPageTransformer extends BGAPageTransformer {
12 |
13 | @Override
14 | public void handleInvisiblePage(View view, float position) {
15 | }
16 |
17 | @Override
18 | public void handleLeftPage(View view, float position) {
19 | ViewCompat.setTranslationX(view, -view.getWidth() * position);
20 |
21 | ViewCompat.setPivotX(view, view.getWidth() * 0.5f);
22 | ViewCompat.setPivotY(view, view.getHeight() * 0.5f);
23 | ViewCompat.setScaleX(view, 1 + position);
24 | ViewCompat.setScaleY(view, 1 + position);
25 |
26 | if (position < -0.95f) {
27 | ViewCompat.setAlpha(view, 0);
28 | } else {
29 | ViewCompat.setAlpha(view, 1);
30 | }
31 | }
32 |
33 | @Override
34 | public void handleRightPage(View view, float position) {
35 | ViewCompat.setTranslationX(view, -view.getWidth() * position);
36 |
37 | ViewCompat.setPivotX(view, view.getWidth() * 0.5f);
38 | ViewCompat.setPivotY(view, view.getHeight() * 0.5f);
39 | ViewCompat.setScaleX(view, 1 - position);
40 | ViewCompat.setScaleY(view, 1 - position);
41 |
42 | if (position > 0.95f) {
43 | ViewCompat.setAlpha(view, 0);
44 | } else {
45 | ViewCompat.setAlpha(view, 1);
46 | }
47 | }
48 |
49 | }
--------------------------------------------------------------------------------
/library/src/main/java/cn/bingoogolapple/bgabanner/transformer/ZoomFadePageTransformer.java:
--------------------------------------------------------------------------------
1 | package cn.bingoogolapple.bgabanner.transformer;
2 |
3 | import androidx.core.view.ViewCompat;
4 | import android.view.View;
5 |
6 | /**
7 | * 作者:王浩 邮件:bingoogolapple@gmail.com
8 | * 创建时间:15/6/19 上午8:41
9 | * 描述:
10 | */
11 | public class ZoomFadePageTransformer extends BGAPageTransformer {
12 |
13 | @Override
14 | public void handleInvisiblePage(View view, float position) {
15 | }
16 |
17 | @Override
18 | public void handleLeftPage(View view, float position) {
19 | ViewCompat.setTranslationX(view, -view.getWidth() * position);
20 |
21 | ViewCompat.setPivotX(view, view.getWidth() * 0.5f);
22 | ViewCompat.setPivotY(view, view.getHeight() * 0.5f);
23 | ViewCompat.setScaleX(view, 1 + position);
24 | ViewCompat.setScaleY(view, 1 + position);
25 |
26 | ViewCompat.setAlpha(view, 1 + position);
27 | }
28 |
29 | @Override
30 | public void handleRightPage(View view, float position) {
31 | ViewCompat.setTranslationX(view, -view.getWidth() * position);
32 |
33 | ViewCompat.setPivotX(view, view.getWidth() * 0.5f);
34 | ViewCompat.setPivotY(view, view.getHeight() * 0.5f);
35 | ViewCompat.setScaleX(view, 1 - position);
36 | ViewCompat.setScaleY(view, 1 - position);
37 | ViewCompat.setAlpha(view, 1 - position);
38 | }
39 |
40 | }
--------------------------------------------------------------------------------
/library/src/main/java/cn/bingoogolapple/bgabanner/transformer/ZoomPageTransformer.java:
--------------------------------------------------------------------------------
1 | package cn.bingoogolapple.bgabanner.transformer;
2 |
3 | import androidx.core.view.ViewCompat;
4 | import android.view.View;
5 |
6 | /**
7 | * 作者:王浩 邮件:bingoogolapple@gmail.com
8 | * 创建时间:15/6/19 上午8:41
9 | * 描述:
10 | */
11 | public class ZoomPageTransformer extends BGAPageTransformer {
12 | private float mMinScale = 0.85f;
13 | private float mMinAlpha = 0.65f;
14 |
15 | public ZoomPageTransformer() {
16 | }
17 |
18 | public ZoomPageTransformer(float minAlpha, float minScale) {
19 | setMinAlpha(minAlpha);
20 | setMinScale(minScale);
21 | }
22 |
23 | @Override
24 | public void handleInvisiblePage(View view, float position) {
25 | ViewCompat.setAlpha(view, 0);
26 | }
27 |
28 | @Override
29 | public void handleLeftPage(View view, float position) {
30 | float scale = Math.max(mMinScale, 1 + position);
31 | float vertMargin = view.getHeight() * (1 - scale) / 2;
32 | float horzMargin = view.getWidth() * (1 - scale) / 2;
33 | ViewCompat.setTranslationX(view, horzMargin - vertMargin / 2);
34 | ViewCompat.setScaleX(view, scale);
35 | ViewCompat.setScaleY(view, scale);
36 | ViewCompat.setAlpha(view, mMinAlpha + (scale - mMinScale) / (1 - mMinScale) * (1 - mMinAlpha));
37 | }
38 |
39 | @Override
40 | public void handleRightPage(View view, float position) {
41 | float scale = Math.max(mMinScale, 1 - position);
42 | float vertMargin = view.getHeight() * (1 - scale) / 2;
43 | float horzMargin = view.getWidth() * (1 - scale) / 2;
44 | ViewCompat.setTranslationX(view, -horzMargin + vertMargin / 2);
45 | ViewCompat.setScaleX(view, scale);
46 | ViewCompat.setScaleY(view, scale);
47 | ViewCompat.setAlpha(view, mMinAlpha + (scale - mMinScale) / (1 - mMinScale) * (1 - mMinAlpha));
48 | }
49 |
50 | public void setMinAlpha(float minAlpha) {
51 | if (minAlpha >= 0.6f && minAlpha <= 1.0f) {
52 | mMinAlpha = minAlpha;
53 | }
54 | }
55 |
56 | public void setMinScale(float minScale) {
57 | if (minScale >= 0.6f && minScale <= 1.0f) {
58 | mMinScale = minScale;
59 | }
60 | }
61 | }
--------------------------------------------------------------------------------
/library/src/main/java/cn/bingoogolapple/bgabanner/transformer/ZoomStackPageTransformer.java:
--------------------------------------------------------------------------------
1 | package cn.bingoogolapple.bgabanner.transformer;
2 |
3 | import android.view.View;
4 |
5 | import androidx.core.view.ViewCompat;
6 |
7 |
8 | /**
9 | * 作者:王浩 邮件:bingoogolapple@gmail.com
10 | * 创建时间:15/6/19 上午8:41
11 | * 描述:
12 | */
13 | public class ZoomStackPageTransformer extends BGAPageTransformer {
14 |
15 | @Override
16 | public void handleInvisiblePage(View view, float position) {
17 | }
18 |
19 | @Override
20 | public void handleLeftPage(View view, float position) {
21 | ViewCompat.setTranslationX(view, -view.getWidth() * position);
22 |
23 | ViewCompat.setPivotX(view, view.getWidth() * 0.5f);
24 | ViewCompat.setPivotY(view, view.getHeight() * 0.5f);
25 | ViewCompat.setScaleX(view, 1 + position);
26 | ViewCompat.setScaleY(view, 1 + position);
27 |
28 | if (position < -0.95f) {
29 | ViewCompat.setAlpha(view, 0);
30 | } else {
31 | ViewCompat.setAlpha(view, 1);
32 | }
33 | }
34 |
35 | @Override
36 | public void handleRightPage(View view, float position) {
37 | ViewCompat.setTranslationX(view, -view.getWidth() * position);
38 |
39 | ViewCompat.setPivotX(view, view.getWidth() * 0.5f);
40 | ViewCompat.setPivotY(view, view.getHeight() * 0.5f);
41 | ViewCompat.setScaleX(view, 1 + position);
42 | ViewCompat.setScaleY(view, 1 + position);
43 |
44 | if (position > 0.95f) {
45 | ViewCompat.setAlpha(view, 0);
46 | } else {
47 | ViewCompat.setAlpha(view, 1);
48 | }
49 | }
50 |
51 | }
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xhdpi/bga_banner_point_disabled.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bingoogolapple/BGABanner-Android/a328a9eb2e49bda75db0003b76be74524da66708/library/src/main/res/drawable-xhdpi/bga_banner_point_disabled.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xhdpi/bga_banner_point_enabled.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bingoogolapple/BGABanner-Android/a328a9eb2e49bda75db0003b76be74524da66708/library/src/main/res/drawable-xhdpi/bga_banner_point_enabled.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable/bga_banner_selector_point_hollow.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable/bga_banner_selector_point_solid.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
8 |
9 | -
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/library/src/main/res/layout/bga_banner_item_image.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/library/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/library/src/main/res/values/ids.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':demo', ':library'
2 |
--------------------------------------------------------------------------------