HorizontalScrollView自定義輪播控件
最近由于項目需要,需要每屏顯示一張半圖檔且滾動時從後半張開始滾動,查了很多資料發現沒有符合自己項目的第三方于是就自己寫了個簡潔版的,相比較傳統viewpager輪播控件,更簡潔,不需要adapter友善使用。
- 首先需要自定義個view繼承HorizontalScrollView;
- 接下來就是在自定義的view中添加子控件了;
private View addView(final int position) {
ImageView imageView = new ImageView(context);
imageView.setLayoutParams(paramsImage);
imageView.setImageResource(list.get(position));
imageView.setScaleType(ImageView.ScaleType.FIT_XY);
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
onChildrenClickListener.onImageClickListener(position);
}
});
return imageView;
}
由于項目隻需要圖檔輪播,是以隻添加了圖檔,如果需要其他的布局各位可以在這個方法中添加直接的布局。
注意:由于圖檔尺寸是伺服器發來,需要動态計算,需要用的LayoutParams,至于怎麼選需要看父布局,比如本項目中的布局是LinearLayout,就需要選LinearLayout.LayoutParams,具體的要具體問題具體分析。
- 子控件加完後,滾動比較好寫了,用HorizontalScrollView自帶的scrollTo和smoothScrollTo方法就好,這兩個方法都能實作滾動的功能,唯一的差別是scrollTo滾動不帶動畫,smoothScrollTo滾動帶動畫,是以我選擇了smoothScrollTo。
this.smoothScrollTo(count * scrollWidth, );
注意:count圖檔位置,scrollWidth你想要的滾動距離。
- 由于就需要讓控件能滾動一定的指定距離,而不是 HorizontalScrollView的跟随手勢滑動,是以需要重寫dispatchTouchEvent方法來計算手指滑動了指定距離,并使控件滾動你想要的距離。由于備注比較詳細就不啰嗦了,代碼如下:
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN: //手指按下ViewPageer時
//獲得按下時XY軸的坐标
downX = ev.getX();
downY = ev.getY();
break;
case MotionEvent.ACTION_UP: //擡起觸摸View的手指時
float diffx = ev.getX() - downX;
float diffy = ev.getY() - downY;
if (Math.abs(diffx) > Math.abs(diffy)) {
// 使用者手指從左往右
// 如果是在第一個頁面,手指從左往右,父容器響應
LogUtil.d("zqr", "水準滑動距離" + diffx);
if (diffx > ) {
// 手指從左往右滑動,自己響應touch
if (diffx > MyUtils.getScreenWidth(context) / ) {
handler.sendEmptyMessage();
LogUtil.d("zqr", "手指從左往右滑動,自己響應touch");
getParent().requestDisallowInterceptTouchEvent(false);
} else {
LogUtil.d("zqr", "手指從左往右滑動,子控件響應touch");
getParent().requestDisallowInterceptTouchEvent(true);
}
} else {
// 手指從右往左滑動,自己響應touch
if (diffx < -MyUtils.getScreenWidth(context) / ) {
handler.sendEmptyMessage();
LogUtil.d("zqr", "手手指從右往左滑動,自己響應touch");
} else {
LogUtil.d("zqr", "手手指從右往左滑動,子控件響應touch");
}
}
} else {
// touch交給父容器
LogUtil.d("zqr", "垂直滑動大于水準滑動,父容器響應touch");
}
isPlay = true;
break;
case MotionEvent.ACTION_MOVE: //在View裡面滑動手指時
LogUtil.d("zqr", "滑動" + MotionEvent.ACTION_MOVE);
break;
}
return super.dispatchTouchEvent(ev);
}
- 對你沒看錯我上面的代碼了用到了handler,大部分童鞋肯定猜出來了,我是要用來實作自動播放功能,畢竟現在輪播都帶自動播放功能,是以我們也得與時俱進嘛。
- 那麼就來說說自動輪播的實作吧,實作方法有很多,不過我覺得用Timer來實作比較友善,其他的比如Thread什麼的大家可以自己根據需求修改。Timer和TimerTask用完需要調用cancel()方法否則,會影響性能,代碼如下:
private void timer() {
timer = new Timer();
timerTask = new TimerTask() {
@Override
public void run() {
if (isPlay) {
handler.sendEmptyMessage();
}
}
};
timer.scheduleAtFixedRate(timerTask, time, time);
}
寫到這基本上自動輪播的功能就實作了,因為一般輪播圖檔都需要監聽點選事件,在這就有個小問題,隻要手指滑動控件就會執行圖檔的監聽事件,這就不是我想要的了,我們需要的是手指滑動一定距離圖檔換上一張或者下一張而不執行點選事件,隻有在手指按下時才執行點選事件。是以還需要重寫onTouchEvent方法,getParent().requestDisallowInterceptTouchEvent(true)傳回true 就是本次觸摸自己消耗掉響應,不傳給子控件,代碼如下:
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
LogUtil.d("zqr", "按下" + MotionEvent.ACTION_DOWN);
isPlay = false;
getParent().requestDisallowInterceptTouchEvent(true);
break;
case MotionEvent.ACTION_UP:
LogUtil.d("zqr", "按上" + MotionEvent.ACTION_UP);
getParent().requestDisallowInterceptTouchEvent(true);
break;
case MotionEvent.ACTION_CANCEL:
LogUtil.d("zqr", "取消" + MotionEvent.ACTION_CANCEL);
getParent().requestDisallowInterceptTouchEvent(true);
break;
case MotionEvent.ACTION_MOVE:
LogUtil.d("zqr", "滑動" + MotionEvent.ACTION_MOVE);
getParent().requestDisallowInterceptTouchEvent(true);
break;
}
return super.onInterceptTouchEvent(ev);
}
-
- 大家肯定會說,輪播沒有訓示器怎麼可以,是的訓示器肯定有啊,也是我自己寫的,十分的簡單,就是繼承LinearLayout ,原理和輪播添加子控件差不多,在這就不多說了之後會有完整的項目上傳的。
- 至此,基本上自定義半圖輪播就完成了,而且這個控件的擴充性也不錯,可以同屏顯示2.5,3.5等等多種需求的輪播效果。
- 完整demo下載下傳位址:http://download.csdn.net/download/zqrdy10/10139666 -
- 代碼中肯定存在很多不足的地方,歡迎大家多多發表意見,可以私信我哦