Android——自定义ViewPager指示器

本文介绍如何在Android中创建一个自定义的ViewPager指示器,以实现各种形状(如正方形、长方形、三角形、圆形)的指示效果。通过示例展示了三角形指示器在滑动时的变化,并提供了相关代码实现,包括自定义View的详细步骤和在Activity中的使用方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

很多ViewPager和下面的图形绑定一块来滚动,也就是指示器,指示器可以是很多,正

方形,长方形,三角形,圆形等。

这里举一个三角形例子:

效果图:未滑动
这里写图片描述

滑动中:

这里写图片描述

这里滑动只要超过倒数第二个就自动向后滑动。

上代码:

自定义view:



public class ViewPagerIndicator extends LinearLayout {
    private Paint paint;
    private Path path;
    private int triangleWidth;
    private int triangleHeight;
    private static final float RADIO_TRIANGLE_WIDTH = 1 / 6f;
    private static final int HIGHCOLOR = 0xffffffff;
    private static final int LOWERCOLOR = 0x88ffffff;
    private int initTranslationX;
    private int moveTranslationX;
    private int TabVisibleCount;
    private static final int COUNT_DEFAULT_TAB = 4;
    private List<String> titles = new ArrayList<String>();

    public ViewPagerIndicator(Context context, AttributeSet attrs) {
        super(context, attrs);
        // 获取可见Tab的数量
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ViewPagerIndicator);
        TabVisibleCount = ta.getInt(R.styleable.ViewPagerIndicator_visible_tab_count, COUNT_DEFAULT_TAB);
        if (TabVisibleCount < 0) {
            TabVisibleCount = COUNT_DEFAULT_TAB;
        }
        ta.recycle();

