先上一张图看下效果:2 l5 M& W8 |3 M
3 d/ C8 e0 s" x2 B1 r/ u
主要实现功能有:
( ]6 l1 D3 D6 Q- Z5 u$ n! q 1.支持左右滑动,每次滑动一个tab
8 `/ f3 W* u( v4 d% Z0 r 2.支持tab点击,直接跳到对应tab- i' } Q% d1 \. E' |; Q$ t
3.选中的tab一直处于居中位置7 g$ v t1 l K$ F1 a! c
4.支持部分UI自定义(大家可根据需要自己改动)
5 j1 q' l" a" T% F! Q# e5 g 5.tab点击回调9 ^( r k* F$ t" J3 ~. ~) G! N
6.内置Tab接口,放入的内容需要实现Tab接口& g; \) N) B! }
7.设置预选中tab
. \8 R& D- B( z* p! L- Y' a
- public class CameraIndicator extends LinearLayout {
- // 当前选中的位置索引
- private int currentIndex;
- //tabs集合
- private Tab[] tabs;
-
- // 利用Scroller类实现最终的滑动效果
- public Scroller mScroller;
- //滑动执行时间(ms)
- private int mDuration = 300;
- //选中text的颜色
- private int selectedTextColor = 0xffffffff;
- //未选中的text的颜色
- private int normalTextColor = 0xffffffff;
- //选中的text的背景
- private Drawable selectedTextBackgroundDrawable;
- private int selectedTextBackgroundColor;
- private int selectedTextBackgroundResources;
- //是否正在滑动
- private boolean isScrolling = false;
-
- private int onLayoutCount = 0;
-
-
- public CameraIndicator(Context context) {
- this(context, null);
- }
-
- public CameraIndicator(Context context, @Nullable AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public CameraIndicator(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- mScroller = new Scroller(context);
-
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- int widthMode = MeasureSpec.getMode(widthMeasureSpec);
- int widthSize = MeasureSpec.getSize(widthMeasureSpec);
- int heightMode = MeasureSpec.getMode(heightMeasureSpec);
- int heightSize = MeasureSpec.getSize(heightMeasureSpec);
- //测量所有子元素
- measureChildren(widthMeasureSpec, heightMeasureSpec);
- //处理wrap_content的情况
- int width = 0;
- int height = 0;
- if (getChildCount() == 0) {
- setMeasuredDimension(0, 0);
- } else if (widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.AT_MOST) {
- for (int i = 0; i < getChildCount(); i++) {
- View child = getChildAt(i);
- width += child.getMeasuredWidth();
- height = Math.max(height, child.getMeasuredHeight());
- }
- setMeasuredDimension(width, height);
- } else if (widthMode == MeasureSpec.AT_MOST) {
- for (int i = 0; i < getChildCount(); i++) {
- View child = getChildAt(i);
- width += child.getMeasuredWidth();
- }
- setMeasuredDimension(width, heightSize);
- } else if (heightMode == MeasureSpec.AT_MOST) {
- for (int i = 0; i < getChildCount(); i++) {
- View child = getChildAt(i);
- height = Math.max(height, child.getMeasuredHeight());
- }
- setMeasuredDimension(widthSize, height);
- } else {
- //如果自定义ViewGroup之初就已确认该ViewGroup宽高都是match_parent,那么直接设置即可
- setMeasuredDimension(widthSize, heightSize);
- }
- }
-
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- //给选中text的添加背景会多次进入onLayout,会导致位置有问题,暂未解决
- if (onLayoutCount > 0) {
- return;
- }
- onLayoutCount++;
-
- int counts = getChildCount();
- int childLeft = 0;
- int childRight = 0;
- int childTop = 0;
- int childBottom = 0;
- //居中显示
- int widthOffset = 0;
-
-
- //计算最左边的子view距离中心的距离
- for (int i = 0; i < currentIndex; i++) {
- View childView = getChildAt(i);
- widthOffset += childView.getMeasuredWidth() + getMargins(childView).get(0)+getMargins(childView).get(2);
- }
-
- //计算出每个子view的位置
- for (int i = 0; i < counts; i++) {
- View childView = getChildAt(i);
- childView.setOnClickListener(v -> moveTo(v));
- if (i != 0) {
- View preView = getChildAt(i - 1);
- childLeft = preView.getRight() +getMargins(preView).get(2)+ getMargins(childView).get(0);
- } else {
- childLeft = (getWidth() - getChildAt(currentIndex).getMeasuredWidth()) / 2 - widthOffset;
- }
- childRight = childLeft + childView.getMeasuredWidth();
- childTop = (getHeight() - childView.getMeasuredHeight()) / 2;
- childBottom = (getHeight() + childView.getMeasuredHeight()) / 2;
- childView.layout(childLeft, childTop, childRight, childBottom);
- }
-
- TextView indexText = (TextView) getChildAt(currentIndex);
- changeSelectedUIState(indexText);
-
|