Android封裝Banner控件方法介紹

如上圖所示效果我們應(yīng)該都不陌生,這是一個(gè)簡(jiǎn)單的banner輪播效果,網(wǎng)上也有很多的開源項(xiàng)目,但有時(shí)候可能我們僅僅只需要一些簡(jiǎn)單的效果,并不需要其他過多的東西。這里簡(jiǎn)單的對(duì)banner進(jìn)行一下封裝,隨時(shí)調(diào)用和添加一些新的功能。
代碼展示
/**
* Created by xiaolong on 2018/1/23.
*/
public class BannerView extends FrameLayout implements ViewPager.OnPageChangeListener{
private ViewPager viewPager;
//網(wǎng)絡(luò)圖片地址
private List<String> imageUrls;
//指示點(diǎn)的容器
private LinearLayout pointLayout;
//當(dāng)前頁(yè)面位置
private int currentItem;
//自動(dòng)播放時(shí)間
private int autoPlayTime = 2000;
//是否自動(dòng)播放
private boolean isAutoPlay;
//是否是一張圖片
private boolean isOneImage;
//監(jiān)聽事件
private OnBannerItemClick onBannerItemClick;
//這里利用handler實(shí)現(xiàn)循環(huán)播放
private Handler handler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
currentItem++;
currentItem = currentItem % (imageUrls.size() + 2);
viewPager.setCurrentItem(currentItem);
handler.sendEmptyMessageDelayed(0,autoPlayTime);
return false;
}
});
public BannerView(@NonNull Context context) {
this(context,null);
}
public BannerView(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}
public BannerView(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs,R.styleable.BannerView,0,0);
//默認(rèn)自動(dòng)播放
isAutoPlay = typedArray.getBoolean(R.styleable.BannerView_isAutoPlay,true);
typedArray.recycle();
viewPager = new ViewPager(getContext());
pointLayout = new LinearLayout(getContext());
//添加監(jiān)聽事件
viewPager.addOnPageChangeListener(this);
//利用布局屬性將指示器容器放置底部并居中
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
params.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
params.bottomMargin = 60;
addView(viewPager);
addView(pointLayout,params);
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
currentItem = position;
if (!isOneImage) {
switchToPoint(toRealPosition(position));
}
}
@Override
public void onPageScrollStateChanged(int state) {
//根據(jù)滑動(dòng)松開后的狀態(tài),去判斷當(dāng)前的current 并跳轉(zhuǎn)到指定current
if (state == ViewPager.SCROLL_STATE_IDLE) {
int current = viewPager.getCurrentItem();
int lastReal = viewPager.getAdapter().getCount() - 2;
if (current == 0) {
viewPager.setCurrentItem(lastReal, false);
} else if (current == lastReal + 1) {
viewPager.setCurrentItem(1, false);
}
}
}
//配置viewpager適配器
private class BannerAdapter extends PagerAdapter {
@Override
public int getCount() {
return imageUrls.size() + 2;
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public Object instantiateItem(ViewGroup container, final int position) {
ImageView imageView = new ImageView(getContext());
imageView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (onBannerItemClick != null) {
onBannerItemClick.onItemClick(toRealPosition(position));
}
}
});
imageView.setScaleType(ImageView.ScaleType.FIT_XY);
Glide.with(getContext()).load(imageUrls.get(toRealPosition(position))).into(imageView);
container.addView(imageView);
return imageView;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
}
//添加網(wǎng)絡(luò)圖片
public void setImageUrls(List<String> imageUrls) {
this.imageUrls = imageUrls;
if (imageUrls.size() <= 1) {
isOneImage = true;
}else {
isOneImage = false;
}
initViewPager();
}
//加載viewPager
private void initViewPager() {
if (!isOneImage) {
//添加指示點(diǎn)
addPoints();
}
BannerAdapter adapter = new BannerAdapter();
viewPager.setAdapter(adapter);
//默認(rèn)當(dāng)前圖片
viewPager.setCurrentItem(1);
//判斷是否自動(dòng)播放和是否是一張圖片的情況
if (isAutoPlay && !isOneImage) {
handler.sendEmptyMessageDelayed(0,autoPlayTime);
}
}
//添加指示點(diǎn)
private void addPoints() {
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
lp.setMargins(10, 10, 10, 10);
ImageView imageView;
int length = imageUrls.size();
for (int i = 0; i < length; i++) {
imageView = new ImageView(getContext());
imageView.setLayoutParams(lp);
imageView.setImageResource(R.drawable.select_point_bg);
pointLayout.addView(imageView);
}
switchToPoint(0);
}
//切換指示器
private void switchToPoint(int currentPoint) {
for (int i = 0; i < pointLayout.getChildCount(); i++) {
pointLayout.getChildAt(i).setEnabled(false);
}
pointLayout.getChildAt(currentPoint).setEnabled(true);
}
//返回真實(shí)的位置
private int toRealPosition(int position) {
int realPosition;
if (imageUrls.size() > 0) {
realPosition = (position - 1) % imageUrls.size();
if (realPosition < 0)
realPosition += imageUrls.size();
}else{
realPosition = 0;
}
return realPosition;
}
public void setAutoPlay(boolean autoPlay) {
isAutoPlay = autoPlay;
}
public void setOnBannerItemClick(OnBannerItemClick onBannerItemClick) {
this.onBannerItemClick = onBannerItemClick;
}
//添加監(jiān)聽事件回調(diào)
public interface OnBannerItemClick{
void onItemClick(int position);
}
}調(diào)用方式
//設(shè)置是否自動(dòng)播放
bannerView.setAutoPlay(true);
//添加網(wǎng)絡(luò)圖片
bannerView.setImageUrls(data);
//banner的點(diǎn)擊事件
bannerView.setOnBannerItemClick(new BannerView.OnBannerItemClick() {
@Override
public void onItemClick(int position) {
Toast.makeText(MainActivity.this,"圖片" + position,Toast.LENGTH_LONG).show();
}
});代碼分析
這里我只考慮了使用網(wǎng)絡(luò)圖片進(jìn)行展示,使用本地圖片原理是一樣的,在里面多加個(gè)方法即可。此效果代碼不是很復(fù)雜,通俗易懂。唯一值得一說的是我在實(shí)現(xiàn)viewpager無限滑動(dòng)時(shí)采用的是return imageUrls.size() + 2的方法。這里我們添加兩條數(shù)據(jù)分別為第一條和最后一條。第一條代表著最后一張圖片而最后一條則代表著第一張圖片,這里手動(dòng)畫個(gè)圖:

