【笔记】自定义控件——ViewPager指示器

本文介绍了一种自定义ViewPager指示器的方法,通过继承LinearLayout并动态创建指示点来实现广告滚动时的页面指示功能。文章详细解释了如何创建选中指示点,并展示了如何根据ViewPager的状态更新指示器的位置。

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

ViewPager的用途很广,像滚动广告、引导页等就常用这个控件实现,而在这些控件里常常会需要一个指示器来表示当前所显示的是第几张广告或第几页。

不堪回首的过去

以前在滚动广告时常常在布局文件中放一个LinearLayout,然后在代码中动态创建ImageView,添加到容器中,

dotList = new ArrayList<ImageView>();
for (int i=0;i<list.size();i++) {
	LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(10,10);
	lp.setMargins(5,5,5,5);
	ImageView imageView = new ImageView(mContext);
	imageView.setLayoutParams(lp);
	imageView.setImageResource(R.drawable.dot_normal);
	//添加到指示器列表中
	dotList.add(imageView);
	//添加到LinearLayout容器中
	llDot.addView(imageView);
}

每当广告滚动就去改变一下选中的指示点
for (int i=0;i<dotList.size();i++){
	dotList.get(i).setImageResource(R.drawable.dot_normal);
}
dotList.get(position%dotList.size()).setImageResource(R.drawable.dot_light);

自定义ViewPager指示器

根据原来的做法是在代码中动态创建指示点,然后加入到LinearLayout容器中,自定义的控件也通过继承LinearLayout来实现。

定义一个选中的指示点。

    class SelectView extends View {
        private Paint mPaint;

        public SelectView(Context context) {
            super(context);

            mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            mPaint.setColor(colorSelected);
        }

        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            setMeasuredDimension(radius * 2, radius * 2);
        }

        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            paint.setColor(colorSelected);
            canvas.drawCircle(radius, radius, radius, mPaint);
        }
    }

为什么只定义选中的指示点呢?

这里把指示点分为选中指示点和未选中指示点,未选中指示点无论是颜色和位置在控件显示之后都不需要改变,在这里可以当作背景,而选中指示点则需要随着ViewPager的onPageScrolled而移动。

    /**
     * 绘制背景指示器
     *
     * @param canvas
     */
    private void drawBackground(Canvas canvas) {
        paint.setColor(colorNormal);
        for (int i = 0; i < num; i++) {
            canvas.drawCircle(
                    padding + radius + i * (2 * radius + padding),
                    padding + radius,
                    radius,
                    paint
            );
        }
    }
根据ViewPager的onPageScrolled显示选中点的位置

    /**
     * 设置页数和偏移
     *
     * @param pager
     * @param offset
     */
    public void setPagerAndOffset(int pager, float offset) {
        this.pager = pager;
        this.offset = offset;
        //调用会使View测量、布局、重绘
        requestLayout();
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        //设置选中点的位置
        selectView.layout(
                (int) (padding + (padding + 2 * radius) * (pager + offset)),
                padding,
                (int) (padding + (padding + 2 * radius) * (pager + 1 + offset)),
                padding + radius * 2
        );
    }

完整实现

public class ViewPagerIndicator extends LinearLayout {
    public ViewPagerIndicator(Context context) {
        this(context, null);
    }

    public ViewPagerIndicator(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ViewPagerIndicator(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        init(attrs);
    }

    //指示器半径
    private int radius = 10;
    //画笔
    private Paint paint;
    //普通指示器颜色
    private int colorNormal = Color.GRAY;
    //选中指示器颜色
    private int colorSelected = Color.RED;
    //间距
    private int padding = 20;
    //个数
    private int num = 3;
    //选中的指示器
    private SelectView selectView;
    //当前选中页
    private int pager;
    //偏移
    private float offset;

    /**
     * 初始化
     *
     * @param attrs
     */
    private void init(AttributeSet attrs) {
        //初始化属性
        initAttrs(attrs);
        //初始化工具
        initTools();
        //不调用自身onDraw
        setWillNotDraw(false);
    }

    /**
     * 初始化属性
     *
     * @param attrs
     */
    private void initAttrs(AttributeSet attrs) {
        TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.ViewPagerIndicator);
        radius = typedArray.getInt(R.styleable.ViewPagerIndicator_radius, 5);
        colorNormal = typedArray.getColor(R.styleable.ViewPagerIndicator_colorNormal, Color.GRAY);
        colorSelected = typedArray.getColor(R.styleable.ViewPagerIndicator_colorSelected, Color.RED);
        padding = typedArray.getInt(R.styleable.ViewPagerIndicator_padding, 10);
        num = typedArray.getInt(R.styleable.ViewPagerIndicator_num, 3);
        typedArray.recycle();
    }

    /**
     * 初始化工具
     */
    private void initTools() {
        //初始化画笔
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setColor(colorNormal);
        //初始化选中点
        selectView = new SelectView(getContext());
        addView(selectView);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //计算设置控件的宽高
        setMeasuredDimension(padding + (padding + 2 * radius) * num, (padding + radius) * 2);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawBackground(canvas);
    }

    /**
     * 绘制背景指示器
     *
     * @param canvas
     */
    private void drawBackground(Canvas canvas) {
        paint.setColor(colorNormal);
        for (int i = 0; i < num; i++) {
            //绘制每个点的位置
            canvas.drawCircle(
                    padding + radius + i * (2 * radius + padding),
                    padding + radius,
                    radius,
                    paint
            );
        }
    }

    public void setNum(int num) {
        this.num = num;
    }

    /**
     * 设置页数和偏移
     *
     * @param pager
     * @param offset
     */
    public void setPagerAndOffset(int pager, float offset) {
        this.pager = pager;
        this.offset = offset;
        //调用会使View测量、布局、重绘
        requestLayout();
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        //设置选中点的位置
        selectView.layout(
                (int) (padding + (padding + 2 * radius) * (pager + offset)),
                padding,
                (int) (padding + (padding + 2 * radius) * (pager + 1 + offset)),
                padding + radius * 2
        );
    }

    /**
     * 选中的指示器
     */
    class SelectView extends View {
        private Paint mPaint;

        public SelectView(Context context) {
            super(context);

            mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            mPaint.setColor(colorSelected);
        }

        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            setMeasuredDimension(radius * 2, radius * 2);
        }

        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            paint.setColor(colorSelected);
            canvas.drawCircle(radius, radius, radius, mPaint);
        }
    }
}















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值