├── .gitignore
├── README.md
├── build.gradle
├── carouselbanner
├── .gitignore
├── build.gradle
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── iwdael
│ │ └── carouselbanner
│ │ ├── Banner.java
│ │ ├── CarouselBanner.java
│ │ ├── CoolCarouselBanner.java
│ │ ├── adapter
│ │ ├── CarouselAdapter.java
│ │ └── CoolCarouselAdapter.java
│ │ ├── base
│ │ ├── BaseBannerAdapter.java
│ │ ├── BaseViewHolder.java
│ │ └── CarouselBannerBase.java
│ │ ├── interfaces
│ │ ├── CarouselImageFactory.java
│ │ ├── OnCarouselItemChangeListener.java
│ │ └── OnCarouselItemClickListener.java
│ │ ├── layoutmanager
│ │ ├── BannerLayoutManager.java
│ │ ├── CenterScrollListener.java
│ │ ├── CoolBannerLayoutManager.java
│ │ └── OrientationHelper.java
│ │ └── viewholder
│ │ ├── CarouselViewHolder.java
│ │ └── CoolCarouselViewHolder.java
│ └── res
│ ├── layout
│ └── item_image.xml
│ └── values
│ ├── attr.xml
│ └── colors.xml
├── config.gradle
├── example
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── iwdael
│ │ └── carouselbanner
│ │ └── example
│ │ ├── ImageFactory.java
│ │ ├── Main2Activity.java
│ │ └── MainActivity.java
│ └── res
│ ├── layout
│ ├── activity_main.xml
│ └── activity_main2.xml
│ └── values
│ ├── colors.xml
│ ├── strings.xml
│ └── styles.xml
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── screenshot
├── CarouselBanner.gif
├── CoolCarouselBanner.gif
└── qq_group.png
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/caches
5 | /.idea/libraries
6 | /.idea/modules.xml
7 | /.idea/workspace.xml
8 | /.idea/navEditor.xml
9 | /.idea/assetWizardSettings.xml
10 | .DS_Store
11 | /build
12 | /captures
13 | .externalNativeBuild
14 | .cxx
15 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # CarouselBanner
2 | 
3 | 
4 | 
5 | 
6 | 
7 | 
8 |
9 | CarouselBanner 是一款展示图片或者广告的控件。它使用简单,不依赖其他第三方框架,而且把图片加载的过程通过接口的方式让使用者自行实现。
10 |
11 | 
12 |
13 | 
14 |
15 |
16 | ## 使用说明
17 | CarouselBanner可以设置滚动的方向,例如水平和垂直,也可以设置滚动的速度,滚动间隔时间,以及指示器的位置。CarouselBanner是普通的轮播控件,如果你想使用带有放缩效果的轮播控件,请使用CoolCarouselBanner。
18 |
19 | ### 代码示例
20 | #### 自定义加载器
21 | ```
22 | public class ImageFactory implements CarouselImageFactory {
23 | @Override
24 | public void onLoadFactory(String url, ImageView view) {
25 | Glide.with(view).load(url).into(view);
26 | }
27 | }
28 | ```
29 | #### 初始化
30 | ```
31 | Banner.init(new ImageFactory());
32 | ```
33 | #### 添加到布局
34 | ```
35 |
36 |
46 | ```
47 | #### 绑定数据
48 | ```
49 | banner = findViewById(R.id.banner);
50 | banner.setOnCarouselItemChangeListener(...);//滚动监听
51 | banner.setOnCarouselItemClickListener(...);//点击监听
52 | list.add("http://.............jpg");
53 | banner.initBanner(list);
54 | ```
55 |
56 | ## 快速引入项目
57 | 合并以下代码到需要使用的Module的dependencies中。
58 | ```Java
59 | dependencies {
60 | ...
61 | implementation 'com.iwdael:carouselbanner:$version'
62 | }
63 | ```
64 |
65 | ## 感谢浏览
66 | 如果你有任何疑问,请加入QQ群,我将竭诚为你解答。欢迎Star和Fork本仓库,当然也欢迎你关注我。
67 |
68 | 
69 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | buildscript {
3 | ext.kotlin_version = "1.4.21"
4 | repositories {
5 | google()
6 | jcenter()
7 | }
8 | dependencies {
9 | classpath "com.android.tools.build:gradle:4.0.2"
10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
11 |
12 | // NOTE: Do not place your application dependencies here; they belong
13 | // in the individual module build.gradle files
14 | }
15 | }
16 |
17 | allprojects {
18 | repositories {
19 | google()
20 | jcenter()
21 | }
22 | }
23 |
24 | task clean(type: Delete) {
25 | delete rootProject.buildDir
26 | }
--------------------------------------------------------------------------------
/carouselbanner/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/carouselbanner/build.gradle:
--------------------------------------------------------------------------------
1 | apply from: './../config.gradle'
2 | apply plugin: 'com.android.library'
3 | apply plugin: 'kotlin-android'
4 | apply plugin: 'kotlin-android-extensions'
5 | android {
6 | buildToolsVersion buidConfig.buildToolsVersion
7 | compileSdkVersion buidConfig.compileSdkVersion
8 | defaultConfig {
9 | minSdkVersion buidConfig.minSdkVersion
10 | targetSdkVersion buidConfig.targetSdkVersion
11 | versionCode buidConfig.versionCode
12 | versionName buidConfig.versionName
13 | }
14 | }
15 |
16 | dependencies {
17 | implementation dependent.kotlinJdk7
18 | compileOnly dependent.appcompat
19 | compileOnly dependent.recyclerview
20 | compileOnly dependent.cardview
21 | }
--------------------------------------------------------------------------------
/carouselbanner/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/carouselbanner/src/main/java/com/iwdael/carouselbanner/Banner.java:
--------------------------------------------------------------------------------
1 | package com.iwdael.carouselbanner;
2 |
3 | import com.iwdael.carouselbanner.interfaces.CarouselImageFactory;
4 |
5 | public class Banner {
6 | public static volatile Banner sBanner;
7 | private CarouselImageFactory factory;
8 |
9 | private Banner() {
10 | }
11 |
12 | public static void init(CarouselImageFactory factory) {
13 | if (sBanner == null) {
14 | synchronized (Banner.class) {
15 | if (sBanner == null)
16 | sBanner = new Banner();
17 | }
18 | }
19 | sBanner.factory = factory;
20 | }
21 |
22 | public static CarouselImageFactory factory() {
23 | if (sBanner == null) {
24 | synchronized (Banner.class) {
25 | if (sBanner == null)
26 | sBanner = new Banner();
27 | }
28 | }
29 | if (sBanner.factory == null)
30 | throw new RuntimeException("CarouselBanner must be initialized by \"Banner.init\" method !!!");
31 | return sBanner.factory;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/carouselbanner/src/main/java/com/iwdael/carouselbanner/CarouselBanner.java:
--------------------------------------------------------------------------------
1 | package com.iwdael.carouselbanner;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.view.View;
6 |
7 | import androidx.recyclerview.widget.RecyclerView;
8 |
9 | import com.iwdael.carouselbanner.adapter.CarouselAdapter;
10 | import com.iwdael.carouselbanner.base.CarouselBannerBase;
11 | import com.iwdael.carouselbanner.interfaces.OnCarouselItemClickListener;
12 | import com.iwdael.carouselbanner.layoutmanager.BannerLayoutManager;
13 |
14 | import java.util.List;
15 |
16 | /**
17 | * author : Iwdael
18 | * e-mail : iwdael@outlook.com
19 | * github : http://github.com/iwdael
20 | * project : CarouselBanner
21 | */
22 | public class CarouselBanner extends CarouselBannerBase {
23 |
24 | public CarouselBanner(Context context) {
25 | this(context, null);
26 | }
27 |
28 | public CarouselBanner(Context context, AttributeSet attrs) {
29 | this(context, attrs, 0);
30 | }
31 |
32 | public CarouselBanner(Context context, AttributeSet attrs, int defStyleAttr) {
33 | super(context, attrs, defStyleAttr);
34 | }
35 |
36 | @Override
37 | protected void onBannerScrolled(RecyclerView recyclerView, int dx, int dy) {
38 | //解决连续滑动时指示器不更新的问题
39 | if (bannerSize < 2) return;
40 | int firstReal = mLayoutManager.findFirstVisibleItemPosition();
41 | View viewFirst = mLayoutManager.findViewByPosition(firstReal);
42 | float width = getWidth();
43 | if (width != 0 && viewFirst != null) {
44 | float right = viewFirst.getRight();
45 | float ratio = right / width;
46 | if (ratio > 0.8) {
47 | if (currentIndex != firstReal) {
48 | currentIndex = firstReal;
49 | refreshIndicator();
50 | }
51 | } else if (ratio < 0.2) {
52 | if (currentIndex != firstReal + 1) {
53 | currentIndex = firstReal + 1;
54 | refreshIndicator();
55 | }
56 | }
57 | }
58 | }
59 |
60 | @Override
61 | protected void onBannerScrollStateChanged(RecyclerView recyclerView, int newState) {
62 | int first = mLayoutManager.findFirstVisibleItemPosition();
63 | int last = mLayoutManager.findLastVisibleItemPosition();
64 | if (currentIndex != first && first == last) {
65 | currentIndex = first;
66 | refreshIndicator();
67 | }
68 | }
69 |
70 | @Override
71 | protected BannerLayoutManager getLayoutManager(Context context, int orientation) {
72 | return new BannerLayoutManager(context, orientation, false, speedPerPixelMillisecond);
73 | }
74 |
75 | @Override
76 | protected CarouselAdapter getAdapter(List list, OnCarouselItemClickListener onBannerItemClickListener) {
77 | return new CarouselAdapter(list, onBannerItemClickListener);
78 | }
79 |
80 |
81 | }
--------------------------------------------------------------------------------
/carouselbanner/src/main/java/com/iwdael/carouselbanner/CoolCarouselBanner.java:
--------------------------------------------------------------------------------
1 | package com.iwdael.carouselbanner;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 |
6 | import androidx.recyclerview.widget.RecyclerView;
7 |
8 | import com.iwdael.carouselbanner.adapter.CoolCarouselAdapter;
9 | import com.iwdael.carouselbanner.base.CarouselBannerBase;
10 | import com.iwdael.carouselbanner.interfaces.OnCarouselItemClickListener;
11 | import com.iwdael.carouselbanner.layoutmanager.CoolBannerLayoutManager;
12 |
13 | import java.util.List;
14 |
15 | /**
16 | * author : Iwdael
17 | * e-mail : iwdael@outlook.com
18 | * github : http://github.com/iwdael
19 | * project : CarouselBanner
20 | */
21 | public class CoolCarouselBanner extends CarouselBannerBase {
22 |
23 |
24 | public CoolCarouselBanner(Context context) {
25 | this(context, null);
26 | }
27 |
28 | public CoolCarouselBanner(Context context, AttributeSet attrs) {
29 | this(context, attrs, 0);
30 | }
31 |
32 | public CoolCarouselBanner(Context context, AttributeSet attrs, int defStyleAttr) {
33 | super(context, attrs, defStyleAttr);
34 | }
35 |
36 | @Override
37 | protected void onBannerScrolled(RecyclerView recyclerView, int dx, int dy) {
38 |
39 | }
40 |
41 | @Override
42 | protected void onBannerScrollStateChanged(RecyclerView recyclerView, int newState) {
43 | int first = mLayoutManager.getCurrentPosition();
44 | if (currentIndex != first) {
45 | currentIndex = first;
46 | refreshIndicator();
47 | }
48 | }
49 |
50 | @Override
51 | protected CoolBannerLayoutManager getLayoutManager(Context context, int orientation) {
52 | return new CoolBannerLayoutManager(orientation, dp2px(10),speedPerPixelMillisecond);
53 | }
54 |
55 | @Override
56 | protected CoolCarouselAdapter getAdapter(List list, OnCarouselItemClickListener onBannerItemClickListener) {
57 | return new CoolCarouselAdapter(list, onBannerItemClickListener);
58 | }
59 |
60 |
61 | }
--------------------------------------------------------------------------------
/carouselbanner/src/main/java/com/iwdael/carouselbanner/adapter/CarouselAdapter.java:
--------------------------------------------------------------------------------
1 | package com.iwdael.carouselbanner.adapter;
2 |
3 | import android.view.ViewGroup;
4 | import android.widget.ImageView;
5 |
6 | import com.iwdael.carouselbanner.base.BaseBannerAdapter;
7 | import com.iwdael.carouselbanner.interfaces.OnCarouselItemClickListener;
8 | import com.iwdael.carouselbanner.viewholder.CarouselViewHolder;
9 |
10 | import java.util.List;
11 |
12 | /**
13 | * author : Iwdael
14 | * e-mail : iwdael@outlook.com
15 | * github : http://github.com/iwdael
16 | * project : CarouselBanner
17 | */
18 | public class CarouselAdapter extends BaseBannerAdapter {
19 |
20 | public CarouselAdapter(List urlList, OnCarouselItemClickListener onBannerItemClickListener) {
21 | super(urlList, onBannerItemClickListener);
22 | }
23 |
24 | @Override
25 | public CarouselViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
26 | return new CarouselViewHolder(new ImageView(parent.getContext()));
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/carouselbanner/src/main/java/com/iwdael/carouselbanner/adapter/CoolCarouselAdapter.java:
--------------------------------------------------------------------------------
1 | package com.iwdael.carouselbanner.adapter;
2 |
3 | import android.view.LayoutInflater;
4 | import android.view.ViewGroup;
5 |
6 | import com.iwdael.carouselbanner.R;
7 | import com.iwdael.carouselbanner.base.BaseBannerAdapter;
8 | import com.iwdael.carouselbanner.interfaces.OnCarouselItemClickListener;
9 | import com.iwdael.carouselbanner.viewholder.CoolCarouselViewHolder;
10 |
11 | import java.util.List;
12 |
13 | /**
14 | * author : Iwdael
15 | * e-mail : iwdael@outlook.com
16 | * github : http://github.com/iwdael
17 | * project : CarouselBanner
18 | */
19 | public class CoolCarouselAdapter extends BaseBannerAdapter {
20 |
21 | public CoolCarouselAdapter(List urlList, OnCarouselItemClickListener onBannerItemClickListener) {
22 | super(urlList, onBannerItemClickListener);
23 | }
24 |
25 | @Override
26 | public CoolCarouselViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
27 | return new CoolCarouselViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_image, parent, false));
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/carouselbanner/src/main/java/com/iwdael/carouselbanner/base/BaseBannerAdapter.java:
--------------------------------------------------------------------------------
1 | package com.iwdael.carouselbanner.base;
2 |
3 |
4 | import androidx.recyclerview.widget.RecyclerView;
5 |
6 | import com.iwdael.carouselbanner.interfaces.OnCarouselItemClickListener;
7 |
8 | import java.util.List;
9 |
10 | /**
11 | * author : Iwdael
12 | * e-mail : iwdael@outlook.com
13 | * github : http://github.com/iwdael
14 | * project : CarouselBanner
15 | */
16 | public abstract class BaseBannerAdapter extends RecyclerView.Adapter {
17 | protected List urlList;
18 | protected OnCarouselItemClickListener onClickListener;
19 |
20 | public BaseBannerAdapter(List urlList, OnCarouselItemClickListener onBannerItemClickListener) {
21 | this.urlList = urlList;
22 | this.onClickListener = onBannerItemClickListener;
23 | }
24 |
25 | @Override
26 | public void onBindViewHolder(VH holder, int position) {
27 | holder.bindData(urlList.get(position % urlList.size()), position % urlList.size(), onClickListener);
28 | }
29 |
30 | @Override
31 | public int getItemCount() {
32 | return urlList.size() < 2 ? 1 : Integer.MAX_VALUE;
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/carouselbanner/src/main/java/com/iwdael/carouselbanner/base/BaseViewHolder.java:
--------------------------------------------------------------------------------
1 | package com.iwdael.carouselbanner.base;
2 |
3 | import android.view.View;
4 | import android.widget.ImageView;
5 |
6 | import androidx.recyclerview.widget.RecyclerView;
7 |
8 | import com.iwdael.carouselbanner.Banner;
9 | import com.iwdael.carouselbanner.interfaces.OnCarouselItemClickListener;
10 |
11 | /**
12 | * author : Iwdael
13 | * e-mail : iwdael@outlook.com
14 | * github : http://github.com/iwdael
15 | * project : CarouselBanner
16 | */
17 |
18 | public class BaseViewHolder extends RecyclerView.ViewHolder {
19 | protected ImageView imageView;
20 |
21 | public BaseViewHolder(View itemView) {
22 | super(itemView);
23 | }
24 |
25 | public void bindData(final String url, final int position, final OnCarouselItemClickListener onClickListener) {
26 | Banner.factory().onLoadFactory(url, imageView);
27 | if (onClickListener != null) {
28 | imageView.setOnClickListener(new View.OnClickListener() {
29 | @Override
30 | public void onClick(View v) {
31 | onClickListener.onItemClick(position, url);
32 | }
33 | });
34 | }
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/carouselbanner/src/main/java/com/iwdael/carouselbanner/base/CarouselBannerBase.java:
--------------------------------------------------------------------------------
1 | package com.iwdael.carouselbanner.base;
2 |
3 | import android.content.Context;
4 | import android.content.res.Resources;
5 | import android.content.res.TypedArray;
6 | import android.graphics.drawable.Drawable;
7 | import android.graphics.drawable.GradientDrawable;
8 | import android.graphics.drawable.LayerDrawable;
9 | import android.os.Handler;
10 | import android.os.Message;
11 | import android.text.TextUtils;
12 | import android.util.AttributeSet;
13 | import android.util.TypedValue;
14 | import android.view.Gravity;
15 | import android.view.MotionEvent;
16 | import android.view.ViewGroup;
17 | import android.widget.FrameLayout;
18 | import android.widget.ImageView;
19 |
20 | import androidx.annotation.ColorRes;
21 | import androidx.core.content.ContextCompat;
22 | import androidx.core.view.GravityCompat;
23 | import androidx.recyclerview.widget.LinearLayoutManager;
24 | import androidx.recyclerview.widget.PagerSnapHelper;
25 | import androidx.recyclerview.widget.RecyclerView;
26 |
27 | import com.iwdael.carouselbanner.R;
28 | import com.iwdael.carouselbanner.interfaces.OnCarouselItemChangeListener;
29 | import com.iwdael.carouselbanner.interfaces.OnCarouselItemClickListener;
30 |
31 | import java.util.ArrayList;
32 | import java.util.List;
33 |
34 | /**
35 | * author : Iwdael
36 | * e-mail : iwdael@outlook.com
37 | * github : http://github.com/iwdael
38 | * project : CarouselBanner
39 | */
40 | public abstract class CarouselBannerBase extends FrameLayout {
41 |
42 | protected int autoPlayDuration;//刷新间隔时间
43 |
44 | protected boolean showIndicator;//是否显示指示器
45 | protected RecyclerView indicatorContainer;
46 | protected Drawable mSelectedDrawable;
47 | protected Drawable mUnselectedDrawable;
48 | protected IndicatorAdapter indicatorAdapter;
49 | protected float speedPerPixelMillisecond;
50 | protected int indicatorMargin;//指示器间距
51 |
52 | protected RecyclerView mRecyclerView;
53 | protected A adapter;
54 | protected L mLayoutManager;
55 |
56 | protected int WHAT_AUTO_PLAY = 1000;
57 |
58 | protected boolean hasInit;
59 | protected int bannerSize = 1;
60 | protected int currentIndex;
61 | protected boolean isPlaying;
62 |
63 | protected boolean isAutoPlaying;
64 | protected List tempUrlList = new ArrayList<>();
65 |
66 | protected OnCarouselItemClickListener onBannerItemClickListener;
67 | protected OnCarouselItemChangeListener onCarouselItemChangeListener;
68 |
69 |
70 | protected Handler mHandler = new Handler(new Handler.Callback() {
71 | @Override
72 | public boolean handleMessage(Message msg) {
73 | if (msg.what == WHAT_AUTO_PLAY) {
74 | mRecyclerView.smoothScrollToPosition(++currentIndex);
75 | refreshIndicator();
76 | mHandler.sendEmptyMessageDelayed(WHAT_AUTO_PLAY, autoPlayDuration);
77 | }
78 | return false;
79 | }
80 | });
81 |
82 | public CarouselBannerBase(Context context) {
83 | this(context, null);
84 | }
85 |
86 | public CarouselBannerBase(Context context, AttributeSet attrs) {
87 | this(context, attrs, 0);
88 | }
89 |
90 | public CarouselBannerBase(Context context, AttributeSet attrs, int defStyleAttr) {
91 | super(context, attrs, defStyleAttr);
92 | initView(context, attrs);
93 | }
94 |
95 | protected void initView(Context context, AttributeSet attrs) {
96 | TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CarouselBannerBase);
97 | showIndicator = a.getBoolean(R.styleable.CarouselBannerBase_showIndicator, true);
98 | autoPlayDuration = a.getInt(R.styleable.CarouselBannerBase_interval, 4000);
99 | isAutoPlaying = a.getBoolean(R.styleable.CarouselBannerBase_autoPlaying, true);
100 | mSelectedDrawable = a.getDrawable(R.styleable.CarouselBannerBase_indicatorSelectedSrc);
101 | mUnselectedDrawable = a.getDrawable(R.styleable.CarouselBannerBase_indicatorUnselectedSrc);
102 | speedPerPixelMillisecond = a.getFloat(R.styleable.CarouselBannerBase_speedPerPixelMillisecond, 0.8f);
103 | if (mSelectedDrawable == null) {
104 | //绘制默认选中状态图形
105 | GradientDrawable selectedGradientDrawable = new GradientDrawable();
106 | selectedGradientDrawable.setShape(GradientDrawable.OVAL);
107 | selectedGradientDrawable.setColor(getColor(R.color.selectIndicationColor));
108 | selectedGradientDrawable.setSize(dp2px(5), dp2px(5));
109 | selectedGradientDrawable.setCornerRadius(dp2px(5) / 2);
110 | mSelectedDrawable = new LayerDrawable(new Drawable[]{selectedGradientDrawable});
111 | }
112 | if (mUnselectedDrawable == null) {
113 | //绘制默认未选中状态图形
114 | GradientDrawable unSelectedGradientDrawable = new GradientDrawable();
115 | unSelectedGradientDrawable.setShape(GradientDrawable.OVAL);
116 | unSelectedGradientDrawable.setColor(getColor(R.color.unSelectIndicationColor));
117 | unSelectedGradientDrawable.setSize(dp2px(5), dp2px(5));
118 | unSelectedGradientDrawable.setCornerRadius(dp2px(5) / 2);
119 | mUnselectedDrawable = new LayerDrawable(new Drawable[]{unSelectedGradientDrawable});
120 | }
121 | indicatorMargin = a.getDimensionPixelSize(R.styleable.CarouselBannerBase_indicatorSpace, dp2px(4));
122 | int marginLeft = a.getDimensionPixelSize(R.styleable.CarouselBannerBase_indicatorMarginLeft, dp2px(16));
123 | int marginRight = a.getDimensionPixelSize(R.styleable.CarouselBannerBase_indicatorMarginRight, dp2px(0));
124 | int marginBottom = a.getDimensionPixelSize(R.styleable.CarouselBannerBase_indicatorMarginBottom, dp2px(11));
125 | int g = a.getInt(R.styleable.CarouselBannerBase_indicatorGravity, 0);
126 | int gravity;
127 | if (g == 0) {
128 | gravity = GravityCompat.START;
129 | } else if (g == 2) {
130 | gravity = GravityCompat.END;
131 | } else {
132 | gravity = Gravity.CENTER;
133 | }
134 | int o = a.getInt(R.styleable.CarouselBannerBase_orientation, 0);
135 | int orientation = 0;
136 | if (o == 0) {
137 | orientation = LinearLayoutManager.HORIZONTAL;
138 | } else if (o == 1) {
139 | orientation = LinearLayoutManager.VERTICAL;
140 | }
141 | a.recycle();
142 | //recyclerView部分
143 | mRecyclerView = new RecyclerView(context);
144 | new PagerSnapHelper().attachToRecyclerView(mRecyclerView);
145 | mLayoutManager = getLayoutManager(context, orientation);
146 | mRecyclerView.setLayoutManager(mLayoutManager);
147 | mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
148 |
149 | @Override
150 | public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
151 | onBannerScrolled(recyclerView, dx, dy);
152 | }
153 |
154 | @Override
155 | public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
156 | onBannerScrollStateChanged(recyclerView, newState);
157 | }
158 | });
159 | LayoutParams vpLayoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
160 | ViewGroup.LayoutParams.MATCH_PARENT);
161 | addView(mRecyclerView, vpLayoutParams);
162 | //指示器部分
163 | indicatorContainer = new RecyclerView(context);
164 |
165 | LinearLayoutManager indicatorLayoutManager = new LinearLayoutManager(context, orientation, false);
166 | indicatorContainer.setLayoutManager(indicatorLayoutManager);
167 | indicatorAdapter = new IndicatorAdapter();
168 | indicatorContainer.setAdapter(indicatorAdapter);
169 | LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
170 | params.gravity = Gravity.BOTTOM | gravity;
171 | params.setMargins(marginLeft, 0, marginRight, marginBottom);
172 | addView(indicatorContainer, params);
173 | if (!showIndicator) {
174 | indicatorContainer.setVisibility(GONE);
175 | }
176 | }
177 |
178 | protected abstract void onBannerScrolled(RecyclerView recyclerView, int dx, int dy);
179 |
180 | protected abstract void onBannerScrollStateChanged(RecyclerView recyclerView, int newState);
181 |
182 | protected abstract L getLayoutManager(Context context, int orientation);
183 |
184 | protected abstract A getAdapter(List list, OnCarouselItemClickListener onBannerItemClickListener);
185 |
186 | public void setIndicatorInterval(int millisecond) {
187 | this.autoPlayDuration = millisecond;
188 | }
189 |
190 |
191 | protected void setPlaying(boolean playing) {
192 | if (isAutoPlaying && hasInit) {
193 | if (!isPlaying && playing && adapter != null && adapter.getItemCount() > 2) {
194 | mHandler.sendEmptyMessageDelayed(WHAT_AUTO_PLAY, autoPlayDuration);
195 | isPlaying = true;
196 | } else if (isPlaying && !playing) {
197 | mHandler.removeMessages(WHAT_AUTO_PLAY);
198 | isPlaying = false;
199 | }
200 | }
201 | }
202 |
203 | public void setAutoPlaying(boolean isAutoPlaying) {
204 | this.isAutoPlaying = isAutoPlaying;
205 | setPlaying(this.isAutoPlaying);
206 | }
207 |
208 | public boolean isPlaying() {
209 | return isPlaying;
210 | }
211 |
212 | public void setShowIndicator(boolean showIndicator) {
213 | this.showIndicator = showIndicator;
214 | indicatorContainer.setVisibility(showIndicator ? VISIBLE : GONE);
215 | }
216 |
217 | public void setOnCarouselItemClickListener(OnCarouselItemClickListener onBannerItemClickListener) {
218 | this.onBannerItemClickListener = onBannerItemClickListener;
219 | }
220 |
221 | public void setOnCarouselItemChangeListener(OnCarouselItemChangeListener onCarouselItemChangeListener) {
222 | this.onCarouselItemChangeListener = onCarouselItemChangeListener;
223 | }
224 |
225 | public void initBanner(List newList) {
226 | //解决recyclerView嵌套问题
227 | if (compareListDifferent(newList, tempUrlList)) {
228 | hasInit = false;
229 | setVisibility(VISIBLE);
230 | setPlaying(false);
231 | adapter = getAdapter(newList, this.onBannerItemClickListener);
232 | mRecyclerView.setAdapter(adapter);
233 | tempUrlList = newList;
234 | bannerSize = tempUrlList.size();
235 | if (bannerSize > 1) {
236 | indicatorContainer.setVisibility(VISIBLE);
237 | currentIndex = bannerSize * 10000;
238 | mRecyclerView.scrollToPosition(currentIndex);
239 | indicatorAdapter.notifyDataSetChanged();
240 | } else {
241 | indicatorContainer.setVisibility(GONE);
242 | currentIndex = 0;
243 | }
244 | hasInit = true;
245 | setPlaying(true);
246 | }
247 | if (!showIndicator) {
248 | indicatorContainer.setVisibility(GONE);
249 | }
250 | }
251 |
252 |
253 | @Override
254 | public boolean dispatchTouchEvent(MotionEvent ev) {
255 | switch (ev.getAction()) {
256 | case MotionEvent.ACTION_DOWN:
257 | setPlaying(false);
258 | break;
259 | case MotionEvent.ACTION_UP:
260 | case MotionEvent.ACTION_CANCEL:
261 | setPlaying(true);
262 | break;
263 | }
264 | //解决recyclerView嵌套问题
265 | try {
266 | return super.dispatchTouchEvent(ev);
267 | } catch (IllegalArgumentException ex) {
268 | ex.printStackTrace();
269 | }
270 | return false;
271 | }
272 |
273 | //解决recyclerView嵌套问题
274 | @Override
275 | public boolean onTouchEvent(MotionEvent ev) {
276 | try {
277 | return super.onTouchEvent(ev);
278 | } catch (IllegalArgumentException ex) {
279 | ex.printStackTrace();
280 | }
281 | return false;
282 | }
283 |
284 | //解决recyclerView嵌套问题
285 | @Override
286 | public boolean onInterceptTouchEvent(MotionEvent ev) {
287 | try {
288 | return super.onInterceptTouchEvent(ev);
289 | } catch (IllegalArgumentException ex) {
290 | ex.printStackTrace();
291 | }
292 | return false;
293 | }
294 |
295 | @Override
296 | protected void onAttachedToWindow() {
297 | super.onAttachedToWindow();
298 | setPlaying(true);
299 | }
300 |
301 | @Override
302 | protected void onDetachedFromWindow() {
303 | super.onDetachedFromWindow();
304 | setPlaying(false);
305 | }
306 |
307 | @Override
308 | protected void onWindowVisibilityChanged(int visibility) {
309 | super.onWindowVisibilityChanged(visibility);
310 | if (visibility == VISIBLE) {
311 | setPlaying(true);
312 | } else {
313 | setPlaying(false);
314 | }
315 | }
316 |
317 |
318 | protected class IndicatorAdapter extends RecyclerView.Adapter {
319 |
320 | int currentPosition = 0;
321 |
322 | public void setPosition(int currentPosition) {
323 | this.currentPosition = currentPosition;
324 | }
325 |
326 | @Override
327 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
328 |
329 | ImageView bannerPoint = new ImageView(getContext());
330 | RecyclerView.LayoutParams lp = new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
331 | ViewGroup.LayoutParams.WRAP_CONTENT);
332 | lp.setMargins(indicatorMargin, indicatorMargin, indicatorMargin, indicatorMargin);
333 | bannerPoint.setLayoutParams(lp);
334 | return new RecyclerView.ViewHolder(bannerPoint) {
335 | };
336 | }
337 |
338 | @Override
339 | public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
340 | ImageView bannerPoint = (ImageView) holder.itemView;
341 | bannerPoint.setImageDrawable(currentPosition == position ? mSelectedDrawable : mUnselectedDrawable);
342 |
343 | }
344 |
345 | @Override
346 | public int getItemCount() {
347 | return bannerSize;
348 | }
349 | }
350 |
351 |
352 | /**
353 | * author : Iwdael
354 | * e-mail : iwdael@outlook.com
355 | * github : http://github.com/iwdael
356 | * project : CarouselBanner
357 | */
358 | protected void refreshIndicator() {
359 | if (showIndicator && bannerSize > 1) {
360 | indicatorAdapter.setPosition(currentIndex % bannerSize);
361 | indicatorAdapter.notifyDataSetChanged();
362 | }
363 | if (onCarouselItemChangeListener != null)
364 | onCarouselItemChangeListener.onItemChange(currentIndex % bannerSize);
365 | }
366 |
367 |
368 | protected int dp2px(int dp) {
369 | return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, Resources.getSystem().getDisplayMetrics());
370 | }
371 |
372 | /**
373 | * author : Iwdael
374 | * e-mail : iwdael@outlook.com
375 | * github : http://github.com/iwdael
376 | * project : CarouselBanner
377 | */
378 | protected int getColor(@ColorRes int color) {
379 | return ContextCompat.getColor(getContext(), color);
380 | }
381 |
382 | protected boolean compareListDifferent(List newTabList, List oldTabList) {
383 | if (oldTabList == null || oldTabList.isEmpty())
384 | return true;
385 | if (newTabList.size() != oldTabList.size())
386 | return true;
387 | for (int i = 0; i < newTabList.size(); i++) {
388 | if (TextUtils.isEmpty(newTabList.get(i)))
389 | return true;
390 | if (!newTabList.get(i).equals(oldTabList.get(i))) {
391 | return true;
392 | }
393 | }
394 | return false;
395 | }
396 |
397 | }
398 |
--------------------------------------------------------------------------------
/carouselbanner/src/main/java/com/iwdael/carouselbanner/interfaces/CarouselImageFactory.java:
--------------------------------------------------------------------------------
1 | package com.iwdael.carouselbanner.interfaces;
2 |
3 | import android.widget.ImageView;
4 |
5 | /**
6 | * author : Iwdael
7 | * e-mail : iwdael@outlook.com
8 | * github : http://github.com/iwdael
9 | * project : CarouselBanner
10 | */
11 |
12 | public interface CarouselImageFactory {
13 | void onLoadFactory(String url, ImageView view);
14 | }
15 |
--------------------------------------------------------------------------------
/carouselbanner/src/main/java/com/iwdael/carouselbanner/interfaces/OnCarouselItemChangeListener.java:
--------------------------------------------------------------------------------
1 | package com.iwdael.carouselbanner.interfaces;
2 |
3 | /**
4 | * author : Iwdael
5 | * e-mail : iwdael@outlook.com
6 | * github : http://github.com/iwdael
7 | * project : CarouselBanner
8 | */
9 |
10 | public interface OnCarouselItemChangeListener {
11 | void onItemChange(int position);
12 | }
13 |
--------------------------------------------------------------------------------
/carouselbanner/src/main/java/com/iwdael/carouselbanner/interfaces/OnCarouselItemClickListener.java:
--------------------------------------------------------------------------------
1 | package com.iwdael.carouselbanner.interfaces;
2 |
3 | /**
4 | * author : Iwdael
5 | * e-mail : iwdael@outlook.com
6 | * github : http://github.com/iwdael
7 | * project : CarouselBanner
8 | */
9 |
10 | public interface OnCarouselItemClickListener {
11 |
12 | void onItemClick(int position, String url);
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/carouselbanner/src/main/java/com/iwdael/carouselbanner/layoutmanager/BannerLayoutManager.java:
--------------------------------------------------------------------------------
1 | package com.iwdael.carouselbanner.layoutmanager;
2 |
3 | import android.content.Context;
4 | import android.graphics.PointF;
5 | import android.util.AttributeSet;
6 | import android.util.DisplayMetrics;
7 |
8 | import androidx.annotation.Nullable;
9 | import androidx.recyclerview.widget.LinearLayoutManager;
10 | import androidx.recyclerview.widget.LinearSmoothScroller;
11 | import androidx.recyclerview.widget.RecyclerView;
12 |
13 | /**
14 | * author : Iwdael
15 | * e-mail : iwdael@outlook.com
16 | * github : http://github.com/iwdael
17 | * project : CarouselBanner
18 | */
19 |
20 | public class BannerLayoutManager extends LinearLayoutManager {
21 |
22 | private float speedPerPixelMillisecond;
23 |
24 | public BannerLayoutManager(Context context) {
25 | super(context);
26 | }
27 |
28 | public BannerLayoutManager(Context context, int orientation, boolean reverseLayout) {
29 | super(context, orientation, reverseLayout);
30 | }
31 | public BannerLayoutManager(Context context, int orientation, boolean reverseLayout , float speedPerPixelMillisecond) {
32 | super(context, orientation, reverseLayout);
33 | this.speedPerPixelMillisecond=speedPerPixelMillisecond;
34 | }
35 |
36 | public BannerLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
37 | super(context, attrs, defStyleAttr, defStyleRes);
38 | }
39 |
40 | @Override
41 | public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
42 | CenterSmoothScroller centerSmoothScroller = new CenterSmoothScroller(recyclerView.getContext());
43 | centerSmoothScroller.setTargetPosition(position);
44 | startSmoothScroll(centerSmoothScroller);
45 | }
46 |
47 |
48 | private class CenterSmoothScroller extends LinearSmoothScroller {
49 |
50 | CenterSmoothScroller(Context context) {
51 | super(context);
52 | }
53 |
54 | @Nullable
55 | @Override
56 | public PointF computeScrollVectorForPosition(int targetPosition) {
57 | return BannerLayoutManager.this.computeScrollVectorForPosition(targetPosition);
58 | }
59 |
60 | @Override
61 | public int calculateDtToFit(int viewStart, int viewEnd, int boxStart, int boxEnd, int snapPreference) {
62 | return (boxStart + (boxEnd - boxStart) / 2) - (viewStart + (viewEnd - viewStart) / 2);
63 | }
64 |
65 | protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
66 | return speedPerPixelMillisecond;
67 | }
68 |
69 | @Override
70 | protected int getVerticalSnapPreference() {
71 | return SNAP_TO_START;
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/carouselbanner/src/main/java/com/iwdael/carouselbanner/layoutmanager/CenterScrollListener.java:
--------------------------------------------------------------------------------
1 | package com.iwdael.carouselbanner.layoutmanager;
2 |
3 |
4 | import androidx.recyclerview.widget.RecyclerView;
5 |
6 | /**
7 | * author : Iwdael
8 | * e-mail : iwdael@outlook.com
9 | * github : http://github.com/iwdael
10 | * project : CarouselBanner
11 | */
12 | public class CenterScrollListener extends RecyclerView.OnScrollListener {
13 | private boolean mAutoSet = false;
14 |
15 | @Override
16 | public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
17 | super.onScrollStateChanged(recyclerView, newState);
18 | final RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
19 | if (!(layoutManager instanceof CoolBannerLayoutManager)) {
20 | mAutoSet = true;
21 | return;
22 | }
23 |
24 | final CoolBannerLayoutManager.OnPageChangeListener onPageChangeListener = ((CoolBannerLayoutManager) layoutManager).onPageChangeListener;
25 | if (onPageChangeListener != null) {
26 | onPageChangeListener.onPageScrollStateChanged(newState);
27 | }
28 |
29 | if (newState == RecyclerView.SCROLL_STATE_IDLE) {
30 | if (mAutoSet) {
31 | if (onPageChangeListener != null) {
32 | onPageChangeListener.onPageSelected(((CoolBannerLayoutManager) layoutManager).getCurrentPosition());
33 | }
34 | mAutoSet = false;
35 | } else {
36 | final int delta;
37 | delta = ((CoolBannerLayoutManager) layoutManager).getOffsetToCenter();
38 | if (delta != 0) {
39 | if (((CoolBannerLayoutManager) layoutManager).getOrientation() == CoolBannerLayoutManager.VERTICAL)
40 | recyclerView.smoothScrollBy(0, delta);
41 | else
42 | recyclerView.smoothScrollBy(delta, 0);
43 | mAutoSet = true;
44 | } else {
45 | if (onPageChangeListener != null) {
46 | onPageChangeListener.onPageSelected(((CoolBannerLayoutManager) layoutManager).getCurrentPosition());
47 | }
48 | mAutoSet = false;
49 | }
50 | }
51 | } else if (newState == RecyclerView.SCROLL_STATE_DRAGGING || newState == RecyclerView.SCROLL_STATE_SETTLING) {
52 | mAutoSet = false;
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/carouselbanner/src/main/java/com/iwdael/carouselbanner/layoutmanager/CoolBannerLayoutManager.java:
--------------------------------------------------------------------------------
1 | package com.iwdael.carouselbanner.layoutmanager;
2 |
3 | import android.content.Context;
4 | import android.graphics.PointF;
5 | import android.util.DisplayMetrics;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 |
9 | import androidx.annotation.Nullable;
10 | import androidx.recyclerview.widget.LinearSmoothScroller;
11 | import androidx.recyclerview.widget.RecyclerView;
12 |
13 | import static androidx.recyclerview.widget.RecyclerView.NO_POSITION;
14 |
15 |
16 | /**
17 | * author : Iwdael
18 | * e-mail : iwdael@outlook.com
19 | * github : http://github.com/iwdael
20 | * project : CarouselBanner
21 | */
22 | public class CoolBannerLayoutManager extends RecyclerView.LayoutManager implements RecyclerView.SmoothScroller.ScrollVectorProvider {
23 |
24 | private static final float SCALE_RATE = 1.2f;
25 | private float speedPerPixelMillisecond;
26 | private int mOrientation = HORIZONTAL;
27 |
28 | private static final int HORIZONTAL = OrientationHelper.HORIZONTAL;
29 | static final int VERTICAL = OrientationHelper.VERTICAL;
30 |
31 | private int mDecoratedMeasurement;
32 |
33 | private int mDecoratedMeasurementInOther;
34 |
35 | private int itemSpace;
36 |
37 | private int mSpaceMain;
38 |
39 | private int mSpaceInOther;
40 |
41 |
42 | private float mOffset;
43 |
44 |
45 | private OrientationHelper mOrientationHelper;
46 |
47 |
48 | private boolean mSmoothScrollbarEnabled = true;
49 |
50 |
51 | private int mPendingScrollPosition = NO_POSITION;
52 |
53 |
54 | private float mInterval; //the mInterval of each item's mOffset
55 |
56 | OnPageChangeListener onPageChangeListener;
57 |
58 | private boolean mInfinite = false;
59 |
60 | private int mLeftItems;
61 |
62 | private int mRightItems;
63 |
64 |
65 | public CoolBannerLayoutManager() {
66 | this(HORIZONTAL, 0,0.8f);
67 | }
68 |
69 |
70 | public CoolBannerLayoutManager(int orientation, int itemSpace,float speedPerPixelMillisecond) {
71 | this.itemSpace = itemSpace;
72 | setOrientation(orientation);
73 | setAutoMeasureEnabled(true);
74 | this.speedPerPixelMillisecond=speedPerPixelMillisecond;
75 | }
76 |
77 |
78 | private float setInterval() {
79 | return mDecoratedMeasurement * ((1.2f - 1) / 2 + 1) + itemSpace;
80 | }
81 |
82 |
83 |
84 | private float calculateScale(float x) {
85 | float deltaX = Math.abs(x - (mOrientationHelper.getTotalSpace() - mDecoratedMeasurement) / 2f);
86 | float diff = 0f;
87 | if ((mDecoratedMeasurement - deltaX) > 0) diff = mDecoratedMeasurement - deltaX;
88 | return (SCALE_RATE - 1f) / mDecoratedMeasurement * diff + 1;
89 | }
90 |
91 |
92 | private float setViewElevation(View itemView, float targetOffset) {
93 | return 0;
94 | }
95 |
96 | @Override
97 | public RecyclerView.LayoutParams generateDefaultLayoutParams() {
98 | return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
99 | ViewGroup.LayoutParams.WRAP_CONTENT);
100 | }
101 |
102 |
103 |
104 | @Override
105 | public boolean canScrollHorizontally() {
106 | return mOrientation == HORIZONTAL;
107 | }
108 |
109 |
110 | @Override
111 | public boolean canScrollVertically() {
112 | return mOrientation == VERTICAL;
113 | }
114 |
115 |
116 | int getOrientation() {
117 | return mOrientation;
118 | }
119 |
120 |
121 | void setOrientation(int orientation) {
122 | if (orientation != HORIZONTAL && orientation != VERTICAL) {
123 | throw new IllegalArgumentException("invalid orientation:" + orientation);
124 | }
125 | assertNotInLayoutOrScroll(null);
126 | if (orientation == mOrientation) {
127 | return;
128 | }
129 | mOrientation = orientation;
130 | mOrientationHelper = null;
131 | removeAllViews();
132 | }
133 |
134 | @Override
135 | public View findViewByPosition(int position) {
136 | final int childCount = getChildCount();
137 | if (childCount == 0) {
138 | return null;
139 | }
140 | final int firstChild = getPosition(getChildAt(0));
141 | final int viewPosition = position - firstChild;
142 | if (viewPosition >= 0 && viewPosition < childCount) {
143 | final View child = getChildAt(viewPosition);
144 | if (getPosition(child) == position) {
145 | return child; // in pre-layout, this may not match
146 | }
147 | }
148 | return super.findViewByPosition(position);
149 | }
150 |
151 | @Override
152 | public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
153 | CenterSmoothScroller smoothScroller = new CenterSmoothScroller(recyclerView.getContext());
154 | smoothScroller.setTargetPosition(position);
155 | startSmoothScroll(smoothScroller);
156 | }
157 |
158 |
159 | private class CenterSmoothScroller extends LinearSmoothScroller {
160 |
161 | CenterSmoothScroller(Context context) {
162 | super(context);
163 | }
164 |
165 | @Nullable
166 | @Override
167 | public PointF computeScrollVectorForPosition(int targetPosition) {
168 | return CoolBannerLayoutManager.this.computeScrollVectorForPosition(targetPosition);
169 | }
170 |
171 | @Override
172 | public int calculateDtToFit(int viewStart, int viewEnd, int boxStart, int boxEnd, int snapPreference) {
173 | return (boxStart + (boxEnd - boxStart) / 2) - (viewStart + (viewEnd - viewStart) / 2);
174 | }
175 |
176 | protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
177 | return speedPerPixelMillisecond;
178 | }
179 |
180 | @Override
181 | protected int getVerticalSnapPreference() {
182 | return SNAP_TO_START;
183 | }
184 | }
185 |
186 |
187 | public PointF computeScrollVectorForPosition(int targetPosition) {
188 | if (getChildCount() == 0) {
189 | return null;
190 | }
191 | final int firstChildPos = getPosition(getChildAt(0));
192 | final float direction = targetPosition < firstChildPos ?
193 | -1 / getDistanceRatio() : 1 / getDistanceRatio();
194 | if (mOrientation == HORIZONTAL) {
195 | return new PointF(direction, 0);
196 | } else {
197 | return new PointF(0, direction);
198 | }
199 | }
200 |
201 | @Override
202 | public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
203 | if (state.getItemCount() == 0) {
204 | removeAndRecycleAllViews(recycler);
205 | mOffset = 0;
206 | return;
207 | }
208 | if (mOrientationHelper == null) {
209 | mOrientationHelper = OrientationHelper.createOrientationHelper(this, mOrientation);
210 | }
211 | if (getChildCount() == 0) {
212 | View scrap = recycler.getViewForPosition(0);
213 | measureChildWithMargins(scrap, 0, 0);
214 | mDecoratedMeasurement = mOrientationHelper.getDecoratedMeasurement(scrap);
215 | mDecoratedMeasurementInOther = mOrientationHelper.getDecoratedMeasurementInOther(scrap);
216 | mSpaceMain = (mOrientationHelper.getTotalSpace() - mDecoratedMeasurement) / 2;
217 | mSpaceInOther = (mOrientationHelper.getTotalSpaceInOther() - mDecoratedMeasurementInOther) / 2;
218 | mInterval = setInterval();
219 | mLeftItems = (int) Math.abs(minRemoveOffset() / mInterval) + 1;
220 | mRightItems = (int) Math.abs(maxRemoveOffset() / mInterval) + 1;
221 | }
222 | if (mPendingScrollPosition != NO_POSITION) {
223 | mOffset = mPendingScrollPosition * mInterval;
224 | }
225 | detachAndScrapAttachedViews(recycler);
226 | layoutItems(recycler);
227 | }
228 |
229 | @Override
230 | public void onLayoutCompleted(RecyclerView.State state) {
231 | super.onLayoutCompleted(state);
232 | mPendingScrollPosition = NO_POSITION;
233 | }
234 |
235 |
236 | private float getProperty(int position) {
237 | return position * mInterval;
238 | }
239 |
240 | @Override
241 | public void onAdapterChanged(RecyclerView.Adapter oldAdapter, RecyclerView.Adapter newAdapter) {
242 | removeAllViews();
243 | mOffset = 0;
244 | }
245 |
246 | @Override
247 | public void scrollToPosition(int position) {
248 | mPendingScrollPosition = position;
249 | mOffset = position * mInterval;
250 | requestLayout();
251 | }
252 |
253 | @Override
254 | public int computeHorizontalScrollOffset(RecyclerView.State state) {
255 | return computeScrollOffset();
256 | }
257 |
258 | @Override
259 | public int computeVerticalScrollOffset(RecyclerView.State state) {
260 | return computeScrollOffset();
261 | }
262 |
263 | @Override
264 | public int computeHorizontalScrollExtent(RecyclerView.State state) {
265 | return computeScrollExtent();
266 | }
267 |
268 | @Override
269 | public int computeVerticalScrollExtent(RecyclerView.State state) {
270 | return computeScrollExtent();
271 | }
272 |
273 | @Override
274 | public int computeHorizontalScrollRange(RecyclerView.State state) {
275 | return computeScrollRange();
276 | }
277 |
278 | @Override
279 | public int computeVerticalScrollRange(RecyclerView.State state) {
280 | return computeScrollRange();
281 | }
282 |
283 | private int computeScrollOffset() {
284 | if (getChildCount() == 0) {
285 | return 0;
286 | }
287 |
288 | if (!mSmoothScrollbarEnabled) {
289 | return getItemCount() - getCurrentPosition() - 1;
290 | }
291 |
292 | final float realOffset = getOffsetOfRightAdapterPosition();
293 | return (int) realOffset;
294 | }
295 |
296 | private int computeScrollExtent() {
297 | if (getChildCount() == 0) {
298 | return 0;
299 | }
300 |
301 | if (!mSmoothScrollbarEnabled) {
302 | return 1;
303 | }
304 |
305 | return (int) mInterval;
306 | }
307 |
308 | private int computeScrollRange() {
309 | if (getChildCount() == 0) {
310 | return 0;
311 | }
312 |
313 | if (!mSmoothScrollbarEnabled) {
314 | return getItemCount();
315 | }
316 |
317 | return (int) (getItemCount() * mInterval);
318 | }
319 |
320 | @Override
321 | public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
322 | if (mOrientation == VERTICAL) {
323 | return 0;
324 | }
325 | return scrollBy(dx, recycler, state);
326 | }
327 |
328 | @Override
329 | public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
330 | if (mOrientation == HORIZONTAL) {
331 | return 0;
332 | }
333 | return scrollBy(dy, recycler, state);
334 | }
335 |
336 | private int scrollBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
337 | if (getChildCount() == 0 || dy == 0) {
338 | return 0;
339 | }
340 | if (mOrientationHelper == null) {
341 | mOrientationHelper = OrientationHelper.createOrientationHelper(this, mOrientation);
342 | }
343 | int willScroll = dy;
344 |
345 | float realDx = dy / getDistanceRatio();
346 | if (Math.abs(realDx) < 0.00000001f) {
347 | return 0;
348 | }
349 | float targetOffset = mOffset + realDx;
350 |
351 | //handle the boundary
352 | if (!mInfinite && targetOffset < getMinOffset()) {
353 | willScroll -= (targetOffset - getMinOffset()) * getDistanceRatio();
354 | } else if (!mInfinite && targetOffset > getMaxOffset()) {
355 | willScroll = (int) ((getMaxOffset() - mOffset) * getDistanceRatio());
356 | }
357 |
358 |
359 | realDx = willScroll / getDistanceRatio();
360 |
361 | mOffset += realDx;
362 |
363 | // we re-layout all current views in the right place
364 | for (int i = 0; i < getChildCount(); i++) {
365 | final View scrap = getChildAt(i);
366 | final float delta = propertyChangeWhenScroll(scrap) - realDx;
367 | layoutScrap(scrap, delta);
368 | }
369 |
370 | //handle recycle
371 | layoutItems(recycler);
372 |
373 | return willScroll;
374 | }
375 |
376 | private void layoutItems(RecyclerView.Recycler recycler) {
377 | final float rightOffset = getOffsetOfRightAdapterPosition();
378 | for (int i = 0; i < getChildCount(); i++) {
379 | final View view = getChildAt(i);
380 | final int position = getPosition(view);
381 | if (removeCondition(getProperty(position) - rightOffset)) {
382 | removeAndRecycleView(view, recycler);
383 | }
384 | }
385 |
386 | //make sure that current position start from 0 to 1
387 | final int currentPos = getCurrentPositionOffset();
388 | int start = currentPos - mLeftItems;
389 | int end = currentPos + mRightItems;
390 |
391 | final int itemCount = getItemCount();
392 | if (!mInfinite) {
393 | if (start < 0) start = 0;
394 | if (end > itemCount) end = itemCount;
395 | }
396 |
397 | float lastOrderWeight = Float.MIN_VALUE;
398 | for (int i = start; i < end; i++) {
399 | if (!removeCondition(getProperty(i) - mOffset)) {
400 | // start and end zero base on current position,
401 | // so we need to calculate the adapter position
402 | int adapterPosition = i;
403 | if (i >= itemCount) {
404 | adapterPosition %= itemCount;
405 | } else if (i < 0) {
406 | int delta = (-adapterPosition) % itemCount;
407 | if (delta == 0) delta = itemCount;
408 | adapterPosition = itemCount - delta;
409 | }
410 | if (findViewByPosition(adapterPosition) == null) {
411 | final View scrap = recycler.getViewForPosition(adapterPosition);
412 | measureChildWithMargins(scrap, 0, 0);
413 | resetViewProperty(scrap);
414 | // we need i to calculate the real offset of current view
415 | final float targetOffset = getProperty(i) - mOffset;
416 | layoutScrap(scrap, targetOffset);
417 | if ((float) adapterPosition > lastOrderWeight) {
418 | addView(scrap);
419 | } else {
420 | addView(scrap, 0);
421 | }
422 | lastOrderWeight = (float) adapterPosition;
423 | }
424 | }
425 | }
426 | }
427 |
428 | private boolean removeCondition(float targetOffset) {
429 | return targetOffset > maxRemoveOffset() || targetOffset < minRemoveOffset();
430 | }
431 |
432 | private void resetViewProperty(View v) {
433 | v.setRotation(0);
434 | v.setRotationY(0);
435 | v.setRotationX(0);
436 | v.setScaleX(1f);
437 | v.setScaleY(1f);
438 | v.setAlpha(1f);
439 | }
440 |
441 | private float getMaxOffset() {
442 | return (getItemCount() - 1) * mInterval;
443 | }
444 |
445 | private float getMinOffset() {
446 | return 0;
447 | }
448 |
449 | private void layoutScrap(View scrap, float targetOffset) {
450 | final int left = calItemLeft(scrap, targetOffset);
451 | final int top = calItemTop(scrap, targetOffset);
452 | if (mOrientation == VERTICAL) {
453 | layoutDecorated(scrap, mSpaceInOther + left, mSpaceMain + top,
454 | mSpaceInOther + left + mDecoratedMeasurementInOther, mSpaceMain + top + mDecoratedMeasurement);
455 | } else {
456 | layoutDecorated(scrap, mSpaceMain + left, mSpaceInOther + top,
457 | mSpaceMain + left + mDecoratedMeasurement, mSpaceInOther + top + mDecoratedMeasurementInOther);
458 | }
459 | setItemViewProperty(scrap, targetOffset);
460 | }
461 |
462 | private void setItemViewProperty(View itemView, float targetOffset) {
463 | float scale = calculateScale(targetOffset + mSpaceMain);
464 | itemView.setScaleX(scale);
465 | itemView.setScaleY(scale);
466 | }
467 |
468 | private int calItemLeft(View itemView, float targetOffset) {
469 | return mOrientation == VERTICAL ? 0 : (int) targetOffset;
470 | }
471 |
472 | private int calItemTop(View itemView, float targetOffset) {
473 | return mOrientation == VERTICAL ? (int) targetOffset : 0;
474 | }
475 |
476 | /**
477 | * author : Iwdael
478 | * e-mail : iwdael@outlook.com
479 | * github : http://github.com/iwdael
480 | * project : CarouselBanner
481 | */
482 | private float maxRemoveOffset() {
483 | return mOrientationHelper.getTotalSpace() - mSpaceMain;
484 | }
485 |
486 | /**
487 | * author : Iwdael
488 | * e-mail : iwdael@outlook.com
489 | * github : http://github.com/iwdael
490 | * project : CarouselBanner
491 | */
492 | private float minRemoveOffset() {
493 | return -mDecoratedMeasurement - mOrientationHelper.getStartAfterPadding() - mSpaceMain;
494 | }
495 |
496 | private float propertyChangeWhenScroll(View itemView) {
497 | if (mOrientation == VERTICAL)
498 | return itemView.getTop() - mSpaceMain;
499 | return itemView.getLeft() - mSpaceMain;
500 | }
501 |
502 | private float getDistanceRatio() {
503 | return 1f;
504 | }
505 |
506 | public int getCurrentPosition() {
507 | int position = getCurrentPositionOffset();
508 | if (!mInfinite) return Math.abs(position);
509 | position = (position >= 0 ? position % getItemCount() : getItemCount() + position % getItemCount());
510 | return position;
511 | }
512 |
513 | private int getCurrentPositionOffset() {
514 | return Math.round(mOffset / mInterval);
515 | }
516 |
517 | /**
518 | * author : Iwdael
519 | * e-mail : iwdael@outlook.com
520 | * github : http://github.com/iwdael
521 | * project : CarouselBanner
522 | */
523 | private float getOffsetOfRightAdapterPosition() {
524 | return mInfinite ?
525 | (mOffset >= 0 ?
526 | (mOffset % (mInterval * getItemCount())) :
527 | (getItemCount() * mInterval + mOffset % (mInterval * getItemCount()))) :
528 | mOffset;
529 | }
530 |
531 | /**
532 | * author : Iwdael
533 | * e-mail : iwdael@outlook.com
534 | * github : http://github.com/iwdael
535 | * project : CarouselBanner
536 | */
537 | public int getOffsetToCenter() {
538 | if (mInfinite)
539 | return (int) ((getCurrentPositionOffset() * mInterval - mOffset) * getDistanceRatio());
540 | return (int) ((getCurrentPosition() *
541 | (mInterval) - mOffset) * getDistanceRatio());
542 | }
543 |
544 | public void setOnPageChangeListener(OnPageChangeListener onPageChangeListener) {
545 | this.onPageChangeListener = onPageChangeListener;
546 | }
547 |
548 | public interface OnPageChangeListener {
549 | void onPageSelected(int position);
550 |
551 | void onPageScrollStateChanged(int state);
552 | }
553 | }
554 |
--------------------------------------------------------------------------------
/carouselbanner/src/main/java/com/iwdael/carouselbanner/layoutmanager/OrientationHelper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.iwdael.carouselbanner.layoutmanager;
18 |
19 | import android.graphics.Rect;
20 | import android.view.View;
21 | import android.widget.LinearLayout;
22 |
23 | import androidx.recyclerview.widget.RecyclerView;
24 |
25 | /**
26 | * author : Iwdael
27 | * e-mail : iwdael@outlook.com
28 | * github : http://github.com/iwdael
29 | * project : CarouselBanner
30 | */
31 | @SuppressWarnings({"WeakerAccess","unused"})
32 | public abstract class OrientationHelper {
33 |
34 | private static final int INVALID_SIZE = Integer.MIN_VALUE;
35 |
36 | protected final RecyclerView.LayoutManager mLayoutManager;
37 |
38 | public static final int HORIZONTAL = LinearLayout.HORIZONTAL;
39 |
40 | public static final int VERTICAL = LinearLayout.VERTICAL;
41 |
42 | private int mLastTotalSpace = INVALID_SIZE;
43 |
44 | final Rect mTmpRect = new Rect();
45 |
46 | private OrientationHelper(RecyclerView.LayoutManager layoutManager) {
47 | mLayoutManager = layoutManager;
48 | }
49 |
50 |
51 | public void onLayoutComplete() {
52 | mLastTotalSpace = getTotalSpace();
53 | }
54 |
55 |
56 | public int getTotalSpaceChange() {
57 | return INVALID_SIZE == mLastTotalSpace ? 0 : getTotalSpace() - mLastTotalSpace;
58 | }
59 |
60 |
61 | public abstract int getDecoratedStart(View view);
62 |
63 |
64 |
65 | public abstract int getDecoratedEnd(View view);
66 |
67 |
68 | public abstract int getTransformedEndWithDecoration(View view);
69 |
70 |
71 | public abstract int getTransformedStartWithDecoration(View view);
72 |
73 |
74 | public abstract int getDecoratedMeasurement(View view);
75 |
76 |
77 | public abstract int getDecoratedMeasurementInOther(View view);
78 |
79 |
80 | public abstract int getStartAfterPadding();
81 |
82 |
83 | public abstract int getEndAfterPadding();
84 |
85 |
86 | public abstract int getEnd();
87 |
88 |
89 | public abstract int getTotalSpace();
90 |
91 |
92 | public abstract int getTotalSpaceInOther();
93 |
94 |
95 | public abstract int getEndPadding();
96 |
97 |
98 | public abstract int getMode();
99 |
100 |
101 | public abstract int getModeInOther();
102 |
103 |
104 | public static OrientationHelper createOrientationHelper(
105 | RecyclerView.LayoutManager layoutManager, int orientation) {
106 | switch (orientation) {
107 | case HORIZONTAL:
108 | return createHorizontalHelper(layoutManager);
109 | case VERTICAL:
110 | return createVerticalHelper(layoutManager);
111 | }
112 | throw new IllegalArgumentException("invalid orientation");
113 | }
114 |
115 |
116 | public static OrientationHelper createHorizontalHelper(
117 | RecyclerView.LayoutManager layoutManager) {
118 | return new OrientationHelper(layoutManager) {
119 | @Override
120 | public int getEndAfterPadding() {
121 | return mLayoutManager.getWidth() - mLayoutManager.getPaddingRight();
122 | }
123 |
124 | @Override
125 | public int getEnd() {
126 | return mLayoutManager.getWidth();
127 | }
128 |
129 | @Override
130 | public int getStartAfterPadding() {
131 | return mLayoutManager.getPaddingLeft();
132 | }
133 |
134 | @Override
135 | public int getDecoratedMeasurement(View view) {
136 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
137 | view.getLayoutParams();
138 | return mLayoutManager.getDecoratedMeasuredWidth(view) + params.leftMargin + params.rightMargin;
139 | }
140 |
141 | @Override
142 | public int getDecoratedMeasurementInOther(View view) {
143 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
144 | view.getLayoutParams();
145 | return mLayoutManager.getDecoratedMeasuredHeight(view) + params.topMargin
146 | + params.bottomMargin;
147 | }
148 |
149 | @Override
150 | public int getDecoratedEnd(View view) {
151 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
152 | view.getLayoutParams();
153 | return mLayoutManager.getDecoratedRight(view) + params.rightMargin;
154 | }
155 |
156 | @Override
157 | public int getDecoratedStart(View view) {
158 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
159 | view.getLayoutParams();
160 | return mLayoutManager.getDecoratedLeft(view) - params.leftMargin;
161 | }
162 |
163 | @Override
164 | public int getTransformedEndWithDecoration(View view) {
165 | mLayoutManager.getTransformedBoundingBox(view, true, mTmpRect);
166 | return mTmpRect.right;
167 | }
168 |
169 | @Override
170 | public int getTransformedStartWithDecoration(View view) {
171 | mLayoutManager.getTransformedBoundingBox(view, true, mTmpRect);
172 | return mTmpRect.left;
173 | }
174 |
175 | @Override
176 | public int getTotalSpace() {
177 | return mLayoutManager.getWidth() - mLayoutManager.getPaddingLeft()
178 | - mLayoutManager.getPaddingRight();
179 | }
180 |
181 | @Override
182 | public int getTotalSpaceInOther() {
183 | return mLayoutManager.getHeight() - mLayoutManager.getPaddingTop()
184 | - mLayoutManager.getPaddingBottom();
185 | }
186 |
187 | @Override
188 | public int getEndPadding() {
189 | return mLayoutManager.getPaddingRight();
190 | }
191 |
192 | @Override
193 | public int getMode() {
194 | return mLayoutManager.getWidthMode();
195 | }
196 |
197 | @Override
198 | public int getModeInOther() {
199 | return mLayoutManager.getHeightMode();
200 | }
201 | };
202 | }
203 |
204 |
205 | public static OrientationHelper createVerticalHelper(RecyclerView.LayoutManager layoutManager) {
206 | return new OrientationHelper(layoutManager) {
207 | @Override
208 | public int getEndAfterPadding() {
209 | return mLayoutManager.getHeight() - mLayoutManager.getPaddingBottom();
210 | }
211 |
212 | @Override
213 | public int getEnd() {
214 | return mLayoutManager.getHeight();
215 | }
216 |
217 | @Override
218 | public int getStartAfterPadding() {
219 | return mLayoutManager.getPaddingTop();
220 | }
221 |
222 | @Override
223 | public int getDecoratedMeasurement(View view) {
224 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
225 | view.getLayoutParams();
226 | return mLayoutManager.getDecoratedMeasuredHeight(view) + params.topMargin
227 | + params.bottomMargin;
228 | }
229 |
230 | @Override
231 | public int getDecoratedMeasurementInOther(View view) {
232 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
233 | view.getLayoutParams();
234 | return mLayoutManager.getDecoratedMeasuredWidth(view) + params.leftMargin
235 | + params.rightMargin;
236 | }
237 |
238 | @Override
239 | public int getDecoratedEnd(View view) {
240 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
241 | view.getLayoutParams();
242 | return mLayoutManager.getDecoratedBottom(view) + params.bottomMargin;
243 | }
244 |
245 | @Override
246 | public int getDecoratedStart(View view) {
247 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
248 | view.getLayoutParams();
249 | return mLayoutManager.getDecoratedTop(view) - params.topMargin;
250 | }
251 |
252 | @Override
253 | public int getTransformedEndWithDecoration(View view) {
254 | mLayoutManager.getTransformedBoundingBox(view, true, mTmpRect);
255 | return mTmpRect.bottom;
256 | }
257 |
258 | @Override
259 | public int getTransformedStartWithDecoration(View view) {
260 | mLayoutManager.getTransformedBoundingBox(view, true, mTmpRect);
261 | return mTmpRect.top;
262 | }
263 |
264 | @Override
265 | public int getTotalSpace() {
266 | return mLayoutManager.getHeight() - mLayoutManager.getPaddingTop()
267 | - mLayoutManager.getPaddingBottom();
268 | }
269 |
270 | @Override
271 | public int getTotalSpaceInOther() {
272 | return mLayoutManager.getWidth() - mLayoutManager.getPaddingLeft()
273 | - mLayoutManager.getPaddingRight();
274 | }
275 |
276 | @Override
277 | public int getEndPadding() {
278 | return mLayoutManager.getPaddingBottom();
279 | }
280 |
281 | @Override
282 | public int getMode() {
283 | return mLayoutManager.getHeightMode();
284 | }
285 |
286 | @Override
287 | public int getModeInOther() {
288 | return mLayoutManager.getWidthMode();
289 | }
290 | };
291 | }
292 | }
--------------------------------------------------------------------------------
/carouselbanner/src/main/java/com/iwdael/carouselbanner/viewholder/CarouselViewHolder.java:
--------------------------------------------------------------------------------
1 | package com.iwdael.carouselbanner.viewholder;
2 |
3 | import android.view.View;
4 | import android.view.ViewGroup;
5 | import android.widget.ImageView;
6 |
7 | import androidx.recyclerview.widget.RecyclerView;
8 |
9 | import com.iwdael.carouselbanner.base.BaseViewHolder;
10 |
11 | /**
12 | * author : Iwdael
13 | * e-mail : iwdael@outlook.com
14 | * github : http://github.com/iwdael
15 | * project : CarouselBanner
16 | */
17 |
18 | public class CarouselViewHolder extends BaseViewHolder {
19 |
20 | public CarouselViewHolder(View itemView) {
21 | super(itemView);
22 | imageView = (ImageView) itemView;
23 | RecyclerView.LayoutParams params = new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
24 | imageView.setLayoutParams(params);
25 | imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/carouselbanner/src/main/java/com/iwdael/carouselbanner/viewholder/CoolCarouselViewHolder.java:
--------------------------------------------------------------------------------
1 | package com.iwdael.carouselbanner.viewholder;
2 |
3 | import android.view.View;
4 |
5 | import com.iwdael.carouselbanner.R;
6 | import com.iwdael.carouselbanner.base.BaseViewHolder;
7 |
8 | /**
9 | * author : Iwdael
10 | * e-mail : iwdael@outlook.com
11 | * github : http://github.com/iwdael
12 | * project : CarouselBanner
13 | */
14 |
15 | public class CoolCarouselViewHolder extends BaseViewHolder {
16 |
17 | public CoolCarouselViewHolder(View itemView) {
18 | super(itemView);
19 | imageView = itemView.findViewById(R.id.image);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/carouselbanner/src/main/res/layout/item_image.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
--------------------------------------------------------------------------------
/carouselbanner/src/main/res/values/attr.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 |
--------------------------------------------------------------------------------
/carouselbanner/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FF4081
4 | #303F9F
5 |
--------------------------------------------------------------------------------
/config.gradle:
--------------------------------------------------------------------------------
1 | ext {
2 | buidConfig = [
3 | 'compileSdkVersion': 30,
4 | 'targetSdkVersion' : 30,
5 | 'minSdkVersion' : 19,
6 | 'versionCode' : 1,
7 | 'versionName' : '1.0.0',
8 | 'buildToolsVersion': '30.0.3'
9 | ]
10 | dependent = [
11 | 'appcompat' : 'androidx.appcompat:appcompat:1.3.1',
12 | 'constraintlayout': 'androidx.constraintlayout:constraintlayout:2.1.1',
13 | 'androidxCore' : 'androidx.core:core-ktx:1.7.0',
14 | 'kotlinJdk7' : 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.4.21',
15 | 'glide' : 'com.github.bumptech.glide:glide:4.12.0',
16 | 'recyclerview' : 'androidx.recyclerview:recyclerview:1.1.0',
17 | 'cardview' : 'androidx.cardview:cardview:1.0.0',
18 | ]
19 | }
--------------------------------------------------------------------------------
/example/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/example/build.gradle:
--------------------------------------------------------------------------------
1 | apply from: './../config.gradle'
2 | apply plugin: 'com.android.application'
3 | apply plugin: 'kotlin-android'
4 | apply plugin: 'kotlin-android-extensions'
5 |
6 | android {
7 | buildToolsVersion buidConfig.buildToolsVersion
8 | compileSdkVersion buidConfig.compileSdkVersion
9 |
10 | defaultConfig {
11 | applicationId "com.iwdael.carouselbanner.example"
12 | minSdkVersion buidConfig.minSdkVersion
13 | targetSdkVersion buidConfig.targetSdkVersion
14 | versionCode buidConfig.versionCode
15 | versionName buidConfig.versionName
16 | }
17 | compileOptions {
18 | sourceCompatibility 1.8
19 | targetCompatibility 1.8
20 | }
21 |
22 | }
23 |
24 | dependencies {
25 | implementation dependent.kotlinJdk7
26 | implementation dependent.appcompat
27 | implementation dependent.constraintlayout
28 | implementation dependent.glide
29 | implementation project(":carouselbanner")
30 | implementation dependent.recyclerview
31 | implementation dependent.cardview
32 | }
--------------------------------------------------------------------------------
/example/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/example/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/example/src/main/java/com/iwdael/carouselbanner/example/ImageFactory.java:
--------------------------------------------------------------------------------
1 | package com.iwdael.carouselbanner.example;
2 |
3 | import android.widget.ImageView;
4 |
5 | import com.bumptech.glide.Glide;
6 | import com.iwdael.carouselbanner.interfaces.CarouselImageFactory;
7 |
8 | public class ImageFactory implements CarouselImageFactory {
9 | @Override
10 | public void onLoadFactory(String url, ImageView view) {
11 | Glide.with(view).load(url).into(view);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/example/src/main/java/com/iwdael/carouselbanner/example/Main2Activity.java:
--------------------------------------------------------------------------------
1 | package com.iwdael.carouselbanner.example;
2 |
3 | import android.os.Bundle;
4 | import android.widget.Toast;
5 |
6 | import androidx.appcompat.app.AppCompatActivity;
7 |
8 | import com.iwdael.carouselbanner.CarouselBanner;
9 | import com.iwdael.carouselbanner.interfaces.OnCarouselItemChangeListener;
10 | import com.iwdael.carouselbanner.interfaces.OnCarouselItemClickListener;
11 |
12 | import java.util.ArrayList;
13 | import java.util.List;
14 |
15 | public class Main2Activity extends AppCompatActivity {
16 | CarouselBanner banner, banner2;
17 |
18 |
19 | @Override
20 | protected void onCreate(Bundle savedInstanceState) {
21 | super.onCreate(savedInstanceState);
22 | setContentView(R.layout.activity_main2);
23 | banner = findViewById(R.id.banner);
24 | banner2 = findViewById(R.id.banner2);
25 | List list = new ArrayList<>();
26 | list.add("http://g.hiphotos.baidu.com/image/pic/item/b17eca8065380cd78775def0ab44ad3459828147.jpg");
27 | list.add("http://f.hiphotos.baidu.com/image/pic/item/a08b87d6277f9e2faa2048151530e924b899f392.jpg");
28 | list.add("http://b.hiphotos.baidu.com/image/pic/item/03087bf40ad162d923621d011bdfa9ec8a13cd1b.jpg");
29 | list.add("http://e.hiphotos.baidu.com/image/pic/item/b7fd5266d0160924d76acf06de0735fae6cd345b.jpg");
30 | list.add("http://a.hiphotos.baidu.com/image/pic/item/c83d70cf3bc79f3d785ce62db0a1cd11728b2969.jpg");
31 | list.add("http://f.hiphotos.baidu.com/image/pic/item/fcfaaf51f3deb48fd146bfc3fa1f3a292df578fb.jpg");
32 |
33 | banner.setOnCarouselItemClickListener(new OnCarouselItemClickListener() {
34 | @Override
35 | public void onItemClick(int position, String url) {
36 | Toast.makeText(Main2Activity.this, url, Toast.LENGTH_LONG).show();
37 | }
38 | });
39 | banner.setOnCarouselItemChangeListener(new OnCarouselItemChangeListener() {
40 | @Override
41 | public void onItemChange(int position) {
42 | // Toast.makeText(Main2Activity.this, String.valueOf(position), Toast.LENGTH_LONG).show();
43 | }
44 | });
45 | banner.initBanner(list);
46 | banner2.initBanner(list);
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/example/src/main/java/com/iwdael/carouselbanner/example/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.iwdael.carouselbanner.example;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.view.View;
6 | import android.widget.Toast;
7 |
8 | import androidx.appcompat.app.AppCompatActivity;
9 |
10 | import com.iwdael.carouselbanner.Banner;
11 | import com.iwdael.carouselbanner.CoolCarouselBanner;
12 | import com.iwdael.carouselbanner.interfaces.OnCarouselItemChangeListener;
13 | import com.iwdael.carouselbanner.interfaces.OnCarouselItemClickListener;
14 |
15 | import java.util.ArrayList;
16 | import java.util.List;
17 |
18 | public class MainActivity extends AppCompatActivity {
19 |
20 | CoolCarouselBanner banner, banner2;
21 |
22 |
23 | @Override
24 | protected void onCreate(Bundle savedInstanceState) {
25 | super.onCreate(savedInstanceState);
26 | setContentView(R.layout.activity_main);
27 | banner = findViewById(R.id.banner);
28 | banner2 = findViewById(R.id.banner2);
29 | List list = new ArrayList<>();
30 | Banner.init(new ImageFactory());
31 | list.add("http://g.hiphotos.baidu.com/image/pic/item/b17eca8065380cd78775def0ab44ad3459828147.jpg");
32 | list.add("http://f.hiphotos.baidu.com/image/pic/item/a08b87d6277f9e2faa2048151530e924b899f392.jpg");
33 | list.add("http://b.hiphotos.baidu.com/image/pic/item/03087bf40ad162d923621d011bdfa9ec8a13cd1b.jpg");
34 | list.add("http://e.hiphotos.baidu.com/image/pic/item/b7fd5266d0160924d76acf06de0735fae6cd345b.jpg");
35 | list.add("http://a.hiphotos.baidu.com/image/pic/item/c83d70cf3bc79f3d785ce62db0a1cd11728b2969.jpg");
36 | list.add("http://f.hiphotos.baidu.com/image/pic/item/fcfaaf51f3deb48fd146bfc3fa1f3a292df578fb.jpg");
37 |
38 | banner.setOnCarouselItemChangeListener(new OnCarouselItemChangeListener() {
39 | @Override
40 | public void onItemChange(int position) {
41 | // Toast.makeText(MainActivity.this, String.valueOf(position), Toast.LENGTH_LONG).show();
42 | }
43 | });
44 | banner.setOnCarouselItemClickListener(new OnCarouselItemClickListener() {
45 | @Override
46 | public void onItemClick(int position, String url) {
47 | Toast.makeText(MainActivity.this, url, Toast.LENGTH_LONG).show();
48 | }
49 | });
50 | banner.initBanner(list);
51 | banner2.initBanner(list);
52 |
53 | }
54 |
55 |
56 | public void jump(View view) {
57 | view.setVisibility(View.GONE);
58 | startActivity(new Intent(MainActivity.this, Main2Activity.class));
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/example/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
19 |
20 |
21 |
27 |
28 |
35 |
36 |
--------------------------------------------------------------------------------
/example/src/main/res/layout/activity_main2.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
16 |
17 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/example/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #6200EE
4 | #3700B3
5 | #03DAC5
6 |
--------------------------------------------------------------------------------
/example/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | CarouselBanner
3 |
--------------------------------------------------------------------------------
/example/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app"s APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Automatically convert third-party libraries to use AndroidX
19 | android.enableJetifier=true
20 | # Kotlin code style for this project: "official" or "obsolete":
21 | kotlin.code.style=official
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iwdael/CarouselBanner/475edbffb9329f6efb7b3a082dae1151646cdefb/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Tue Dec 28 14:05:36 CST 2021
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-6.1.1-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
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 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/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 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
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 Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/screenshot/CarouselBanner.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iwdael/CarouselBanner/475edbffb9329f6efb7b3a082dae1151646cdefb/screenshot/CarouselBanner.gif
--------------------------------------------------------------------------------
/screenshot/CoolCarouselBanner.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iwdael/CarouselBanner/475edbffb9329f6efb7b3a082dae1151646cdefb/screenshot/CoolCarouselBanner.gif
--------------------------------------------------------------------------------
/screenshot/qq_group.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iwdael/CarouselBanner/475edbffb9329f6efb7b3a082dae1151646cdefb/screenshot/qq_group.png
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':carouselbanner'
2 | include ':example'
3 | rootProject.name = "CarouselBanner"
--------------------------------------------------------------------------------