布局文件比较简单,直接上代码:
<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();
}
}
“`
具体的代码可以参考如下地址:
https://github.com/h55l55/DateIndicator