通過此圖我們應(yīng)該不難發(fā)現(xiàn),當(dāng)我們滑動(dòng)到第二個(gè)0的時(shí)候則跳轉(zhuǎn)到第一個(gè)0,滑動(dòng)到第一個(gè)2的時(shí)候則跳轉(zhuǎn)到第二個(gè)2。這里0代表第一張圖片,2代表第二張圖片。這樣就可以實(shí)現(xiàn)無限滑動(dòng)的效果了,可能有些人會(huì)覺得這樣做有些復(fù)雜還要判斷真實(shí)的位置不如直接將getConut()返回一個(gè)最大值然后取其中間值即可。但這樣做其實(shí)代碼性能并不是很高。
結(jié)束
這樣一個(gè)常用的banner就寫好了,當(dāng)我們需要實(shí)現(xiàn)一些滑動(dòng)動(dòng)畫的時(shí)候,可以在里面實(shí)現(xiàn)viewpager的動(dòng)畫屬性即可。先從簡(jiǎn)單的入手,慢慢的就可以了解更多的原理和知識(shí)點(diǎn),哈哈!這里貼出傳送門以便參考。
到此這篇關(guān)于Android封裝Banner控件方法介紹的文章就介紹到這了,更多相關(guān)Android封裝Banner內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android編程程序?qū)崿F(xiàn)一鍵鎖屏的方法講解
今天小編就為大家分享一篇關(guān)于Android編程程序?qū)崿F(xiàn)一鍵鎖屏的方法講解,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2019-03-03
kotlin協(xié)程之coroutineScope函數(shù)使用詳解
這篇文章主要為大家介紹了kotlin協(xié)程之coroutineScope函數(shù)使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09
詳解Android Activity中的幾種監(jiān)聽器和實(shí)現(xiàn)方式
這篇文章主要介紹了Activity中的幾種監(jiān)聽器和實(shí)現(xiàn)方式的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)使用Android,感興趣的朋友可以了解下2021-04-04
Android中實(shí)現(xiàn)密碼的隱藏和顯示的示例
本篇文章主要介紹了Android中實(shí)現(xiàn)密碼的隱藏和顯示的示例,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2017-09-09
Android游戲開發(fā)實(shí)踐之人物移動(dòng)地圖的平滑滾動(dòng)處理
玩過rpg游戲的朋友應(yīng)該都知道RPG的游戲地圖一般都比較大 今天我和大家分享一下在RPG游戲中如何來處理超出手機(jī)屏幕大小的游戲地圖。2014-06-06
Android自定義View實(shí)現(xiàn)天氣預(yù)報(bào)折線圖
這篇文章主要為大家詳細(xì)介紹了Android自定義View實(shí)現(xiàn)天氣預(yù)報(bào)折線圖,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-09-09
Android項(xiàng)目依賴庫(kù)無法找到的解決方案
最近,我在編譯一個(gè)?Android?老項(xiàng)目時(shí)遇到了一個(gè)問題,錯(cuò)誤信息顯示無法找到?com.gyf.immersionbar:immersionbar:3.0.0?這個(gè)依賴,經(jīng)過一些排查和調(diào)試,我找到了幾種解決方法,今天就來分享一下如何解決這個(gè)問題,需要的朋友可以參考下2025-03-03
Android端內(nèi)數(shù)據(jù)狀態(tài)同步方案VM-Mapping詳解
這篇文章主要介紹了Android端內(nèi)數(shù)據(jù)狀態(tài)同步方案VM-Mapping詳解,本篇文章通過簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-09-09
Android 對(duì)手機(jī)網(wǎng)絡(luò)的檢測(cè)和監(jiān)聽的方法示例
本篇文章主要介紹了Android 對(duì)手機(jī)網(wǎng)絡(luò)的檢測(cè)和監(jiān)聽的方法示例,主要使用BroadcastReceiver廣播接收器來接收網(wǎng)絡(luò)狀態(tài),現(xiàn)在分享給大家,也給大家做個(gè)參考,有興趣的一起來了解一下2018-03-03

