導(dǎo)語
主要是為了分析一些我用過的第三方控件胧砰,學(xué)習(xí)一下一些酷炫的特效是怎么實現(xiàn)的。ConvenientBanner是我之前在github上翻到的一款輪播圖控件苇瓣,項目催的比較急就開始用了尉间,現(xiàn)在讓我這個磚戰(zhàn)士來分析一下。
腦補原理
先隨便腦補一下這玩意大概是怎么做的击罪,一個viewpager哲嘲,加個定時器,開始滑啊滑媳禁,大概就這樣了吧眠副。
??ConvenientBanner繼承的是LinearLayout???LinearLayout???LinearLayout???
分析
直接構(gòu)造方法
public ConvenientBanner(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.ConvenientBanner);
canLoop = a.getBoolean(R.styleable.ConvenientBanner_canLoop,true);
a.recycle();
init(context);
}
不多說,直接init(context);
private void init(Context context) {
View hView = LayoutInflater.from(context).inflate(
R.layout.include_viewpager, this, true);
viewPager = (CBLoopViewPager) hView.findViewById(R.id.cbLoopViewPager);
loPageTurningPoint = (ViewGroup) hView
.findViewById(R.id.loPageTurningPoint);
initViewPagerScroll();
adSwitchTask = new AdSwitchTask(this);
}
原來是viewpager+ LinearLayout竣稽,LinearLayout里面放的是小圓點指示器囱怕,都忘記有小圓點這東西, = = 丧枪。所以用LinearLayout包起來了光涂。讓我looklook布局文件,CBLoopViewPager拧烦?看來這就是關(guān)鍵所在咯。
CBLoopViewPager
讓我們看看钝计,有一些必要的方法在里面恋博。
- CBPageAdapter
繼承PagerAdapter,重寫了幾個方法一個一個看私恬。
@Override
public Object instantiateItem(ViewGroup container, int position) {
int realPosition = toRealPosition(position);
View view = getView(realPosition, null, container);
// if(onItemClickListener != null) view.setOnClickListener(onItemClickListener);
container.addView(view);
return view;
}
展示pager用的债沮,返回一個自己想要的view,第一行判斷當(dāng)前position本鸣,第二行根據(jù)position獲取view添加點擊事件疫衩。getView里面有一個holder抽出來可以自己構(gòu)造想要展示的view。這個用的時候有印象荣德,可以直接構(gòu)造闷煤,用著還挺方便的。
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
View view = (View) object;
container.removeView(view);
}
移除item時候調(diào)用移除掉之前的view
@Override
public void finishUpdate(ViewGroup container) {
int position = viewPager.getCurrentItem();
if (position == 0) {
position = viewPager.getFristItem();
} else if (position == getCount() - 1) {
position = viewPager.getLastItem();
}
try {
viewPager.setCurrentItem(position, false);
}catch (IllegalStateException e){}
}
更新后期調(diào)用的方法涮瞻,在這里面調(diào)用顯示到指定位置的view鲤拿,獲取了當(dāng)前顯示的view的position,判斷了一下第一個和最后一個....然后卡住了署咽。丫嘍近顷,啥東西生音,為啥position==0的時候獲取的是positon == datas.size?然后還移動了過去?待老夫冥想一下.....
@Override
public int getCount() {
return canLoop ? getRealCount()*MULTIPLE_COUNT : getRealCount();
}
原來漏掉了這一段...MULTIPLE_COUNT是300.我說咋又fristItem又lastItem,又RealCount的,原來是他給乘了300啊窒升。這樣就差不多了缀遍,因為需要循環(huán)所以需要處理循環(huán)的item。
??Adpater差不多就這樣了饱须,感覺還蠻容易的域醇。
- onTouchEvent
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (isCanScroll) {
if (onItemClickListener != null) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
oldX = ev.getX();
break;
case MotionEvent.ACTION_UP:
newX = ev.getX();
if (Math.abs(oldX - newX) < sens) {
onItemClickListener.onItemClick((getRealItem()));
}
oldX = 0;
newX = 0;
break;
}
}
return super.onTouchEvent(ev);
} else
return false;
}
點擊事件,原來是判斷了UP和DOWN冤寿,我說有時候咋點著費勁呢歹苦,看上去是判斷左右滑動和單擊事件的,恩督怜,一定是這樣殴瘦。
- 其他
??別的都是些常規(guī)的屬性設(shè)置,沒啥可看的号杠。
醒醒蚪腋,醒醒,你丫倒是轉(zhuǎn)啊~~~~
- AdSwitchTask 轉(zhuǎn)轉(zhuǎn)轉(zhuǎn)
static class AdSwitchTask implements Runnable {
private final WeakReference<ConvenientBanner> reference;
AdSwitchTask(ConvenientBanner convenientBanner) {
this.reference = new WeakReference<ConvenientBanner>(convenientBanner);
}
@Override
public void run() {
ConvenientBanner convenientBanner = reference.get();
if(convenientBanner != null){
if (convenientBanner.viewPager != null && convenientBanner.turning) {
int page = convenientBanner.viewPager.getCurrentItem() + 1;
convenientBanner.viewPager.setCurrentItem(page);
convenientBanner.postDelayed(convenientBanner.adSwitchTask, convenientBanner.autoTurningTime);
}
}
}
}
開線程姨蟋,這是viewpager切換屉凯,convenientBanner.autoTurningTime,還專門動態(tài)搞了個時間眼溶。好的悠砚,你終于可以輪播了,啪啪啪堂飞。
贈品:圓點指示器
- 圓點基礎(chǔ)屬性
public ConvenientBanner setPageIndicator(int[] page_indicatorId) {
loPageTurningPoint.removeAllViews();
mPointViews.clear();
this.page_indicatorId = page_indicatorId;
if(mDatas==null)return this;
for (int count = 0; count < mDatas.size(); count++) {
// 翻頁指示的點
ImageView pointView = new ImageView(getContext());
pointView.setPadding(5, 0, 5, 0);
if (mPointViews.isEmpty())
pointView.setImageResource(page_indicatorId[1]);
else
pointView.setImageResource(page_indicatorId[0]);
mPointViews.add(pointView);
loPageTurningPoint.addView(pointView);
}
pageChangeListener = new CBPageChangeListener(mPointViews,
page_indicatorId);
viewPager.setOnPageChangeListener(pageChangeListener);
pageChangeListener.onPageSelected(viewPager.getRealItem());
if(onPageChangeListener != null)pageChangeListener.setOnPageChangeListener(onPageChangeListener);
return this;
}
配置圓點灌旧,往LinearLayout強行插♂入圖片,這是監(jiān)聽回調(diào)不拉不拉绰筛,那樣吧枢泰,雖然看上去懂了,但是估計自己寫的時候夠嗆铝噩,默念三遍衡蚂,啦啦啦啦啦啦啦,OK
- 圓點的位置
public ConvenientBanner setPageIndicatorAlign(PageIndicatorAlign align) {
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) loPageTurningPoint.getLayoutParams();
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT, align == PageIndicatorAlign.ALIGN_PARENT_LEFT ? RelativeLayout.TRUE : 0);
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, align == PageIndicatorAlign.ALIGN_PARENT_RIGHT ? RelativeLayout.TRUE : 0);
layoutParams.addRule(RelativeLayout.CENTER_HORIZONTAL, align == PageIndicatorAlign.CENTER_HORIZONTAL ? RelativeLayout.TRUE : 0);
loPageTurningPoint.setLayoutParams(layoutParams);
return this;
}
作者可以的骏庸,夠人性的毛甲,RelativeLayout設(shè)置圓點的位置,左敞恋,中丽啡,右滿足你的所有體位,666
總結(jié)
- 就這樣硬猫,和我想的差不多补箍,關(guān)鍵是里面的一些細節(jié)自己想不到改执,比如點擊事件,按下的時候別滑動等等坑雅,自己寫肯定就是各種大坑辈挂,學(xué)習(xí)一個思路吧。另外裹粤,這篇文章從早上稀稀拉拉寫终蒂,寫到現(xiàn)在,感覺周期有些長了遥诉,和自己想的不太一樣.....期間還玩了一會SourceTree,git,github和Markdown嘿嘿嘿拇泣。