本文主要是介绍android 循环轮播控件com.youth.banner 的自定义轮播指示器,满足开发需求。,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
1:轮播com.youth.banner
轮播图控件com.youth.banner,github地址:https://github.com/youth5201314/banner。
具体使用请看github,简单方便,咱们主要介绍如何自定义指示器。
2:自定义指示器
1:自定义属性
在values.xml添加属性
<declare-styleable name="ViewPagerIndicator"><attr format="color|reference" name="sbl_selected_color"/><attr format="color|reference" name="sbl_default_color"/><attr format="dimension|reference" name="sbl_radius"/><attr format="dimension|reference" name="sbl_radius_selected"/><attr format="dimension|reference" name="sbl_length"/><attr format="dimension|reference" name="sbl_distance"/><attr format="integer" name="sbl_num"/><attr name="sbl_indicatorType"><enum name="LINE" value="0"/><enum name="CIRCLE" value="1"/><enum name="CIRCLE_LINE" value="2"/><enum name="BEZIER" value="3"/><enum name="SPRING" value="4"/><enum name="PROGRESS" value="5"/></attr><attr name="sbl_distanceType"><enum name="BY_RADIUS" value="0"/><enum name="BY_DISTANCE" value="1"/><enum name="BY_LAYOUT" value="2"/></attr><attr format="boolean" name="sbl_animation"/>
</declare-styleable>
2:自定义view
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;import androidx.viewpager.widget.ViewPager;
import androidx.viewpager2.widget.ViewPager2;import com.sbl.hwscankitdemo.R;/*** 自定义轮播*/
public class MyViewPagerIndicator extends View {private Path mPath;private Paint paintFill;private Paint paintStroke;private int mNum;//个数private float mRadius;//半径private float mRadiusSelected;//选中半径,默认为mRadiusprivate float mLength;//线长private float mHeight;//线宽private float mOffset;//偏移量private int mSelected_color;//选中颜色private int mDefault_color;//默认颜色private int mIndicatorType;//点类型private int mDistanceType;//距离类型private float mDistance;//间隔距离private int mPosition;//第几张/*** 一个常量,用来计算绘制圆形贝塞尔曲线控制点的位置*/private static final float M = 0.551915024494f;private float mPercent;private boolean mIsLeft;private boolean mIsInfiniteCircle;//无限循环private boolean mAnimation;public MyViewPagerIndicator(Context context, AttributeSet attrs) {super(context, attrs);setStyleable(context, attrs);initPaint();}/*** xml 参数设置 选中颜色 默认颜色 点大小 长度 距离 距离类型 类型 真实个数(轮播)** @param context* @param attrs*/private void setStyleable(Context context, AttributeSet attrs) {TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.ViewPagerIndicator);mSelected_color = array.getColor(R.styleable.ViewPagerIndicator_sbl_selected_color, 0xffffffff);mDefault_color = array.getColor(R.styleable.ViewPagerIndicator_sbl_default_color, 0xffcdcdcd);mRadius = array.getDimension(R.styleable.ViewPagerIndicator_sbl_radius, 20);//pxmRadiusSelected = array.getDimension(R.styleable.ViewPagerIndicator_sbl_radius_selected, mRadius);//pxmLength = array.getDimension(R.styleable.ViewPagerIndicator_sbl_length, 2 * mRadius);//pxmDistance = array.getDimension(R.styleable.ViewPagerIndicator_sbl_distance, 3 * mRadius);//pxmDistanceType = array.getInteger(R.styleable.ViewPagerIndicator_sbl_distanceType, MyViewPagerIndicator.DistanceType.BY_RADIUS);mIndicatorType = array.getInteger(R.styleable.ViewPagerIndicator_sbl_indicatorType, MyViewPagerIndicator.IndicatorType.CIRCLE);mNum = array.getInteger(R.styleable.ViewPagerIndicator_sbl_num, 0);mAnimation = array.getBoolean(R.styleable.ViewPagerIndicator_sbl_animation, true);array.recycle();switch (mIndicatorType) {case MyViewPagerIndicator.IndicatorType.BEZIER:mControlPoint = new MyViewPagerIndicator.Point[]{new MyViewPagerIndicator.Point(), new MyViewPagerIndicator.Point(), new MyViewPagerIndicator.Point(), new MyViewPagerIndicator.Point(), new MyViewPagerIndicator.Point(), new MyViewPagerIndicator.Point(),new MyViewPagerIndicator.Point(), new MyViewPagerIndicator.Point(), new MyViewPagerIndicator.Point(), new MyViewPagerIndicator.Point(), new MyViewPagerIndicator.Point(), new MyViewPagerIndicator.Point()};break;case MyViewPagerIndicator.IndicatorType.SPRING:mSpringPoint = new MyViewPagerIndicator.Point[]{new MyViewPagerIndicator.Point(), new MyViewPagerIndicator.Point(), new MyViewPagerIndicator.Point(), new MyViewPagerIndicator.Point(), new MyViewPagerIndicator.Point(), new MyViewPagerIndicator.Point()};break;}invalidate();}/*** 初始化画笔*/private void initPaint() {paintStroke = new Paint();paintFill = new Paint();mPath = new Path();//实心paintFill.setStyle(Paint.Style.FILL_AND_STROKE);paintFill.setColor(mSelected_color);paintFill.setAntiAlias(true);paintFill.setStrokeWidth(3);//空心paintStroke.setStyle(Paint.Style.FILL);paintStroke.setColor(mDefault_color);paintStroke.setAntiAlias(true);paintStroke.setStrokeWidth(3);}/*** 绘制 invalidate()后 执行** @param canvas*/@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);if ((mNum <= 0)) {return;}int width = canvas.getWidth();int height = canvas.getHeight();canvas.translate(width / 2, height / 2);//初始化画笔initPaint();//距离switch (mDistanceType) {case MyViewPagerIndicator.DistanceType.BY_DISTANCE:break;case MyViewPagerIndicator.DistanceType.BY_RADIUS://圆心到 3倍半径 只有一个半径mDistance = 3 * mRadius;break;case MyViewPagerIndicator.DistanceType.BY_LAYOUT://布局等分if (mIndicatorType == MyViewPagerIndicator.IndicatorType.CIRCLE_LINE) {mDistance = width / (mNum + 1);} else {mDistance = width / mNum;}break;}switch (mIndicatorType) {case MyViewPagerIndicator.IndicatorType.CIRCLE://圆for (int i = 0; i < mNum; i++) {//默认点 -(mNum - 1) * 0.5f * mDistance 第一个点canvas.drawCircle(-(mNum - 1) * 0.5f * mDistance + i * mDistance, 0, mRadius, paintStroke);}//选中canvas.drawCircle(-(mNum - 1) * 0.5f * mDistance + mOffset, 0, mRadiusSelected, paintFill);break;case MyViewPagerIndicator.IndicatorType.LINE://线paintStroke.setStrokeWidth(mRadius);float startX = -(mNum - 1) * 0.5f * mDistance - mLength / 2;float stopX = -(mNum - 1) * 0.5f * mDistance + mLength / 2;//默认for (int i = 0; i < mNum; i++) {canvas.drawLine(startX + i * mDistance, 0, stopX + i * mDistance, 0, paintStroke);}//选中paintFill.setStrokeWidth(mRadius);float startF = -(mNum - 1) * 0.5f * mDistance - mLength / 2 + mOffset;float stopF = -(mNum - 1) * 0.5f * mDistance + mLength / 2 + mOffset;canvas.drawLine(startF, 0, stopF, 0, paintFill);break;case MyViewPagerIndicator.IndicatorType.CIRCLE_LINE://圆线if (mPosition == mNum - 1) {//最后一个 右滑//第一个 线 选中 消失float leftClose = -(mNum) * 0.5f * mDistance - mRadius;float rightClose = leftClose + 2 * mRadius + mOffset;float topClose = -mRadius;float bottomClose = mRadius;RectF rectClose = new RectF(leftClose, topClose, rightClose, bottomClose);// 设置个新的长方形canvas.drawRoundRect(rectClose, mRadius, mRadius, paintStroke);//最后一个 线 显示float rightOpen = -(mNum) * 0.5f * mDistance + mNum * mDistance + mRadius;float leftOpen = rightOpen - 2 * mRadius - mDistance + mOffset;float topOpen = -mRadius;float bottomOpen = mRadius;RectF rectOpen = new RectF(leftOpen, topOpen, rightOpen, bottomOpen);// 设置个新的长方形canvas.drawRoundRect(rectOpen, mRadius, mRadius, paintStroke);//圆for (int i = 1; i < mNum; i++) {canvas.drawCircle(rightClose - mRadius + i * mDistance, 0, mRadius, paintStroke);}} else {//第一个 线 选中 消失float leftClose = -(mNum) * 0.5f * mDistance + mPosition * mDistance - mRadius;float rightClose = leftClose + 2 * mRadius + mDistance - mOffset;float topClose = -mRadius;float bottomClose = mRadius;RectF rectClose = new RectF(leftClose, topClose, rightClose, bottomClose);// 设置个新的长方形canvas.drawRoundRect(rectClose, mRadius, mRadius, paintStroke);//第二个 线 显示if (mPosition < mNum - 1) {float rightOpen = -(mNum) * 0.5f * mDistance + (mPosition + 2) * mDistance + mRadius;float leftOpen = rightOpen - 2 * mRadius - mOffset;float topOpen = -mRadius;float bottomOpen = mRadius;RectF rectOpen = new RectF(leftOpen, topOpen, rightOpen, bottomOpen);// 设置个新的长方形canvas.drawRoundRect(rectOpen, mRadius, mRadius, paintStroke);}//圆for (int i = mPosition + 3; i <= mNum; i++) {canvas.drawCircle(-(mNum) * 0.5f * mDistance + i * mDistance, 0, mRadius, paintStroke);}for (int i = mPosition - 1; i >= 0; i--) {canvas.drawCircle(-(mNum) * 0.5f * mDistance + i * mDistance, 0, mRadius, paintStroke);}}break;case MyViewPagerIndicator.IndicatorType.BEZIER://贝塞尔for (int i = 0; i < mNum; i++) {//默认点 -(mNum - 1) * 0.5f * mDistance 第一个点canvas.drawCircle(-(mNum - 1) * 0.5f * mDistance + i * mDistance, 0, mRadius, paintStroke);}//选中drawCubicBezier(canvas);break;case MyViewPagerIndicator.IndicatorType.SPRING://贝塞尔 弹性for (int i = 0; i < mNum; i++) {//默认点 -(mNum - 1) * 0.5f * mDistance 第一个点canvas.drawCircle(-(mNum - 1) * 0.5f * mDistance + i * mDistance, 0, mRadius, paintStroke);}drawSpringBezier(canvas);break;case MyViewPagerIndicator.IndicatorType.PROGRESS://进度条for (int i = 0; i < mNum; i++) {//默认点 -(mNum - 1) * 0.5f * mDistance 第一个点canvas.drawCircle(-(mNum - 1) * 0.5f * mDistance + i * mDistance, 0, mRadius, paintStroke);}//选中float rightOpen = -(mNum - 1) * 0.5f * mDistance + mOffset + mRadius;float leftOpen = -(mNum - 1) * 0.5f * mDistance - mRadius;float topOpen = -mRadius;float bottomOpen = mRadius;RectF rectOpen = new RectF(leftOpen, topOpen, rightOpen, bottomOpen);// 设置个新的长方形canvas.drawRoundRect(rectOpen, mRadius, mRadius, paintFill);break;}}private MyViewPagerIndicator.Point[] mSpringPoint = new MyViewPagerIndicator.Point[6];/*** 绘制弹性** @param canvas*/private void drawSpringBezier(Canvas canvas) {//右圆圆心float right_circle_x;//右圆半径float right_circle_radius;//左圆圆心float left_circle_x;//左圆半径float left_circle_radius;//最大半径float max_radius = mRadius;//最小半径float min_radius = mRadius / 2;//控制点if (mPosition == mNum - 1 && !mIsLeft) {//第一个 右滑 0---4if (mPercent <= 0.5) {right_circle_x = -(mNum - 1) * 0.5f * mDistance + (mNum - 1) * mDistance;left_circle_x = -(mNum - 1) * 0.5f * mDistance + (0.5f - mPercent) / 0.5f * (mNum - 1) * mDistance;right_circle_radius = min_radius + (max_radius - min_radius) * (0.5f - mPercent) / 0.5f;} else {right_circle_x = -(mNum - 1) * 0.5f * mDistance + (1f - mPercent) / 0.5f * (mNum - 1) * mDistance;left_circle_x = -(mNum - 1) * 0.5f * mDistance;right_circle_radius = min_radius;}left_circle_radius = mRadius * (mPercent);} else if (mPosition == mNum - 1 && mIsLeft) {//最后一个 左滑 4--0//0-1if (mPercent >= 0.5) {//左亭left_circle_radius = min_radius + (max_radius - min_radius) * (-0.5f + mPercent) / 0.5f;left_circle_x = -(mNum - 1) * 0.5f * mDistance;right_circle_x = -(mNum - 1) * 0.5f * mDistance + (1 - mPercent) / 0.5f * (mNum - 1) * mDistance;} else {//左动left_circle_radius = min_radius;left_circle_x = -(mNum - 1) * 0.5f * mDistance + (0.5f - mPercent) / 0.5f * (mNum - 1) * mDistance;right_circle_x = -(mNum - 1) * 0.5f * mDistance + (mNum - 1) * mDistance;}right_circle_radius = mRadius * (1 - mPercent);} else if (mIsLeft) {//中间的 左滑mOffset = (mPercent + mPosition) * mDistance;if (mPercent >= 0.5) {left_circle_x = -(mNum - 1) * 0.5f * mDistance + ((mPercent - 0.5f) / 0.5f + mPosition) * mDistance;right_circle_x = -(mNum - 1) * 0.5f * mDistance + (1 + mPosition) * mDistance;right_circle_radius = min_radius + (max_radius - min_radius) * (mPercent - 0.5f) / 0.5f;} else {right_circle_x = -(mNum - 1) * 0.5f * mDistance + ((mPercent) / 0.5f + mPosition) * mDistance;left_circle_x = -(mNum - 1) * 0.5f * mDistance + mPosition * mDistance;right_circle_radius = min_radius;}left_circle_radius = mRadius * (1 - mPercent);} else {//右滑mOffset = (mPercent + mPosition) * mDistance;if (mPercent <= 0.5) {left_circle_x = -(mNum - 1) * 0.5f * mDistance + (mPosition) * mDistance;right_circle_x = -(mNum - 1) * 0.5f * mDistance + ((mPercent) / 0.5f + mPosition) * mDistance;left_circle_radius = min_radius + (max_radius - min_radius) * (0.5f - mPercent) / 0.5f;} else {left_circle_x = -(mNum - 1) * 0.5f * mDistance + ((mPercent - 0.5f) / 0.5f + mPosition) * mDistance;right_circle_x = -(mNum - 1) * 0.5f * mDistance + (mPosition + 1) * mDistance;left_circle_radius = min_radius;}right_circle_radius = mRadius * (mPercent);}//右圆canvas.drawCircle(right_circle_x, 0, right_circle_radius, paintFill);//左圆canvas.drawCircle(left_circle_x, 0, left_circle_radius, paintFill);//贝塞尔//控制点mSpringPoint[0].x = left_circle_x;mSpringPoint[0].y = -left_circle_radius;mSpringPoint[5].x = mSpringPoint[0].x;mSpringPoint[5].y = left_circle_radius;//mSpringPoint[1].x = (left_circle_x + right_circle_x) / 2;mSpringPoint[1].y = -left_circle_radius / 2;mSpringPoint[4].x = mSpringPoint[1].x;mSpringPoint[4].y = left_circle_radius / 2;//mSpringPoint[2].x = right_circle_x;mSpringPoint[2].y = -right_circle_radius;mSpringPoint[3].x = mSpringPoint[2].x;mSpringPoint[3].y = right_circle_radius;mPath.reset();mPath.moveTo(mSpringPoint[0].x, mSpringPoint[0].y);mPath.quadTo(mSpringPoint[1].x, mSpringPoint[1].y, mSpringPoint[2].x, mSpringPoint[2].y);mPath.lineTo(mSpringPoint[3].x, mSpringPoint[3].y);mPath.quadTo(mSpringPoint[4].x, mSpringPoint[4].y, mSpringPoint[5].x, mSpringPoint[5].y);canvas.drawPath(mPath, paintFill);}/*** 绘制贝塞尔曲线** @param canvas*/private void drawCubicBezier(Canvas canvas) {//更换控制点changePoint();/** 清除Path中的内容reset不保留内部数据结构,但会保留FillType.rewind会保留内部的数据结构,但不保留FillType */mPath.reset();//0mPath.moveTo(mControlPoint[0].x, mControlPoint[0].y);//0-3mPath.cubicTo(mControlPoint[1].x, mControlPoint[1].y, mControlPoint[2].x, mControlPoint[2].y, mControlPoint[3].x, mControlPoint[3].y);//3-6mPath.cubicTo(mControlPoint[4].x, mControlPoint[4].y, mControlPoint[5].x, mControlPoint[5].y, mControlPoint[6].x, mControlPoint[6].y);//6-9mPath.cubicTo(mControlPoint[7].x, mControlPoint[7].y, mControlPoint[8].x, mControlPoint[8].y, mControlPoint[9].x, mControlPoint[9].y);//9-0mPath.cubicTo(mControlPoint[10].x, mControlPoint[10].y, mControlPoint[11].x, mControlPoint[11].y, mControlPoint[0].x, mControlPoint[0].y);canvas.drawPath(mPath, paintFill);}/*** 控制点*/private void changePoint() {mCenterPoint.y = 0;float mc = M;mControlPoint[2].y = mRadius;//底部mControlPoint[8].y = -mRadius;//顶部//圆心位置if (mPosition == mNum - 1 && !mIsLeft) {//第一个 右滑 0-->4if (mPercent <= 0.2) { //回弹 圆心到达mCenterPoint.x = -(mNum - 1) * 0.5f * mDistance + (mNum - 1) * mDistance;//最后一个} else if (mPercent <= 0.8) {//加速 左凸起 扁平化M 最右端固定不变 圆心移动mCenterPoint.x = -(mNum - 1) * 0.5f * mDistance + (1 - (mPercent - 0.2f) / 0.6f) * (mNum - 1) * mDistance;} else if (mPercent > 0.8 && mPercent < 1) {//mCenterPoint.x = -(mNum - 1) * 0.5f * mDistance;//第一个} else if (mPercent == 1) {//圆mCenterPoint.x = -(mNum - 1) * 0.5f * mDistance;}//控制点位置if (mPercent > 0.8 && mPercent <= 1) {//右凸起 圆心不变mControlPoint[5].x = mCenterPoint.x + mRadius * (2 - (mPercent - 0.8f) / 0.2f);//右半圆mControlPoint[0].x = mCenterPoint.x - mRadius;//左半圆} else if (mPercent > 0.5 && mPercent <= 0.8) {//加速 左凸起 扁平化M 最右端固定不变 圆心移动mControlPoint[5].x = mCenterPoint.x + 2 * mRadius;//右半圆mControlPoint[0].x = mCenterPoint.x - mRadius * (1 + (0.8f - mPercent) / 0.3f);//左半圆mControlPoint[2].y = mRadius * (1 + (mPercent - 0.8f) / 0.3f * 0.1f);//底部mControlPoint[8].y = -mRadius * (1 + (mPercent - 0.8f) / 0.3f * 0.1f);//顶部mc = mc * (1 + (-mPercent + 0.8f) / 0.3f * 0.3f);} else if (mPercent > 0.2 && mPercent <= 0.5) {//左右恢复 变圆M逐渐重置为原来大小 圆心移动mControlPoint[5].x = mCenterPoint.x + mRadius * (1 + (mPercent - 0.2f) / 0.3f);//右半圆mControlPoint[0].x = mCenterPoint.x - mRadius * (1 + (mPercent - 0.2f) / 0.3f);//左半圆mControlPoint[2].y = mRadius * (1 - (mPercent - 0.2f) / 0.3f * 0.1f);//底部mControlPoint[8].y = -mRadius * (1 - (mPercent - 0.2f) / 0.3f * 0.1f);//顶部mc = mc * (1 + (mPercent - 0.2f) / 0.3f * 0.3f);} else if (mPercent > 0.1 && mPercent <= 0.2) {//左凹 圆心到达.0mControlPoint[5].x = mCenterPoint.x + mRadius;//右半圆mControlPoint[0].x = mCenterPoint.x - mRadius * (1 - (0.2f - mPercent) / 0.1f * 0.5f);//左半圆} else if (mPercent >= 0 && mPercent <= 0.1) {//回弹 圆心到达mControlPoint[5].x = mCenterPoint.x + mRadius;//右半圆mControlPoint[0].x = mCenterPoint.x - mRadius * (1 - (mPercent) / 0.1f * 0.5f);//左半圆}} else if (mPosition == mNum - 1 && mIsLeft) {//最后一个 左滑 4-->0if (mPercent <= 0.2) {//圆mCenterPoint.x = -(mNum - 1) * 0.5f * mDistance + (mNum - 1) * mDistance;} else if (mPercent <= 0.8) {//加速 左凸起 扁平化M 最右端固定不变 圆心移动mCenterPoint.x = -(mNum - 1) * 0.5f * mDistance + (1 - (mPercent - 0.2f) / 0.6f) * (mNum - 1) * mDistance;} else if (mPercent > 0.8 && mPercent < 1) {//回弹 圆心到达mCenterPoint.x = -(mNum - 1) * 0.5f * mDistance;//第一个} else if (mPercent == 1) {//圆mCenterPoint.x = -(mNum - 1) * 0.5f * mDistance + mPosition * mDistance;}if (mPercent <= 0) {//圆} else if (mPercent <= 0.2 && mPercent >= 0) {//左凸起 圆心不变mControlPoint[5].x = mCenterPoint.x + mRadius;//右半圆mControlPoint[0].x = mCenterPoint.x - mRadius * (1 + (mPercent) / 0.2f);//左半圆} else if (mPercent > 0.2 && mPercent <= 0.5) {//加速 右凸起 扁平化M 最左端固定不变 圆心移动mControlPoint[5].x = mCenterPoint.x + mRadius * (1 + (mPercent - 0.2f) / 0.3f);//右半圆mControlPoint[0].x = mCenterPoint.x - 2 * mRadius;//左半圆mControlPoint[2].y = mRadius * (1 - (mPercent - 0.2f) / 0.3f * 0.1f);//底部mControlPoint[8].y = -mRadius * (1 - (mPercent - 0.2f) / 0.3f * 0.1f);//顶部mc = mc * (1 + (mPercent - 0.2f) / 0.3f * 0.3f);} else if (mPercent > 0.5 && mPercent <= 0.8) {//左右恢复 变圆M逐渐重置为原来大小 圆心移动mControlPoint[5].x = mCenterPoint.x + mRadius * (1 + (0.8f - mPercent) / 0.3f);//右半圆mControlPoint[0].x = mCenterPoint.x - mRadius * (1 + (0.8f - mPercent) / 0.3f);//左半圆mControlPoint[2].y = mRadius * (1 + (mPercent - 0.8f) / 0.3f * 0.1f);//底部mControlPoint[8].y = -mRadius * (1 + (mPercent - 0.8f) / 0.3f * 0.1f);//顶部mc = mc * (1 + (0.8f - mPercent) / 0.3f * 0.3f);} else if (mPercent > 0.8 && mPercent <= 0.9) {//右凹 圆心到达mControlPoint[5].x = mCenterPoint.x + mRadius * (1 - (mPercent - 0.8f) / 0.1f * 0.5f);//右半圆mControlPoint[0].x = mCenterPoint.x - mRadius;//左半圆} else if (mPercent > 0.9 && mPercent <= 1) {//回弹 圆心到达mControlPoint[5].x = mCenterPoint.x + mRadius * (1 - (mPercent - 0.9f) / 0.1f * 0.5f);//右半圆mControlPoint[0].x = mCenterPoint.x - mRadius;//左半圆}} else {if (mPercent <= 0.2) {//圆mCenterPoint.x = -(mNum - 1) * 0.5f * mDistance + mPosition * mDistance;} else if (mPercent <= 0.8) {//加速 左凸起 扁平化M 最右端固定不变 圆心移动mCenterPoint.x = -(mNum - 1) * 0.5f * mDistance + (mPosition + mPercent) * mDistance;mCenterPoint.x = -(mNum - 1) * 0.5f * mDistance + (mPosition + (mPercent - 0.2f) / 0.6f) * mDistance;} else if (mPercent > 0.8 && mPercent < 1) {//回弹 圆心到达mCenterPoint.x = -(mNum - 1) * 0.5f * mDistance + (mPosition + 1) * mDistance;} else if (mPercent == 1) {//圆mCenterPoint.x = -(mNum - 1) * 0.5f * mDistance + mPosition * mDistance;}//控制点位置if (mIsLeft)//左滑{if (mPercent >= 0 && mPercent <= 0.2) {//右凸起 圆心不变mControlPoint[5].x = mCenterPoint.x + mRadius * (2 - (0.2f - mPercent) / 0.2f);//右半圆mControlPoint[0].x = mCenterPoint.x - mRadius;//左半圆} else if (mPercent > 0.2 && mPercent <= 0.5) {//加速 左凸起 扁平化M 最右端固定不变 圆心移动mControlPoint[5].x = mCenterPoint.x + 2 * mRadius;//右半圆mControlPoint[0].x = mCenterPoint.x - mRadius * (1 + (mPercent - 0.2f) / 0.3f);//左半圆mControlPoint[2].y = mRadius * (1 - (mPercent - 0.2f) / 0.3f * 0.1f);//底部mControlPoint[8].y = -mRadius * (1 - (mPercent - 0.2f) / 0.3f * 0.1f);//顶部mc = mc * (1 + (mPercent - 0.2f) / 0.3f * 0.3f);} else if (mPercent > 0.5 && mPercent <= 0.8) {//左右恢复 变圆M逐渐重置为原来大小 圆心移动mControlPoint[5].x = mCenterPoint.x + mRadius * (1 + (0.8f - mPercent) / 0.3f);//右半圆mControlPoint[0].x = mCenterPoint.x - mRadius * (1 + (0.8f - mPercent) / 0.3f);//左半圆mControlPoint[2].y = mRadius * (1 + (mPercent - 0.8f) / 0.3f * 0.1f);//底部mControlPoint[8].y = -mRadius * (1 + (mPercent - 0.8f) / 0.3f * 0.1f);//顶部mc = mc * (1 + (-mPercent + 0.8f) / 0.3f * 0.3f);} else if (mPercent > 0.8 && mPercent <= 0.9) {//左凹 圆心到达mControlPoint[5].x = mCenterPoint.x + mRadius;//右半圆mControlPoint[0].x = mCenterPoint.x - mRadius * (1 - (mPercent - 0.8f) / 0.1f * 0.5f);//左半圆} else if (mPercent > 0.9 && mPercent <= 1) {//回弹 圆心到达mControlPoint[5].x = mCenterPoint.x + mRadius;//右半圆mControlPoint[0].x = mCenterPoint.x - mRadius * (1 - (1.0f - mPercent) / 0.1f * 0.5f);//左半圆}} else//右滑{if (mPercent <= 1 && mPercent >= 0.8) {//左凸起 圆心不变mControlPoint[5].x = mCenterPoint.x + mRadius;//右半圆mControlPoint[0].x = mCenterPoint.x - mRadius * (2 - (mPercent - 0.8f) / 0.2f);//左半圆} else if (mPercent > 0.5 && mPercent <= 0.8) {//加速 右凸起 扁平化M 最左端固定不变 圆心移动mControlPoint[5].x = mCenterPoint.x + mRadius * (2 - (mPercent - 0.5f) / 0.3f);//右半圆mControlPoint[0].x = mCenterPoint.x - 2 * mRadius;//左半圆mControlPoint[2].y = mRadius * (1 - (0.8f - mPercent) / 0.3f * 0.1f);//底部mControlPoint[8].y = -mRadius * (1 - (0.8f - mPercent) / 0.3f * 0.1f);//顶部mc = mc * (1 + (0.8f - mPercent) / 0.3f * 0.3f);} else if (mPercent > 0.2 && mPercent <= 0.5) {//左右恢复 变圆M逐渐重置为原来大小 圆心移动mControlPoint[5].x = mCenterPoint.x + mRadius * (1 + (mPercent - 0.2f) / 0.3f);//右半圆mControlPoint[0].x = mCenterPoint.x - mRadius * (1 + (mPercent - 0.2f) / 0.3f);//左半圆mControlPoint[2].y = mRadius * (1 - (mPercent - 0.2f) / 0.3f * 0.1f);//底部mControlPoint[8].y = -mRadius * (1 - (mPercent - 0.2f) / 0.3f * 0.1f);//顶部mc = mc * (1 + (mPercent - 0.2f) / 0.3f * 0.3f);} else if (mPercent > 0.1 && mPercent <= 0.2) {//右凹 圆心到达mControlPoint[5].x = mCenterPoint.x + mRadius * (1 - (0.2f - mPercent) / 0.1f * 0.5f);//右半圆mControlPoint[0].x = mCenterPoint.x - mRadius;//左半圆} else if (mPercent >= 0 && mPercent <= 0.1) {//回弹 圆心到达mControlPoint[5].x = mCenterPoint.x + mRadius * (1 - (mPercent) / 0.1f * 0.5f);//右半圆mControlPoint[0].x = mCenterPoint.x - mRadius;//左半圆}}}//11 0 1mControlPoint[0].y = 0;mControlPoint[1].x = mControlPoint[0].x;mControlPoint[1].y = mRadius * mc;mControlPoint[11].x = mControlPoint[0].x;mControlPoint[11].y = -mRadius * mc;//2 3 4mControlPoint[2].x = mCenterPoint.x - mRadius * mc;mControlPoint[3].x = mCenterPoint.x;mControlPoint[3].y = mControlPoint[2].y;mControlPoint[4].x = mCenterPoint.x + mRadius * mc;mControlPoint[4].y = mControlPoint[2].y;//5 6 7mControlPoint[5].y = mRadius * mc;mControlPoint[6].x = mControlPoint[5].x;mControlPoint[6].y = 0;mControlPoint[7].x = mControlPoint[5].x;mControlPoint[7].y = -mRadius * mc;//8 9 10mControlPoint[8].x = mCenterPoint.x + mRadius * mc;mControlPoint[9].x = mCenterPoint.x;mControlPoint[9].y = mControlPoint[8].y;mControlPoint[10].x = mCenterPoint.x - mRadius * mc;mControlPoint[10].y = mControlPoint[8].y;}private MyViewPagerIndicator.Point[] mControlPoint = new MyViewPagerIndicator.Point[9];private MyViewPagerIndicator.CenterPoint mCenterPoint = new MyViewPagerIndicator.CenterPoint();class CenterPoint {float x;float y;}class Point {float x;float y;}/*** 移动指示点** @param percent 比例* @param position 第几个* @param isLeft 是否左滑*/public void move(float percent, int position, boolean isLeft) {mPosition = position;mPercent = percent;mIsLeft = isLeft;switch (mIndicatorType) {case MyViewPagerIndicator.IndicatorType.CIRCLE_LINE://圆线if (mPosition == mNum - 1 && !isLeft) {//第一个 右滑mOffset = percent * mDistance;}if (mPosition == mNum - 1 && isLeft) {//最后一个 左滑mOffset = percent * mDistance;} else {//中间mOffset = percent * mDistance;}break;case MyViewPagerIndicator.IndicatorType.CIRCLE://圆case MyViewPagerIndicator.IndicatorType.LINE://线case MyViewPagerIndicator.IndicatorType.PROGRESS://进度条if (mPosition == mNum - 1 && !isLeft) {//第一个 右滑mOffset = (1 - percent) * (mNum - 1) * mDistance;} else if (mPosition == mNum - 1 && isLeft) {//最后一个 左滑mOffset = (1 - percent) * (mNum - 1) * mDistance;} else {//中间的mOffset = (percent + mPosition) * mDistance;}break;case MyViewPagerIndicator.IndicatorType.BEZIER://贝塞尔break;case MyViewPagerIndicator.IndicatorType.SPRING://弹性break;}invalidate();}/*** 个数** @param num*/public MyViewPagerIndicator setNum(int num) {mNum = num;invalidate();return this;}/*** 类型** @param indicatorType*/public MyViewPagerIndicator setType(int indicatorType) {mIndicatorType = indicatorType;invalidate();return this;}/*** 线,圆,圆线,贝塞尔,弹性球,进度条*/public interface IndicatorType {int LINE = 0;int CIRCLE = 1;int CIRCLE_LINE = 2;int BEZIER = 3;int SPRING = 4;int PROGRESS = 5;}/*** 半径** @param radius*/public MyViewPagerIndicator setRadius(float radius) {this.mRadius = radius;invalidate();return this;}/*** 距离 在IndicatorDistanceType为BYDISTANCE下作用** @param distance*/public MyViewPagerIndicator setDistance(float distance) {this.mDistance = distance;invalidate();return this;}/*** 距离类型** @param mDistanceType*/public MyViewPagerIndicator setDistanceType(int mDistanceType) {this.mDistanceType = mDistanceType;invalidate();return this;}/*** 布局,距离,半径*/public interface DistanceType { //int BY_RADIUS = 0;int BY_DISTANCE = 1;int BY_LAYOUT = 2;}/*** 一般 不循环 固定* @param viewPager 适配的viewpager* @return*/public MyViewPagerIndicator setViewPager(ViewPager2 viewPager) {setViewPager(viewPager, viewPager.getAdapter().getItemCount(),false);return this;}/**** @param viewpager 适配的viewpager* @param CycleNumber 伪无限循环 真实个数* @return*/public MyViewPagerIndicator setViewPager(ViewPager2 viewpager, int CycleNumber) {setViewPager(viewpager, CycleNumber,false);return this;}/**** @param viewPager 适配的viewpager* @param isInfiniteCircle 真无限循环 配合BannerView 通常是true;false为一般 不循环 固定等价于{@link #setViewPager(ViewPager viewPager)}** @return*/public MyViewPagerIndicator setViewPager(ViewPager2 viewPager, boolean isInfiniteCircle) {if(isInfiniteCircle){setViewPager(viewPager,viewPager.getAdapter().getItemCount()-2,isInfiniteCircle);}else{setViewPager(viewPager,viewPager.getAdapter().getItemCount(),isInfiniteCircle);}return this;}/**** @param viewpager 适配的viewpager* @param CycleNumber 真/伪无限循环都必须输入* @param isInfiniteCircle 真无限循环 配合Banner* @return*/public MyViewPagerIndicator setViewPager(ViewPager2 viewpager, int CycleNumber, boolean isInfiniteCircle) {mNum = CycleNumber;mIsInfiniteCircle = isInfiniteCircle;viewpager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {//记录上一次滑动的positionOffsetPixels值private int lastValue = -1;@Overridepublic void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {if(!mAnimation){//不需要动画return;}boolean isLeft = mIsLeft;if (lastValue / 10 > positionOffsetPixels / 10) {//右滑isLeft = false;} else if (lastValue / 10 < positionOffsetPixels / 10) {//左滑isLeft = true;}if (mNum > 0&&!mIsInfiniteCircle) {move(positionOffset, position % mNum, isLeft);}else if(mNum>0&&mIsInfiniteCircle){if(position==0){position=mNum-1;}else if(position==mNum+1){position=0;}else{position--;}move(positionOffset, position , isLeft);}lastValue = positionOffsetPixels;}@Overridepublic void onPageSelected(int position) {if(mAnimation){//需要动画return;}if(mNum>0&&!mIsInfiniteCircle){move(0, position % mNum, false);}else if(mNum>0&&mIsInfiniteCircle){if(position==0){position=mNum-1;}else if(position==mNum+1){position=0;}else{position--;}move(0, position , false);}}@Overridepublic void onPageScrollStateChanged(int state) {}});return this;}}
3:属性说明
属性 | 说明 |
| 选中的指示器颜色 |
| 未选中的指示器颜色 |
| |
| 指示器的类型 |
4:使用效果加说明
(1):圆线
<com.sbl.hwscankitdemo.view.MyViewPagerIndicatorandroid:layout_centerHorizontal="true"android:layout_alignParentBottom="true"android:id="@+id/indicator_line"android:layout_width="wrap_content"android:layout_marginBottom="10dp"android:layout_height="16dp"app:sbl_default_color="#f00"app:sbl_radius="3dp"app:sbl_distanceType="BY_DISTANCE"app:sbl_indicatorType="CIRCLE_LINE"app:sbl_distance="10dp"/>
属性 (sbl_indicatorType) | 说明 |
| |
| 默认的颜色(sbl_selected_color)无作用, |
| 原点的半径 |
sbl_distanceType="BY_DISTANCE" | 指示器的item间距类型, |
sbl_distance | item间距 |
(2):线
<com.sbl.hwscankitdemo.view.MyViewPagerIndicatorandroid:layout_centerHorizontal="true"android:layout_alignParentBottom="true"android:id="@+id/indicator_line"android:layout_width="wrap_content"android:layout_marginBottom="10dp"android:layout_height="16dp"app:sbl_default_color="#f00"app:sbl_selected_color="#ff0"app:sbl_radius="3dp"app:sbl_distanceType="BY_DISTANCE"app:sbl_indicatorType="LINE"app:sbl_distance="10dp"/>
属性 (sbl_indicatorType) | 说明 |
| |
| 未选中的颜色 |
| 选中的颜色 |
| 原点的半径 |
sbl_distanceType="BY_DISTANCE" | 指示器的item间距类型, |
sbl_distance | item间距 |
(3):点
<com.sbl.hwscankitdemo.view.MyViewPagerIndicatorandroid:layout_centerHorizontal="true"android:layout_alignParentBottom="true"android:id="@+id/indicator_line"android:layout_width="wrap_content"android:layout_marginBottom="10dp"android:layout_height="16dp"app:sbl_default_color="#f00"app:sbl_selected_color="#ff0"app:sbl_radius="3dp"app:sbl_distanceType="BY_DISTANCE"app:sbl_indicatorType="CIRCLE"app:sbl_distance="10dp"/>
属性 (sbl_indicatorType) | 说明 |
| |
| 未选中的颜色 |
| 选中的颜色 |
| 原点的半径 |
sbl_distanceType="BY_DISTANCE" | 指示器的item间距类型, |
sbl_distance | item间距 |
(4):贝塞尔曲线、弹性球和进度条样式这里就不举例了,gif制作有点虚,有兴趣的可以自己修改代码看下效果。
3:和viewpager2绑定
public class BannerActivity extends AppCompatActivity {Banner banner;public List<Integer> list = new ArrayList<>();MyViewPagerIndicator indicator;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_banner);banner = findViewById(R.id.banner);indicator = findViewById(R.id.indicator_line);banner.setAdapter(new ImageAdapter(DataBean.getTestData()));//在这里绑定viewpager2indicator.setViewPager( banner.getViewPager2(),DataBean.getTestData().size());}}
activity_banner.xml布局
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".BannerActivity"><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="150dp"><com.youth.banner.Bannerxmlns:banner="http://schemas.android.com/apk/res-auto"android:id="@+id/banner"android:layout_width="match_parent"android:layout_height="150dp" /><com.sbl.hwscankitdemo.view.MyViewPagerIndicatorandroid:layout_centerHorizontal="true"android:layout_alignParentBottom="true"android:id="@+id/indicator_line"android:layout_width="wrap_content"android:layout_marginBottom="10dp"android:layout_height="16dp"app:sbl_default_color="#f00"app:sbl_selected_color="#ff0"app:sbl_radius="3dp"app:sbl_distanceType="BY_DISTANCE"app:sbl_indicatorType="PROGRESS"app:sbl_distance="10dp"/></RelativeLayout></RelativeLayout>
4:源码地址:https://gitee.com/ishopSbl/hua-wei-qr-demo.git
这篇关于android 循环轮播控件com.youth.banner 的自定义轮播指示器,满足开发需求。的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!