转载请标明出处:
https://blog.csdn.net/m0_38074457/article/details/86433483
,本文出自【陈少华的博客】
public TurntableView(Context context) {
this(context, null);
}
public TurntableView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public TurntableView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context, attrs);
}
initView方法中初始化控件的值
/**
* 初始化view
*
* @param context
* @param attrs
*/
private void initView(Context context, AttributeSet attrs) {
//手势识别对象
mDetector = new GestureDetectorCompat(context, new TurntableGestureListener());
//抗锯齿
mPaint.setAntiAlias(true);
mScreenHeight = getResources().getDisplayMetrics().heightPixels;
mScreenWidth = getResources().getDisplayMetrics().widthPixels;
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.TurntableView);
if (array != null) {
mPanNum = array.getInteger(R.styleable.TurntableView_pannum, 8);
int colorsId = array.getResourceId(R.styleable.TurntableView_colors, R.array.colors);
int namesArray = array.getResourceId(R.styleable.TurntableView_names, R.array.names);
int iconsArray = array.getResourceId(R.styleable.TurntableView_icons, R.array.icons);
mPercentage = array.getFloat(R.styleable.TurntableView_percentage, (float) 0.75);
int[] colors = context.getResources().getIntArray(colorsId);
String[] namesStrs = context.getResources().getStringArray(namesArray);
String[] iconsStrs = context.getResources().getStringArray(iconsArray);
for (int i = 0; i < colors.length; i++) {
mColors.add(colors[i]);
}
for (int i = 0; i < namesStrs.length; i++) {
mNamesStrs.add(namesStrs[i]);
}
List iconLists = new ArrayList<>();
for (int i = 0; i < iconsStrs.length; i++) {
iconLists.add(context.getResources().getIdentifier(iconsStrs[i], "mipmap", context.getPackageName()));
}
for (int i = 0; i < iconLists.size(); i++) {
Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), iconLists.get(i));
mBitmaps.add(bitmap);
}
array.recycle();
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//控制view的宽为屏幕宽的mPercentage
int viewWid = (int) ((float) mScreenWidth * mPercentage);
setMeasuredDimension(viewWid, viewWid);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mWid = w;
mHei = h;
//让转盘的宽为view的宽,半径为view的宽的一半
mCenterX = mWid / 2;
mCenterY = mCenterX;
mRadius = mWid / 2;
mOffsetAngle = (float) 360 / (float) mPanNum;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//画圆的背景颜色
drawBackground(canvas);
//画图片
drawImage(canvas);
//画文本
drawText(canvas);
}
/**
* 画圆的整体背景
*
* @param canvas
*/
private void drawBackground(Canvas canvas) {
mPaint.setStyle(Paint.Style.FILL);
RectF rectF = new RectF(0, 0, mWid, mHei);
float angle = mCurrentAngle;
for (int i = 0; i < mPanNum; i++) {
int yushu = i % mColors.size();
mPaint.setColor(mColors.get(yushu));
canvas.drawArc(rectF, angle, mOffsetAngle, true, mPaint);
angle = angle + mOffsetAngle;
}
}
/**
* 画图像
*
* @param canvas
*/
private void drawImage(Canvas canvas) {
//绘制图片开始的角度位置
float radian = mCurrentAngle + mOffsetAngle / (float) 2;
//使图像的宽度的一半为半径的1/7
float imageOffset = (float) mRadius / (float) 7;
for (int i = 0; i < mBitmaps.size(); i++) {
//计算图片中心位置的坐标
//Math.toRadians 是为了提高计算精度
float x = (float) (mCenterX + (float) mRadius * (float) 0.6 * Math.cos(Math.toRadians(radian)));
float y = (float) (mCenterY + (float) mRadius * (float) 0.6 * Math.sin(Math.toRadians(radian)));
RectF rectF = new RectF(x - imageOffset, y - imageOffset, x + imageOffset, y + imageOffset);
canvas.drawBitmap(mBitmaps.get(i), null, rectF, mPaint);
radian = radian + mOffsetAngle;
}
}
/**
* 画文本
*
* @param canvas
*/
private void drawText(Canvas canvas) {
mPaint.setColor(Color.WHITE);
mPaint.setTextAlign(Paint.Align.CENTER);
mPaint.setTextSize(30);
RectF rectF = new RectF(0, 0, mWid, mHei);
//计算text文本的高度
Paint.FontMetrics fm = mPaint.getFontMetrics();
float textHeight = fm.bottom - fm.top;
float startAngle = mCurrentAngle;
for (int i = 0; i < mNamesStrs.size(); i++) {
//使文本根据,每个item的圆弧路径绘制
Path path = new Path();
path.addArc(rectF, startAngle, mOffsetAngle);
canvas.drawTextOnPath(mNamesStrs.get(i), path, 0, textHeight + 10, mPaint);
startAngle = startAngle + mOffsetAngle;
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return mDetector.onTouchEvent(event);
}
private class TurntableGestureListener extends GestureDetector.SimpleOnGestureListener {
@Override
public boolean onDown(MotionEvent e) {
//如果正在抽奖,则不可以手势滑动
if (isDrawingLottery) {
return false;
}
if (mOnFlingAnimator != null) {
mOnFlingAnimator.cancel();
}
mStartX = e.getX();
mStartY = e.getY();
return true;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
LoggerUtil.i(TAG, "onScroll");
float e2X = e2.getX();
float e2Y = e2.getY();
float xStart = mStartX - mCenterX;
float yStart = mCenterY - mStartY;
double distancestart = Math.sqrt(xStart * xStart + yStart * yStart);
//计算移动点到圆心的距离
float xMove = e2X - mCenterX;
float yMove = mCenterY - e2Y;
double distanceMove = Math.sqrt(xMove * xMove + yMove * yMove);
double distanceMoveDz = Math.sqrt(distanceX * distanceX + distanceY * distanceY);
double cosValue = (distancestart * distancestart + distanceMove * distanceMove - distanceMoveDz * distanceMoveDz) / (2 * distancestart * distanceMove);
//多指触控的时候会造成cosValue 大于1,这里控制一下
if (cosValue > 1) {
LoggerUtil.i(TAG + "大于1", cosValue);
cosValue = 1;
} else if (cosValue < -1) {
LoggerUtil.i(TAG + "小于1", cosValue);
cosValue = -1;
}
double acos = Math.acos(cosValue);
double changeAngleDz = Math.toDegrees(acos);
//大于0 顺时针,小于0 逆时针
float value = (mStartX - mCenterX) * (e2Y - mCenterY) - (mStartY - mCenterY) * (e2X - mCenterX);
if (value >= 0) {
mCurrentAngle = (float) (mCurrentAngle + changeAngleDz);
isClockwise = true;
} else {
mCurrentAngle = (float) (mCurrentAngle - changeAngleDz);
isClockwise = false;
}
setRotate(mCurrentAngle);
mStartX = e2X;
mStartY = e2Y;
return true;
}
@Override
public boolean onFling(MotionEvent e1, final MotionEvent e2, final float velocityX, final float velocityY) {
float e2X = e2.getX();
float e2Y = e2.getY();
float dx = velocityX * (float) 0.005;
float dy = velocityY * (float) 0.005;
float xStart = mStartX - mCenterX;
float yStart = mCenterY - mStartY;
double distancestart = Math.sqrt(xStart * xStart + yStart * yStart);
//计算移动点到圆心的距离
float xMove = e2X - mCenterX;
float yMove = mCenterY - e2Y;
double distanceMove = Math.sqrt(xMove * xMove + yMove * yMove);
double distanceMoveDz = Math.sqrt(dx * dx + dy * dy);
double cosValue = (distancestart * distancestart + distanceMove * distanceMove - distanceMoveDz * distanceMoveDz) / (2 * distancestart * distanceMove);
//多指触控的时候会造成cosValue 大于1,这里控制一下
if (cosValue > 1) {
cosValue = 1;
} else if (cosValue < -1) {
cosValue = -1;
}
double acos = Math.acos(cosValue);
double changeAngleDz = Math.toDegrees(acos);
if (isClockwise) {
} else {
//逆时针
changeAngleDz = changeAngleDz * -1;
}
mOnFlingAnimator = ValueAnimator.ofFloat((float) changeAngleDz, 0);
mOnFlingAnimator.setDuration(1000);
mOnFlingAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float animatedX = (float) animation.getAnimatedValue();
mCurrentAngle = mCurrentAngle + animatedX;
setRotate(mCurrentAngle);
}
});
mOnFlingAnimator.start();
return true;
}
}
onScroll方法中计算手指滑动时候转盘转动的角度原理:
步骤1.将JitPack存储库添加到构建文件中
项目的根build.gradle中添加以下代码:
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
步骤2.build.gradle添加依赖项
dependencies {
implementation 'com.github.hnsycsxhzcsh:TurntableView:v1.1'
}
步骤3. 布局中引用控件(控件需要放在一个父布局中,父布局中放一个图片按钮)
步骤4. activity中添加监听
mIvGo.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mTurntable.startRotate(new ITurntableListener() {
@Override
public void onStart() {
Toast.makeText(MainActivity.this, "开始抽奖", Toast.LENGTH_SHORT).show();
}
@Override
public void onEnd(int position, String name) {
mTvResult.setText("抽奖结束抽中第" + (position + 1) + "位置的奖品:" + name);
}
});
}
});
可以在github上下载我的项目:https://github.com/hnsycsxhzcsh/TurntableView,如果我的博客对你有帮助的话,欢迎博客点赞支持,并在github右上角star支持!