自定义拖动条android,Android自定义滑动带(横条指示器)

本文详细介绍了如何在Android中自定义滑动带(SlidingStrip),包括为什么要自定义、实现原理及自定义过程。通过分析TabLayout的源码,展示了SlidingStrip的绘制和更新过程,以及如何在没有TabLayout的情况下实现类似功能。最后,给出了作者自定义滑动带的简单实现和效果展示。
摘要由CSDN通过智能技术生成

一.滑动带

什么是Android滑动带,我们举个栗子

4e301419f852

image.png

就是图中的黑色长条,最典型的就是用在和viewpager或者多个fragment相关的地方,因此也有人称这个东西为Indicator(指示器)。

那我为什么称它为滑动带呢?有个使用和典型场景,有个控件叫TabLayout,它经常和viewpager一起使用,TabLayout的内部会自带这个横条指示器,看看内部的定义。

4e301419f852

image.png

它的官方给它命名为SlidingTabStrip,我翻译过来就是滑动带、滑动条。Tab是和TabLayout相关的命名,我可以再接下来都叫它SlidingStrip

二.自定义滑动带

1. 为什么要自定义SlidingStrip

既然系统的控件已经帮我封装好了,为什么还要重复造轮子。有时候可能某种特殊情况不适用TabLayout,需要自定义Tab或者其它一些SlidingStrip和Tab不连用的状态,那时候就只能自己写个SlidingStrip。

2.怎么自定义SlidingStrip

怎么去自定义,当然每个人都有每个人的做法,或者你脑洞能想出实现这个功能的方法,但这里既然官方都写了,我个人肯定是会按照官方的做法去做。至于官方怎么做的,我们只能看看源码,看TabLayout内部的SlidingTabStrip类

private class SlidingTabStrip extends LinearLayout {

private int mSelectedIndicatorHeight;

private final Paint mSelectedIndicatorPaint;

private int mSelectedPosition = -1;

private float mSelectionOffset;

private int mIndicatorLeft = -1;

private int mIndicatorRight = -1;

private ValueAnimatorCompat mIndicatorAnimator;

SlidingTabStrip(Context context) {

super(context);

setWillNotDraw(false);

mSelectedIndicatorPaint = new Paint();

}

void setSelectedIndicatorColor(int color) {

if (mSelectedIndicatorPaint.getColor() != color) {

mSelectedIndicatorPaint.setColor(color);

ViewCompat.postInvalidateOnAnimation(this);

}

}

void setSelectedIndicatorHeight(int height) {

if (mSelectedIndicatorHeight != height) {

mSelectedIndicatorHeight = height;

ViewCompat.postInvalidateOnAnimation(this);

}

}

boolean childrenNeedLayout() {

for (int i = 0, z = getChildCount(); i < z; i++) {

final View child = getChildAt(i);

if (child.getWidth() <= 0) {

return true;

}

}

return false;

}

void setIndicatorPositionFromTabPosition(int position, float positionOffset) {

if (mIndicatorAnimator != null && mIndicatorAnimator.isRunning()) {

mIndicatorAnimator.cancel();

}

mSelectedPosition = position;

mSelectionOffset = positionOffset;

updateIndicatorPosition();

}

float getIndicatorPosition() {

return mSelectedPosition + mSelectionOffset;

}

@Override

protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {

......

}

@Override

protected void onLayout(boolean changed, int l, int t, int r, int b) {

......

}

private void setIndicatorPosition(int left, int right) {

if (left != mIndicatorLeft || right != mIndicatorRight) {

// If the indicator's left/right has changed, invalidate

mIndicatorLeft = left;

mIndicatorRight = right;

ViewCompat.postInvalidateOnAnimation(this);

}

}

void animateIndicatorToPosition(final int position, int duration) {

if (mIndicatorAnimator != null && mIndicatorAnimator.isRunning()) {

mIndicatorAnimator.cancel();

}

final boolean isRtl = ViewCompat.getLayoutDirection(this)

== ViewCompat.LAYOUT_DIRECTION_RTL;

final View targetView = getChildAt(position);

if (targetView == null) {

// If we don't have a view, just update the position now and return

updateIndicatorPosition();

return;

}

final int targetLeft = targetView.getLeft();

final int targetRight = targetView.getRight();

final int startLeft;

final int startRight;

if (Math.abs(position - mSelectedPosition) <= 1) {

// If the views are adjacent, we'll animate from edge-to-edge

startLeft = mIndicatorLeft;

startRight = mIndicatorRight;

} else {

// Else, we'll just grow from the nearest edge

final int offset = dpToPx(MOTION_NON_ADJACENT_OFFSET);

if (position < mSelectedPosition) {

// We're going end-to-start

if (isRtl) {

startLeft = startRight = targetLeft - offset;

} else {

startLeft = startRight = targetRight + offset;

}

} else {

// We're going start-to-end

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值