自定義橫向日期選擇器,可滑動,可點選
阿新 • • 發佈:2019-01-07
佈局檔案比較簡單,直接上程式碼:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="${relativePackage}.${activityClass}" >
<LinearLayout
android:id="@+id/ll"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<Button
android:id="@+id/btn_left"
android:layout_width="24dp"
android:layout_height="match_parent" />
<com.wscq.dataindicator.DataIndicatorView
android:id="@+id/data_indicator"
android:layout_width="0dp"
android:layout_height="135dp"
android:layout_weight="1" >
</com.wscq.dataindicator.DataIndicatorView>
<Button
android:id="@+id/btn_right"
android:layout_width="24dp"
android:layout_height="match_parent" />
</LinearLayout>
<TextView
android:id="@+id/tv_context"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/ll"
android:gravity="center"
android:textSize="30sp" />
</RelativeLayout>
其中主要的難度就是自定義了一個橫向的LinearLayout,其中因為只是攔截橫向滾動,所以需要有如下的事件分發程式碼:
/** 事件分發,只攔截橫向滑動,不攔截其他事件 */
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean intercepted = false;
int x = (int) ev.getX();
int y = (int) ev.getY();
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN: {
intercepted = false;
if (!mScroller.isFinished()) {
mScroller.abortAnimation();
intercepted = true;
}
break;
}
case MotionEvent.ACTION_MOVE: {
int deltaX = x - mLastXIntercept;
int deltaY = y - mLastYIntercept;
// 判斷是不是橫向滑動
if (Math.abs(deltaX) > Math.abs(deltaY)) {
intercepted = true;
} else {
intercepted = false;
}
// 判斷是否是有效的滑動
if (Math.abs(deltaX) < ViewConfiguration.get(getContext()).getScaledTouchSlop()) {
intercepted = false;
}
break;
}
case MotionEvent.ACTION_UP: {
intercepted = false;
break;
}
default:
break;
}
mLastX = x;
mLastY = y;
mLastXIntercept = x;
mLastYIntercept = y;
return intercepted;
}
/** 橫向滑動時候的相關處理操作 */
@Override
public boolean onTouchEvent(MotionEvent event) {
mVelocityTracker.addMovement(event);
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
if (!mScroller.isFinished()) {
mScroller.abortAnimation();
}
break;
}
case MotionEvent.ACTION_MOVE: {
// 獲取水平方向的移動距離
int deltaX = x - mLastX;
// 因為是水平移動,所以這個變數並沒有使用
int deltaY = y - mLastY;
// 移動到對應的地方
scrollBy(-deltaX, 0);
break;
}
case MotionEvent.ACTION_UP: {
// 設定滾動時間
mVelocityTracker.computeCurrentVelocity(1000);
// 當水平距離大於某個值時候,移動到下一頁,否則停留在當前頁
float xVelocity = mVelocityTracker.getXVelocity();
int page = mChoosePage;
if (Math.abs(xVelocity) >= mLayoutWidth / 3) {
// 更新當前螢幕的頁數
page = xVelocity > 0 ? page - 1 : page + 1;
}
scrollPage(page);
mVelocityTracker.clear();
break;
}
default:
break;
}
// 更新最後觸控點的座標
mLastX = x;
mLastY = y;
return true;
}
這裡的橫向滑動是彈性滑動,實現彈性滑動需要有如下程式碼:
/**
* 頁數改變時的滾動方法
*
* @param page
*/
public void scrollPage(int page) {
// 取到正確的page值
mChoosePage = Math.max(0, Math.min(page, mPageSum));
// 如果顯示的不是當前頁,重置所有文字顏色,防止view複用引發的字型顏色顯示異常
if (mChooseIndex / 7 == mChoosePage) {
highLightTextView(mChooseIndex);
} else {
resetTextViewColor();
}
// 滾動到對應的位置
int scrollX = getScrollX();
int delta = mChoosePage * mLayoutWidth - scrollX;
mScroller.startScroll(scrollX, 0, delta, 0, 1000);
invalidate();
// 回撥頁面改變監聽
if (null != listener) {
listener.onPageChangedListener(mChoosePage);
}
}
/** 覆寫方法,用來實現彈性滑動 */
@Override
public void computeScroll() {
super.computeScroll();
if (mScroller.computeScrollOffset()) {
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
postInvalidate();
}
}
“`