项目经理突然要求做一个有切换指向的标题头,开始想使用TabLayout,TabLayout的指示器只可以设置颜色,因此我就自己写了一个Layout,话不多说,先说下思路
- 可以设置多个、线性的标题,因此可以继承LinearLayout
- 指示图标可以使用onDraw绘制上去
- 根据ViewPager滑动进行设置指示图标的位置
- 可以手指滑动标题,进行切换ViewPager界面
思路就是这样,好了,话不多说,直接上代码
public class MyTitleLayout extends LinearLayout {
private int mCount;
private int mWidth;
private int mHeight;
private Paint mPaint;
private int mStartWidth;
private int mChildWidth;
private Bitmap mBitmap;
private int mStartX;
private int mTouchSlop;
//判断标题是否可以滑动,false:不可以
private boolean mCanScroll;
//标题滑动监听
private OnTitleScroll mOnTitleScroll;
private int mBitmapWidth;
private int mBitmapHeight;
public MyTitleLayout(Context context) {
super(context);
initData();
}
public MyTitleLayout(Context context, AttributeSet attrs) {
super(context, attrs);
initData();
}
public MyTitleLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initData();
}
private void initData() {
//不调用该方法不能进行绘制
setWillNotDraw(false);
mPaint = new Paint();
mPaint.setColor(Color.RED);
mPaint.setAntiAlias(true);
//初始化默认图标
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.mark);
mBitmap = Bitmap.createScaledBitmap(bitmap, bitmap.getWidth(), bitmap.getHeight(), true);
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(mBitmap, mStartWidth + mChildWidth / 2 - mBitmapWidth / 2, mHeight - mBitmapHeight, mPaint);
super.onDraw(canvas);
}
public interface OnTitleScroll {
void onTitleScroll(int position);
}
/**
* 设置标题是否可以滑动,设置标题滑动监听
*
* @param onTitleScroll
* @param canScroll
*/
public void setOnTitleScroll(OnTitleScroll onTitleScroll, boolean canScroll) {
mCanScroll = canScroll;
if (mCanScroll && onTitleScroll == null) {
mCanScroll = false;
}
mOnTitleScroll = onTitleScroll;
}
/**
* 滑动时调用该方法,参数为将要滑动到的position
*
* @param px
*/
public void onScrollTo(int px) {
//viewPager会在position变化时突然传过来一个0,如果不进行判断,会重置
if (mStartWidth - px / 2 >= mWidth / (mCount + 1)) {
return;
}
mStartWidth = px / 2;
invalidate();
}
/**
* 滑动时调用该方法,参数为将要滑动的距离
*
* @param px
*/
public void onScrollFor(int px) {
//边界判定
if ((mStartWidth + px) > 0 && (mStartWidth + px) < mChildWidth * (mCount - 1)) {
mStartWidth += px;
invalidate();
}
}
/**
* 滑动结束后调用,count为判定图标显示在第几个
*
* @param count
*/
public void onFinishScroll(int count) {
mStartWidth = mChildWidth * count;
invalidate();
}
/**
* 滑动标题结束后调用该方法
*/
private void onFinishScroll() {
mStartWidth += mChildWidth / 2 - mBitmapWidth / 2;
for (int i = 0; i < mCount; i++) {
int startPosition = mChildWidth * i;
int endPosition = mChildWidth * (i + 1);
if (mStartWidth >= startPosition && mStartWidth < endPosition) {
onFinishScroll(i);
if (mOnTitleScroll != null) {
mOnTitleScroll.onTitleScroll(i);
}
break;
}
}
}
/**
* 使用外部拦截法
*
* @param event
* @return
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
if (!mCanScroll) {
return false;
}
boolean intercept = false;
int x = (int) getX();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
intercept = false;
break;
case MotionEvent.ACTION_MOVE:
int moveX = (int) event.getX();
if (Math.abs(moveX - x) > mTouchSlop) {
intercept = true;
} else {
intercept = false;
}
break;
case MotionEvent.ACTION_UP:
intercept = false;
break;
}
return intercept;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mStartX = (int) event.getX();
break;
case MotionEvent.ACTION_MOVE:
int moveX = (int) event.getX();
onScrollFor(moveX - mStartX);
mStartX = moveX;
break;
case MotionEvent.ACTION_UP:
onFinishScroll();
break;
}
return true;
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mCount = getChildCount();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mWidth = getMeasuredWidth();
mHeight = getMeasuredHeight();
mChildWidth = mWidth / mCount;
mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
mBitmapWidth = mBitmap.getWidth();
mBitmapHeight = mBitmap.getHeight();
}
控件虽然很简单,但是提供更换指示图标,可以根据ViewPager滑动,或者根据手势滑动。事件分发采用外部拦截法进行,比较简单。
控件项目地址:https://git.oschina.net/qiangshen/commentview.git
这是我开始维护的一个控件地址,这里面的控件都是我自己学习时或工作时写的,可能控件还有各种bug,可能我的做法太复杂或代码规范有问题,我希望大家可以帮我提出并改正。