        // 初始化画笔
        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setColor(Color.WHITE);
        paint.setStyle(Style.FILL);
        paint.setPathEffect(new CornerPathEffect(5));

    }

    public ViewPagerIndicator(Context context) {
        super(context, null);
        // TODO Auto-generated constructor stub
    }

    /**
     * 绘制三角形
     */

    /**
     * 没有背景时直接调用的是dispatchDraw()方法,draw()方法里包含了dispatchDraw()方法的调用。
     * 因此要在ViewGroup上绘制东西的时候往往重写的是dispatchDraw()方法而不是onDraw()方法
     */
    @Override
    protected void dispatchDraw(Canvas canvas) {
        // TODO Auto-generated method stub
        super.dispatchDraw(canvas);
        /*
         * 如果有save()和restore(), 那么平移、缩放、旋转等操作只对save()和restore()作用域之间的代码有效。
         * 当你用canvas的方法来进行这些操作的时候,其实是对整个画布进行了操作,
         * 那么之后在画布上的元素都会受到影响,所以我们在操作之前调用canvas.save()来保存画布当前的状态,
         * 当操作之后取出之前保存过的状态,这样就不会对其他的元素进行影响
         */
        canvas.save();
        canvas.translate(initTranslationX + moveTranslationX, getHeight());
        canvas.drawPath(path, paint);
        canvas.restore();
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        // TODO Auto-generated method stub
        super.onSizeChanged(w, h, oldw, oldh);
        triangleWidth = (int) (w / TabVisibleCount * RADIO_TRIANGLE_WIDTH);
        initTranslationX = w / TabVisibleCount / 2 - triangleWidth / 2;

        initTrangle();
    }

    /**
     * 在xml加载完成以后调用此方法
     */

    @Override
    protected void onFinishInflate() {
        // TODO Auto-generated method stub
        super.onFinishInflate();

        int count = getChildCount();
        if (count == 0)
            return;

        for (int i = 0; i < count; i++) {
            View view = getChildAt(i);
            LinearLayout.LayoutParams lp = (LayoutParams) view.getLayoutParams();
            // 如果之前设有weight 都设置为0
            lp.weight = 0;
            lp.width = getScreenWidth() / TabVisibleCount;
            view.setLayoutParams(lp);
        }
        setItemClickEvent();
    }

    private int getScreenWidth() {
        // TODO Auto-generated method stub
        WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics outMetrics = new DisplayMetrics();
        wm.getDefaultDisplay().getMetrics(outMetrics);
        return outMetrics.widthPixels;
    }

    /**
     * 初始化三角形
     */
    private void initTrangle() {
        // TODO Auto-generated method stub
        path = new Path();
        triangleHeight = (int) (triangleWidth / 2 / 1.7);
        path.moveTo(0, 0);
        path.lineTo(triangleWidth, 0);
        path.lineTo(triangleWidth / 2, -triangleHeight);
        path.close();
    }

    /**
     * 指示器跟随手指移动
     * 
     * @param position
     *            当前页
     * @param offset(0~1)
     *            偏移量
     */
    public void scoll(int position, float offset) {
        // TODO Auto-generated method stub
        int tabWidth = getWidth() / TabVisibleCount;
        moveTranslationX = (int) (tabWidth * (position + offset));

        // 容器移动,当tab处于移动至最后一个时

        if (position >= (TabVisibleCount - 2) && offset > 0 && getChildCount() > TabVisibleCount) {

            if (TabVisibleCount != 1) {

                scrollTo((position - (TabVisibleCount - 2)) * tabWidth + (int) (tabWidth * offset), 0);
            } else {
                scrollTo(position * tabWidth + (int) (tabWidth * offset), 0);
            }
        }

        // 请求重绘三角形
        invalidate();
    }

    // 该方法需要在setTabitemTitles方法之前调用有效,因为用到了TabVisibleCount
    public void setVisibleTab(int count) {
        this.TabVisibleCount = count;
    }

    /**
     * 根据title动态创建TextView
     * 
     * @param title
     * @return
     */
    public void setTabitemTitles(List<String> titles) {
        if (titles != null && titles.size() > 0) {
            this.titles = titles;
        }
        for (String title : titles) {
            addView(getTextView(title));
        }
        setItemClickEvent();
    }

    private View getTextView(String title) {
        // TODO Auto-generated method stub
        TextView tv = new TextView(getContext());
        LinearLayout.LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
        lp.width = getScreenWidth() / TabVisibleCount;
        tv.setText(title);
        tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);
        tv.setGravity(Gravity.CENTER);
        tv.setLayoutParams(lp);
        tv.setTextColor(LOWERCOLOR);
        return tv;
    }

    /**
     * 用户的setOnPageChangeListener回调方法供外部使用
     * 
     * @author lpl
     *
     */
    public interface PageChangeListener {
        public void onPageScrollStateChanged(int arg0);

        public void onPageScrolled(int arg0, float arg1, int arg2);

        public void onPageSelected(int arg0);
    }

    private PageChangeListener listener;

    public void setOnPageChangeListener(PageChangeListener listener) {
        this.listener = listener;
    }

    /**
     * 关联ViewPager
     * 
     * @param pager
     * @param pos
     *            默认选中页
     */
    private ViewPager pager;

    public void setViewPager(final ViewPager pager, int pos) {
        this.pager = pager;
        pager.setOnPageChangeListener(new OnPageChangeListener() {

            @Override
            public void onPageScrollStateChanged(int arg0) {
                // TODO Auto-generated method stub

            }

            @Override
            public void onPageScrolled(int arg0, float arg1, int arg2) {
                // 总偏移量:arg0(position)*tabWidth+arg1(positionoffset)*tabWidth
                if (listener != null) {
                    listener.onPageScrolled(arg0, arg1, arg2);
                }
                scoll(arg0, arg1);

            }

            @Override
            public void onPageSelected(int arg0) {
                // TODO Auto-generated method stub
                if (listener != null) {
                    listener.onPageSelected(arg0);
                }
                HighTextView(arg0);
            }
        });
        pager.setCurrentItem(pos);
        HighTextView(pos);
    }

    public void resetColorTextView() {
        for (int i = 0; i < getChildCount(); i++) {
            TextView tv = (TextView) getChildAt(i);
            tv.setTextColor(LOWERCOLOR);
        }
    }

    /**
     * 设置高亮的TextView
     * 
     * @param position
     */
    public void HighTextView(int position) {
        resetColorTextView();
        TextView tv = (TextView) getChildAt(position);
        tv.setTextColor(HIGHCOLOR);
    }

    /**
     * 设置tab的点击事件
     */
    public void setItemClickEvent() {
        for (int i = 0; i < getChildCount(); i++) {
            final int j = i;
            TextView tv = (TextView) getChildAt(i);
            tv.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    // TODO Auto-generated method stub
                    pager.setCurrentItem(j);
                }
            });
        }
    }
}

在Activity中onCreate调用此控件:

// setVisibleTab该方法需要在setTabitemTitles方法之前调用有效,
//因为用到了TabVisibleCount
        // indicator.setVisibleTab(3);设置可见的title个数

        //titles是List容器存放TextView
        indicator.setTabitemTitles(titles);

        //默认0是第一个title为高亮选中
        indicator.setViewPager(viewpager, 0);
        viewpager.setAdapter(adapter);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值