效果演示
上圖這個(gè)效果你可以于淘寶和媳,愛(ài)奇藝凉蜂,華為應(yīng)用商店等一系列熱門(mén)或者不熱門(mén)的APP中看到,因?yàn)槭褂肂anner可以通過(guò)固定大小的位置動(dòng)態(tài)或者靜態(tài)的向用戶(hù)展示多條甚至幾十條(雖然沒(méi)人這樣子做)圖文數(shù)據(jù),對(duì)于我自己來(lái)說(shuō)也經(jīng)常會(huì)使用到Banner來(lái)展示廣告數(shù)據(jù)或者手機(jī)啟動(dòng)引導(dǎo)界面蚁阳,所以就有了現(xiàn)在這個(gè)SimpleBanner庫(kù)稠茂,它肯定不是最完美的,但是我希望它是有用的次哈。
使用
- 在你project的
build.gradle
的repositories
里面添加:
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}```
2. 在你所需的module的```build.gradle```里面添加依賴(lài):
dependencies {
compile 'com.github.AmatorLee:SimpleBanner:1.0.0'
}```
- 在你需要展示Banner數(shù)據(jù)的xml文件中引入:
<com.amator.simplebanner.widget.SimpleBanner
android:id="@+id/banner_simple"
android:layout_width="match_parent"
android:layout_height="200dp">
</com.amator.simplebanner.widget.SimpleBanner>```
4. 在Activity或者Fragment中配置SimpleBanner:
/**
* 測(cè)試本地圖片資源胎署,圖片較大,造成開(kāi)銷(xiāo)大
/
private int[] imaRes = {R.drawable.a123, R.drawable.color, R.drawable.flash, R.drawable.zhixiao, R.drawable.xiaozhi};
private SimpleBanner mBanner;
/*
* 默認(rèn)圖片資源(圖片URL地址)
/
private String[] defaultUrl = new String[]{
"http://g.hiphotos.baidu.com/imgad/pic/item/a8773912b31bb051be533b24317adab44aede043.jpg",
"http://g.hiphotos.baidu.com/imgad/pic/item/c75c10385343fbf22c362d2fb77eca8065388fa0.jpg",
"http://liaoning.sinaimg.cn/2014/1111/U10435P1195DT20141111220802.jpg",
"http://photocdn.sohu.com/20151124/mp43786429_1448294862260_4.jpeg",
"http://h.hiphotos.baidu.com/image/pic/item/faedab64034f78f0b00507c97e310a55b3191cf9.jpg"};
/*
* 測(cè)試文字提示
*/
private String[] titleRes = {"深色", "淺色", "動(dòng)物", "宋智孝", "宋智孝"};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//加載本地圖片
List<Integer> mDatas = new ArrayList<>();
for (int i = 0; i < imaRes.length; i++) {
mDatas.add(imaRes[i]);
}
//加載網(wǎng)絡(luò)圖片
List<String> mImageRes = new ArrayList<>();
for (int i = 0; i < defaultUrl.length; i++) {
mImageRes.add(defaultUrl[i]);
}
List<String> tips = new ArrayList<>();
for (int i = 0; i < titleRes.length; i++) {
tips.add(titleRes[i]);
}
//1.寫(xiě)在布局文件中
mBanner = (SimpleBanner) findViewById(R.id.banner_simple);
mBanner.setImageRes(mImageRes)
.start();//調(diào)用則表示允許自動(dòng)循環(huán)播放
//2.代碼中直接使用
LinearLayout linearLayout = (LinearLayout) findViewById(R.id.ll_banner_container);
mBanner = SimpleBanner.createBanner(this)
.setImageRes(mImageRes);
mBanner.start();
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, DisplayUtil.dp2px(this, 200));
linearLayout.addView(mBanner, params);
}
@Override
protected void onPause() {
super.onPause();
//釋放資源避免內(nèi)存泄漏
mBanner.stop();
}```
就這樣就可以實(shí)現(xiàn)以下效果
可能有人會(huì)問(wèn)窑滞,那么切換效果呢琼牧?恢筝,其實(shí)切換效果的實(shí)現(xiàn)很簡(jiǎn)單,但是實(shí)現(xiàn)炫酷的切換效果需要大量是時(shí)間進(jìn)行計(jì)算巨坊,同時(shí)對(duì)于部分APP來(lái)說(shuō)是不合適的撬槽,所以我不打算提供多種切換效果,當(dāng)然你可以自己實(shí)現(xiàn)然后調(diào)用
setBannerPageTranFormer(boolean reverseDrawingOrder, ViewPager.PageTransformer transformer)
即可趾撵。同時(shí)我推薦一個(gè)開(kāi)源庫(kù)android-viewpager-transformers恢氯,感謝。
代碼分析
短短的使用步驟絞盡腦汁也寫(xiě)不出來(lái)鼓寺,所以直接show you the fuck codes就好勋拟。
在此之前我先簡(jiǎn)單來(lái)說(shuō)說(shuō)SimpleBanner實(shí)現(xiàn)無(wú)限輪播的實(shí)現(xiàn)方式
現(xiàn)今gayhub上的banner開(kāi)源庫(kù)主要分為兩大類(lèi):
- 使用ViewPager實(shí)現(xiàn)
- 自定義或者使用RecyclerView等實(shí)現(xiàn)
那么Simple是使用第一種方式,所以就結(jié)合代碼分析來(lái)說(shuō)說(shuō)第一種的套路吧:
既然知道了精髓是ViewPager妈候,在確定ViewPager之后我們要考慮以下兩個(gè)問(wèn)題
- 實(shí)現(xiàn)循環(huán)播放
- 如何進(jìn)行自動(dòng)循環(huán)
回答一
其實(shí)實(shí)現(xiàn)循環(huán)很簡(jiǎn)單敢靡,只要在最后一張圖片滑動(dòng)時(shí)把它下一張重新設(shè)置為第一張就可以實(shí)現(xiàn)“偽循環(huán)”,但是這樣重新滑進(jìn)去會(huì)造成很不好的用戶(hù)體驗(yàn)苦银,所以我們給ViewPager的adapter設(shè)置一個(gè)很大的數(shù)啸胧,返回一個(gè)巨大的數(shù)值,通過(guò)與實(shí)際數(shù)量的求余就可以實(shí)現(xiàn)“無(wú)限循環(huán)”幔虏。
回答二
很多時(shí)候我們都會(huì)新建一個(gè)Handler
纺念,然后再其實(shí)現(xiàn)方法里面對(duì)viewPager進(jìn)行setCurrentItem,然后再界面跳轉(zhuǎn)完成后掩飾某個(gè)delayTime
不斷發(fā)送自身空消息就可以實(shí)現(xiàn)自動(dòng)播放了,bug,還有更好的辦法嗎想括?知道我看到了達(dá)哥的《手把手教你用ViewPager自定義實(shí)現(xiàn)Banner輪播 》陷谱,找到了更好的寫(xiě)法,當(dāng)然思想是一樣的瑟蜈。
BannerViewPager
/**
* Created by AmatorLee on 2017/7/21.
*/
public class BannerViewPager extends ViewPager {
private int delayTime = 3000;//設(shè)置展示時(shí)間
private BannerDirection mBannerDirection = LEFT;//試著輪播方向
private boolean isAuto = true;//是否為自動(dòng)輪播
public void setAuto(boolean auto) {
isAuto = auto;
}
public void setDelayTime(int delayTime) {
this.delayTime = delayTime;
}
public void setBannerDirection(BannerDirection bannerDirection) {
mBannerDirection = bannerDirection;
}
public BannerViewPager(Context context) {
super(context);
}
public BannerViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void start() {
if (isAuto) {
//每次開(kāi)始前先remove掉避免重復(fù)調(diào)用
removeCallbacks(mBannerTask);
postDelayed(mBannerTask, delayTime);
}
}
public void stop() {
removeCallbacks(mBannerTask);
}
private Runnable mBannerTask = new Runnable() {
@Override
public void run() {
bannerPlay();
}
};
private void bannerPlay() {
PagerAdapter adapter = getAdapter();
if (adapter != null) {
int count = adapter.getCount();
int currentItem = getCurrentItem();
switch (mBannerDirection) {
case LEFT:
currentItem++;
if (currentItem >= count) {
currentItem = 0;
}
break;
case RIGHT:
currentItem--;
if (currentItem < 0) {
currentItem = count - 1;
}
break;
}
setCurrentItem(currentItem);
}
start();
}
@Override
protected void onDetachedFromWindow() {
removeCallbacks(mBannerTask);
super.onDetachedFromWindow();
}
}```
如上所說(shuō)烟逊,需要給Adapter設(shè)置一個(gè)很大的數(shù)```Integer.MAX_VALUE```
**BannerViewPager**
/**
- Created by AmatorLee on 2017/7/20.
*/
public class BannerAdapter extends PagerAdapter {
private List<View> mViews;
public static final String TAG = "BannerPagerAdapter";
private OnBannerClickListener mBannerClickListener;
private int pos;
public void setBannerClickListener(OnBannerClickListener bannerClickListener) {
mBannerClickListener = bannerClickListener;
}
public BannerAdapter(List<View> mViews) {
this.mViews = mViews;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
if (mViews == null || mViews.size() == 0) {
Log.d(TAG, "instantiateItem return");
return null;
}
final int pos = position % mViews.size();
View view = mViews.get(pos);
ViewGroup parent = (ViewGroup) view.getParent();
if (parent != null) {
parent.removeView(view);
}
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d(TAG, "instantiateItem pos is :" + pos);
if (mBannerClickListener != null) {
mBannerClickListener.onBannerClick(pos);
}
}
});
container.addView(view);
return view;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
if (mViews == null || mViews.size() == 0) {
return;
}
int pos = position % mViews.size();
Log.d(TAG, "destroyItempos: " + pos);
container.removeView(mViews.get(pos));
}
@Override
public int getCount() {
return mViews == null ? 0 : Integer.MAX_VALUE;
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
}其實(shí)看到上面的演示圖還有最后一個(gè)注意點(diǎn)就是指示器Indicator,我嘗試過(guò)自己自定義幾種類(lèi)型的
BannerIndicator```铺根,但是這樣做的話實(shí)現(xiàn)太多的子類(lèi)宪躯,所以我采取代碼家AndroidImageSlider的寫(xiě)法使用圖層Drawable動(dòng)態(tài)實(shí)現(xiàn)。
總結(jié)
Banner幾乎是最常見(jiàn)的一種效果同時(shí)對(duì)于我們Coder來(lái)說(shuō)也應(yīng)該是最容易實(shí)現(xiàn)的位迂,所以自己抽空寫(xiě)一下访雪。如果發(fā)現(xiàn)有什么錯(cuò)漏的地方,麻煩指出掂林,同時(shí)我也會(huì)不斷自我完善臣缀。
gayhub地址:SimpleBanner