Android自定义超级炫酷的ViewPage指示器

请你先在我的回答里看到标题及类别,以便更好地组织答案。

标题:Android自定义超级炫酷的ViewPage指示器的完整攻略

类别:Android开发 / ViewPage指示器

1. 基本思路

要自定义一个炫酷的ViewPage指示器,我们需要完成以下几个步骤:

  1. 创建一个自定义View,用于渲染指示器;
  2. 实现ViewPager.OnPageChangeListener接口,监听ViewPager页面变化,实时更新指示器;
  3. 对指示器进行渐变、弹簧效果等美化处理。

2. 创建自定义View

创建自定义View的过程如下:

  1. 继承View类;
  2. 重写onMeasure方法用于测量View的大小;
  3. 重写onDraw方法用于绘制View。

以下是代码示例:

public class DotIndicatorView extends View {
    private int mDotNum = 0;
    private int mSelectedIndex = 0;
    private Paint mPaint;
    private int mRadius;
    private int mGap;
    private int mPaddingLeft;
    private int mPaddingRight;
    private int mPaddingTop;
    private int mPaddingBottom;

    public DotIndicatorView(Context context) {
        this(context, null);
    }

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

    public DotIndicatorView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setColor(Color.WHITE);
        mPaint.setStyle(Paint.Style.FILL);

        DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
        mRadius = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 5, displayMetrics);
        mGap = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, displayMetrics);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int width = mDotNum * mRadius * 2 + (mDotNum - 1) * mGap + mPaddingLeft + mPaddingRight;
        int height = mRadius * 2 + mPaddingTop + mPaddingBottom;
        setMeasuredDimension(width, height);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (mDotNum <= 1) {
            return;
        }
        for (int i = 0; i < mDotNum; i++) {
            int cx = mPaddingLeft + mRadius + i * (mGap + mRadius * 2);
            int cy = getHeight() / 2;
            canvas.drawCircle(cx, cy, mRadius, mPaint);
        }
    }

    public void setDotNum(int dotNum) {
        mDotNum = dotNum;
        requestLayout();
    }

    public void setSelectedIndex(int selectedIndex) {
        mSelectedIndex = selectedIndex;
        invalidate();
    }
}

3. 监听ViewPager页面变化

监听ViewPager页面变化的过程如下:

  1. 实现ViewPager.OnPageChangeListener接口;
  2. 在onPageSelected方法中更新指示器。

以下是代码示例:

public class MainActivity extends AppCompatActivity implements ViewPager.OnPageChangeListener {
    private ViewPager mViewPager;
    private DotIndicatorView mDotIndicatorView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mViewPager = (ViewPager) findViewById(R.id.view_pager);
        mDotIndicatorView = (DotIndicatorView) findViewById(R.id.dot_indicator);
        mViewPager.setAdapter(new MyPagerAdapter());
        mViewPager.addOnPageChangeListener(this);
        mDotIndicatorView.setDotNum(3);
    }

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
    }

    @Override
    public void onPageSelected(int position) {
        mDotIndicatorView.setSelectedIndex(position);
    }

    @Override
    public void onPageScrollStateChanged(int state) {
    }

    private class MyPagerAdapter extends PagerAdapter {
        private List<View> mViewList;

        public MyPagerAdapter() {
            mViewList = new ArrayList<>();
            mViewList.add(getLayoutInflater().inflate(R.layout.pager_item_1, null));
            mViewList.add(getLayoutInflater().inflate(R.layout.pager_item_2, null));
            mViewList.add(getLayoutInflater().inflate(R.layout.pager_item_3, null));
        }

        @Override
        public int getCount() {
            return mViewList.size();
        }

        @Override
        public boolean isViewFromObject(View view, Object object) {
            return view == object;
        }

        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            View view = mViewList.get(position);
            container.addView(view);
            return view;
        }

        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            container.removeView(mViewList.get(position));
        }
    }
}

4. 美化指示器

我们可以使用属性动画,对指示器进行渐变、弹簧效果等美化处理。以下是代码示例:

public class DotIndicatorView extends View {
    // ...
    private int mTickness;
    private float mHollowRatio;
    private int mHollowColor;
    private int mSelectedColor;
    private int mDuration;

    private ValueAnimator mAnimator;
    private int mToIndex;
    private int mFromIndex;
    private float mSelectedRatio;

    public DotIndicatorView(Context context) {
        // ...
        mTickness = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2, displayMetrics);
        mHollowRatio = 0.4f;
        mHollowColor = Color.TRANSPARENT;
        mSelectedColor = Color.WHITE;
        mDuration = 300;

