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日

相关文章

  • ASP、PHP与javascript根据时段自动切换CSS皮肤的代码

    实现网站根据时段自动切换CSS皮肤的代码需要用到服务器端的脚本语言,如ASP、PHP等,以及客户端的脚本语言JavaScript。下面是具体的实现流程: 创建多个CSS皮肤 要实现时段自动切换CSS皮肤,首先需要创建多个CSS皮肤。可以根据自己的需求和设计风格,创建不同的CSS文件,例如“皮肤1.css”、“皮肤2.css”等。 创建切换皮肤的脚本 在网站中…

    other 2023年6月27日
    00
  • 像素 分辨率 ppi(像素密度) bpp扫盲

    像素 分辨率 ppi(像素密度) bpp扫盲 什么是像素? 像素(Pixel)是图像图形处理中最小的显示单位。像素可以是数字或者光学系统中的单个光点。在数字图像处理中,像素是计算机中显示图像的基本单位,在显示器或打印机中,一个像素被视为一个独立的圆点。 什么是分辨率? 分辨率(Resolution)是指显示器或打印机中的像素数目。通常,分辨率以水平像素数×垂…

    其他 2023年3月29日
    00
  • Flutter 中如何优雅的实现多渠道打包(埋点统计系列)

    Flutter 中如何优雅的实现多渠道打包(埋点统计系列) 本文将为您详细讲解如何在Flutter中优雅地实现多渠道打包,包括环境搭建、配置文件修改、打包命令和示例说明等步骤。 环境搭建 在开始实现多渠道打包之前,需要先在Flutter项目中添加flutter_channel插件。可以按照以下步骤进行操作: 在pubspec.yaml文件中添加flutter…

    other 2023年5月6日
    00
  • ThinkPad R480值得买吗?ThinkPad R480商务本性价比全面评测

    ThinkPad R480商务本性价比全面评测攻略 1. 产品概述 ThinkPad R480是联想旗下的商务本系列产品,以其稳定可靠的性能和出色的性价比而备受关注。本攻略将对ThinkPad R480的各项特点进行详细评测,以帮助您判断其是否值得购买。 2. 外观设计 ThinkPad R480采用经典的ThinkPad设计风格,外壳采用高强度材料制成,具…

    other 2023年10月17日
    00
  • Android实现视频的画中画功能

    Android实现视频的画中画功能攻略 1. 添加画中画权限 首先,在AndroidManifest.xml文件中添加画中画权限: <uses-permission android:name=\"android.permission.SYSTEM_ALERT_WINDOW\" /> 2. 创建画中画窗口 在需要使用画中画功能的…

    other 2023年8月23日
    00
  • vueselectchange事件

    以下是关于Vue中的v-select组件的vueselectchange事件的完整攻略: v-select组件简介 v-select是Vue.js中的一个组件,它提供了一个下拉列表框,用户可以从中选择一个或多个选项。v-select组件支持多种选项,包括搜索、分组、异步加载等。 vueselectchange事件 vueselectchange事件是v-se…

    other 2023年5月6日
    00
  • poi解析excel内容

    以下是关于“POI解析Excel内容”的完整攻略: 步骤1:准备数据 首先,需要准备要解析的Excel文件。可以使用Java的POI库来读取和解析文件。在本攻略中,我们将使用一个名为example.xlsx的Excel文件作为示例。 步骤2:使用POI库解析Excel内容 接下来,需要使用POI库来解析Excel内容。可以使用Workbook、Sheet和R…

    other 2023年5月7日
    00
  • Java Set集合及其子类HashSet与LinkedHashSet详解

    Java Set集合及其子类HashSet与LinkedHashSet详解 Java中的Set是一种集合类,它不能包含重复元素。Java的Set集合有两个主要的实现类:HashSet和LinkedHashSet。 HashSet HashSet是基于哈希表实现的Set集合。当我们向HashSet中添加元素时,HashSet首先使用元素的hashCode生成对…

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