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

yizhihongxing

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

标题: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日

相关文章

  • linuxalias理解及设置

    Linux Alias 理解及设置 什么是Alias 在Linux系统中,Alias(别名)指的是一个命令或者一组命令的替代方式。当你输入一个指定的别名时,实际上执行的是与别名相关联的命令列表。 为什么要使用Alias 通过使用Alias,我们可以简化系统命令的书写和容易记忆的方式来唤出一组复杂的操作,从而达到提高工作效率和简化工作流程的目的。 如何设置Al…

    其他 2023年3月28日
    00
  • Mybatis中的延迟加载案例解析

    Mybatis中的延迟加载案例解析 Mybatis是一款优秀的基于Java的持久层框架,采用了ORM(对象关系映射)思想,可以将Java对象和数据库表中的数据进行映射。Mybatis中的延迟加载功能非常实用,可以大幅提升系统的性能和响应速度。下面我们来详细讲解Mybatis中的延迟加载案例解析。 延迟加载的概念 延迟加载是指在需要实际使用对象时再进行加载和初…

    other 2023年6月25日
    00
  • 基于Android的服务器端程序实例

    基于Android的服务器端程序实例攻略 前置知识 Java语言基础 Android开发基础 网络编程基础 概述 本攻略主要介绍如何基于Android平台开发一个服务器端程序。我们将使用Java语言和Android开发工具进行开发,常用的网络编程库OkHttp将被用来作为网络请求的框架。在本攻略中,我们将主要从以下几个方面进行讲解: 服务器端程序架构设计 安…

    other 2023年6月27日
    00
  • nginx 代理后出现503的解决方法

    下面我将为您提供“nginx 代理后出现503的解决方法”的完整攻略,具体内容如下: 问题描述 在使用 nginx 进行代理时,有时会出现状态码为503的错误,这时候意味着 nginx 在收到请求后无法将其转发给目标服务器进行处理。那么出现这种情况该如何解决呢?下面提供两种解决方法。 解决方法一:增加代理缓存 nginx 自带了一个代理缓存功能,可以在一定程…

    other 2023年6月27日
    00
  • Nginx+php配置文件及原理解析

    Nginx是一个轻量级的web服务器软件,而PHP是一种流行的Web编程语言,使用Nginx服务器来处理PHP应用程序可以提高Web应用程序的性能和并发性能。本文将详细介绍如何通过Nginx服务器和php配置文件来配置和运行PHP应用程序。具体内容如下: 准备工作 在开始之前,请确保已经安装了Nginx和PHP。如果没有,请执行以下步骤进行安装: # 安装N…

    other 2023年6月25日
    00
  • 如何添加一种新Case协议

    如何添加一种新Case协议 在实施测试计划时,Case是一个重要概念, 每个测试用例都是按照同样的基准来运行的。在模拟测试前,需要习惯性地评估当前的Case库并添加所需的新Case。本文将介绍如何添加一种新的Case协议。 步骤一:理解Case的基本概念 在添加新Case之前,需要了解Case的基本概念和其他元素的描述,然后再考虑如何添加新的协议以满足特定的…

    其他 2023年3月28日
    00
  • C++虚函数表的原理与使用解析

    C++虚函数表的原理与使用解析 简介 在C++的类继承中,为了实现多态,我们常常会使用虚函数。虚函数与虚函数表有着密切的关系,在本文中,我们将深入探讨C++虚函数表的原理和使用。 虚函数的概念 虚函数是在C++中用于实现多态的重要机制。通过在基类中声明虚函数,在子类中覆盖该虚函数,可以在运行时根据对象的实际类型来调用相应的函数实现,从而实现多态。 虚函数的声…

    other 2023年6月26日
    00
  • 记一次Docker生产环境搭建的方法

    记一次Docker生产环境搭建的方法 什么是Docker? Docker是一个开源的应用程序容器引擎,可以轻松地在各种操作系统上创建、部署和运行应用程序。与传统的虚拟机不同,Docker容器不需要完整的操作系统,因此启动时间和资源消耗都很少。 Docker环境搭建 在一台服务器上搭建Docker生产环境,需要以下步骤: 安装Docker引擎 安装Docker…

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