        mAnimator = ValueAnimator.ofFloat(0f, 1f);
        mAnimator.setInterpolator(new OverShootInterpolator());
        mAnimator.setDuration(mDuration);
        mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mSelectedRatio = (float) animation.getAnimatedValue();
                invalidate();
            }
        });
    }

    private void drawDot(Canvas canvas, int cx, int cy, int radius, Paint paint) {
        canvas.drawCircle(cx, cy, radius - mTickness / 2, paint);
        canvas.drawCircle(cx, cy, radius * (1 - mHollowRatio) + mTickness / 2, mPaint);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (mDotNum <= 1) {
            return;
        }
        for (int i = 0; i < mDotNum; i++) {
            int cx = mPaddingLeft + mRadius + i * (mGap + mRadius * 2);
            int cy = getHeight() / 2;

            if (i == mSelectedIndex) {
                int fromRadius = mRadius;
                int toRadius = (int) (mRadius * (1 + mHollowRatio));
                int radius = (int) (fromRadius + (toRadius - fromRadius) * mSelectedRatio);
                mPaint.setColor(mSelectedColor);
                drawDot(canvas, cx, cy, radius, mPaint);
            } else {
                mPaint.setColor(mHollowColor);
                drawDot(canvas, cx, cy, mRadius, mPaint);
            }
        }
    }

    public void setSelectedIndex(int selectedIndex, boolean isAnimate) {
        if (isAnimate) {
            if (mAnimator.isRunning()) {
                mAnimator.cancel();
            }
            mFromIndex = mSelectedIndex;
            mToIndex = selectedIndex;
            mAnimator.start();
        } else {
            mSelectedRatio = 1f;
            mSelectedIndex = selectedIndex;
            invalidate();
        }
    }
}

以上就是自定义炫酷的ViewPage指示器的完整攻略,希望可以帮助到你。如果有需要,也可以将以上代码片段按需整合到项目中,让自己的指示器更炫酷。

至于示例可以关注这个链接:https://github.com/max299792458/indicator 里面展示了两个指示器的示例代码

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Android自定义超级炫酷的ViewPage指示器 - Python技术站

(0)
上一篇 2023年6月25日
下一篇 2023年6月25日

相关文章

  • c++字符串string拼接

    以下是关于“C++字符串string拼接”的完整攻略,包含两个示例说明。 C++字符串string拼接 在C++中,我们可以使用string类表示字符串,并使用+运算符来拼接字符串。在本攻略中,我们将介绍如何使用string类来拼接字符串。 1. 使用+运算符拼接字符串 在C++中,我们可以使用+运算符来拼接两个字符串。以下是一个示例: #include &…

    other 2023年5月9日
    00
  • 无畏契约弹VAN9003错误怎么办 瓦罗兰特VAN9003错误解决方法

    无畏契约弹VAN9003错误怎么办? 如果你在玩《无畏契约》游戏时,遇到 VAN9003 错误并不是什么罕见的问题。这个错误通常会显示为“无法连接到服务器”的提示,并且会阻止你进入游戏。这个错误的原因可能有很多,可能是由于网络问题,也可能是游戏客户端或服务器问题导致的。接下来,我们将为大家介绍一些可能的解决方法。 解决方法一:检查网络连接 由于 VAN900…

    other 2023年6月27日
    00
  • SpringBatch从入门到精通之StepScope作用域和用法详解

    当然!下面是关于\”Spring Batch从入门到精通之StepScope作用域和用法详解\”的完整攻略,包含两个示例说明。 … … … 示例1:使用StepScope作用域的Bean @Component @StepScope public class MyTasklet implements Tasklet { private final …

    other 2023年8月20日
    00
  • MySql通过ip地址进行访问的方法

    MySql通过IP地址进行访问的方法攻略 要通过IP地址访问MySQL数据库,需要进行以下步骤: 步骤一:配置MySQL服务器 打开MySQL服务器的配置文件。在Linux系统中,配置文件通常位于/etc/mysql/mysql.conf.d/mysqld.cnf,而在Windows系统中,通常位于C:\\Program Files\\MySQL\\MySQ…

    other 2023年7月30日
    00
  • windows常用网络命令使用脚本分享

    下面是详细讲解“Windows常用网络命令使用脚本分享”的完整攻略。 Windows常用网络命令使用脚本分享 什么是网络命令 网络命令是指在Windows操作系统中用于网络通信和管理的一系列命令行工具。使用网络命令可以实现网络的连接、诊断、管理等功能。 常用网络命令 下面是常用的几个网络命令: ipconfig ipconfig命令用于查看和配置网络适配器的…

    other 2023年6月26日
    00
  • [转载]什么情况下应该设置cudnn.benchmark=true?

    [转载]什么情况下应该设置cudnn.benchmark=true? 在深度学习中,使用GPU进行加速训练已经变得越来越普遍。但在使用GPU训练时,我们常常会遇到优化的问题,其中之一就是cudnn库的使用,而cudnn.benchmark的设置就成了解决该问题的一种重要方法。那么什么情况下应该设置cudnn.benchmark=true呢?让我们来探究一下。…

    其他 2023年3月28日
    00
  • tensorflow如何提高gpu训练效率和利用率

    TensorFlow如何提高GPU训练效率和利用率 TensorFlow是目前最流行的深度学习框架之一,其具有高效的自动微分计算和强大的GPU加速能力。然而,在实际的深度学习训练过程中,GPU的利用率和训练效率往往成为瓶颈。本文将介绍一些TensorFlow提高GPU训练效率和利用率的技巧和方法。 1. 使用数据增强 在深度学习训练中,数据增强是提高模型泛化…

    其他 2023年3月29日
    00
  • 深入apache配置文件httpd.conf的部分参数说明

    当我们需要自定义Apache Web服务器时,就需要深入了解Apache的配置文件httpd.conf。下面是一些常用的重要httpd.conf参数的详细说明: 1. Listen 表示Apache监听的IP地址、端口号。格式为:Listen IP:Port 示例:只监听本地IP地址127.0.0.1,端口号为8080 Listen 127.0.0.1:80…

    other 2023年6月25日
    00
合作推广
合作推广
分享本页
返回顶部