当前位置:   article > 正文

《Android自定义控件》TurntableView,抽奖转盘_android tableview

android tableview

转载请标明出处:https://blog.csdn.net/m0_38074457/article/details/86433483 ,本文出自【陈少华的博客】

一、效果图

效果图

二、实现步骤

三、代码实现

1、attrs.xml中添加自定义控件的属性

  1. <declare-styleable name="TurntableView">
  2. <!--转盘的item数量-->
  3. <attr name="pannum" format="integer" />
  4. <!--转盘的item的文本-->
  5. <attr name="names" format="reference" />
  6. <!--转盘的本地图像地址-->
  7. <attr name="icons" format="reference" />
  8. <!--转盘背景的颜色-->
  9. <attr name="colors" format="reference" />
  10. <!--控件宽占屏幕宽的比例-->
  11. <attr name="percentage" format="float" />
  12. </declare-styleable>

2、控件的构造方法

  1. public TurntableView(Context context) {
  2. this(context, null);
  3. }
  4. public TurntableView(Context context, @Nullable AttributeSet attrs) {
  5. this(context, attrs, 0);
  6. }
  7. public TurntableView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
  8. super(context, attrs, defStyleAttr);
  9. initView(context, attrs);
  10. }

initView方法中初始化控件的值

  1. /**
  2. * 初始化view
  3. *
  4. * @param context
  5. * @param attrs
  6. */
  7. private void initView(Context context, AttributeSet attrs) {
  8. //手势识别对象
  9. mDetector = new GestureDetectorCompat(context, new TurntableGestureListener());
  10. //抗锯齿
  11. mPaint.setAntiAlias(true);
  12. mScreenHeight = getResources().getDisplayMetrics().heightPixels;
  13. mScreenWidth = getResources().getDisplayMetrics().widthPixels;
  14. TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.TurntableView);
  15. if (array != null) {
  16. mPanNum = array.getInteger(R.styleable.TurntableView_pannum, 8);
  17. int colorsId = array.getResourceId(R.styleable.TurntableView_colors, R.array.colors);
  18. int namesArray = array.getResourceId(R.styleable.TurntableView_names, R.array.names);
  19. int iconsArray = array.getResourceId(R.styleable.TurntableView_icons, R.array.icons);
  20. mPercentage = array.getFloat(R.styleable.TurntableView_percentage, (float) 0.75);
  21. int[] colors = context.getResources().getIntArray(colorsId);
  22. String[] namesStrs = context.getResources().getStringArray(namesArray);
  23. String[] iconsStrs = context.getResources().getStringArray(iconsArray);
  24. for (int i = 0; i < colors.length; i++) {
  25. mColors.add(colors[i]);
  26. }
  27. for (int i = 0; i < namesStrs.length; i++) {
  28. mNamesStrs.add(namesStrs[i]);
  29. }
  30. List<Integer> iconLists = new ArrayList<>();
  31. for (int i = 0; i < iconsStrs.length; i++) {
  32. iconLists.add(context.getResources().getIdentifier(iconsStrs[i], "mipmap", context.getPackageName()));
  33. }
  34. for (int i = 0; i < iconLists.size(); i++) {
  35. Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), iconLists.get(i));
  36. mBitmaps.add(bitmap);
  37. }
  38. array.recycle();
  39. }
  40. }

3、onMeasure和onSizeChanged控制控件和转盘的大小

  1. @Override
  2. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  3. super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  4. //控制view的宽为屏幕宽的mPercentage
  5. int viewWid = (int) ((float) mScreenWidth * mPercentage);
  6. setMeasuredDimension(viewWid, viewWid);
  7. }
  8. @Override
  9. protected void onSizeChanged(int w, int h, int oldw, int oldh) {
  10. super.onSizeChanged(w, h, oldw, oldh);
  11. mWid = w;
  12. mHei = h;
  13. //让转盘的宽为view的宽,半径为view的宽的一半
  14. mCenterX = mWid / 2;
  15. mCenterY = mCenterX;
  16. mRadius = mWid / 2;
  17. mOffsetAngle = (float) 360 / (float) mPanNum;
  18. }

4、onDraw来绘制转盘

  1. @Override
  2. protected void onDraw(Canvas canvas) {
  3. super.onDraw(canvas);
  4. //画圆的背景颜色
  5. drawBackground(canvas);
  6. //画图片
  7. drawImage(canvas);
  8. //画文本
  9. drawText(canvas);
  10. }
  1. /**
  2. * 画圆的整体背景
  3. *
  4. * @param canvas
  5. */
  6. private void drawBackground(Canvas canvas) {
  7. mPaint.setStyle(Paint.Style.FILL);
  8. RectF rectF = new RectF(0, 0, mWid, mHei);
  9. float angle = mCurrentAngle;
  10. for (int i = 0; i < mPanNum; i++) {
  11. int yushu = i % mColors.size();
  12. mPaint.setColor(mColors.get(yushu));
  13. canvas.drawArc(rectF, angle, mOffsetAngle, true, mPaint);
  14. angle = angle + mOffsetAngle;
  15. }
  16. }
  17. /**
  18. * 画图像
  19. *
  20. * @param canvas
  21. */
  22. private void drawImage(Canvas canvas) {
  23. //绘制图片开始的角度位置
  24. float radian = mCurrentAngle + mOffsetAngle / (float) 2;
  25. //使图像的宽度的一半为半径的1/7
  26. float imageOffset = (float) mRadius / (float) 7;
  27. for (int i = 0; i < mBitmaps.size(); i++) {
  28. //计算图片中心位置的坐标
  29. //Math.toRadians 是为了提高计算精度
  30. float x = (float) (mCenterX + (float) mRadius * (float) 0.6 * Math.cos(Math.toRadians(radian)));
  31. float y = (float) (mCenterY + (float) mRadius * (float) 0.6 * Math.sin(Math.toRadians(radian)));
  32. RectF rectF = new RectF(x - imageOffset, y - imageOffset, x + imageOffset, y + imageOffset);
  33. canvas.drawBitmap(mBitmaps.get(i), null, rectF, mPaint);
  34. radian = radian + mOffsetAngle;
  35. }
  36. }
  37. /**
  38. * 画文本
  39. *
  40. * @param canvas
  41. */
  42. private void drawText(Canvas canvas) {
  43. mPaint.setColor(Color.WHITE);
  44. mPaint.setTextAlign(Paint.Align.CENTER);
  45. mPaint.setTextSize(30);
  46. RectF rectF = new RectF(0, 0, mWid, mHei);
  47. //计算text文本的高度
  48. Paint.FontMetrics fm = mPaint.getFontMetrics();
  49. float textHeight = fm.bottom - fm.top;
  50. float startAngle = mCurrentAngle;
  51. for (int i = 0; i < mNamesStrs.size(); i++) {
  52. //使文本根据,每个item的圆弧路径绘制
  53. Path path = new Path();
  54. path.addArc(rectF, startAngle, mOffsetAngle);
  55. canvas.drawTextOnPath(mNamesStrs.get(i), path, 0, textHeight + 10, mPaint);
  56. startAngle = startAngle + mOffsetAngle;
  57. }
  58. }

5、添加手势控制

  1. @Override
  2. public boolean onTouchEvent(MotionEvent event) {
  3. return mDetector.onTouchEvent(event);
  4. }
  1. private class TurntableGestureListener extends GestureDetector.SimpleOnGestureListener {
  2. @Override
  3. public boolean onDown(MotionEvent e) {
  4. //如果正在抽奖,则不可以手势滑动
  5. if (isDrawingLottery) {
  6. return false;
  7. }
  8. if (mOnFlingAnimator != null) {
  9. mOnFlingAnimator.cancel();
  10. }
  11. mStartX = e.getX();
  12. mStartY = e.getY();
  13. return true;
  14. }
  15. @Override
  16. public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
  17. LoggerUtil.i(TAG, "onScroll");
  18. float e2X = e2.getX();
  19. float e2Y = e2.getY();
  20. float xStart = mStartX - mCenterX;
  21. float yStart = mCenterY - mStartY;
  22. double distancestart = Math.sqrt(xStart * xStart + yStart * yStart);
  23. //计算移动点到圆心的距离
  24. float xMove = e2X - mCenterX;
  25. float yMove = mCenterY - e2Y;
  26. double distanceMove = Math.sqrt(xMove * xMove + yMove * yMove);
  27. double distanceMoveDz = Math.sqrt(distanceX * distanceX + distanceY * distanceY);
  28. double cosValue = (distancestart * distancestart + distanceMove * distanceMove - distanceMoveDz * distanceMoveDz) / (2 * distancestart * distanceMove);
  29. //多指触控的时候会造成cosValue 大于1,这里控制一下
  30. if (cosValue > 1) {
  31. LoggerUtil.i(TAG + "大于1", cosValue);
  32. cosValue = 1;
  33. } else if (cosValue < -1) {
  34. LoggerUtil.i(TAG + "小于1", cosValue);
  35. cosValue = -1;
  36. }
  37. double acos = Math.acos(cosValue);
  38. double changeAngleDz = Math.toDegrees(acos);
  39. //大于0 顺时针,小于0 逆时针
  40. float value = (mStartX - mCenterX) * (e2Y - mCenterY) - (mStartY - mCenterY) * (e2X - mCenterX);
  41. if (value >= 0) {
  42. mCurrentAngle = (float) (mCurrentAngle + changeAngleDz);
  43. isClockwise = true;
  44. } else {
  45. mCurrentAngle = (float) (mCurrentAngle - changeAngleDz);
  46. isClockwise = false;
  47. }
  48. setRotate(mCurrentAngle);
  49. mStartX = e2X;
  50. mStartY = e2Y;
  51. return true;
  52. }
  53. @Override
  54. public boolean onFling(MotionEvent e1, final MotionEvent e2, final float velocityX, final float velocityY) {
  55. float e2X = e2.getX();
  56. float e2Y = e2.getY();
  57. float dx = velocityX * (float) 0.005;
  58. float dy = velocityY * (float) 0.005;
  59. float xStart = mStartX - mCenterX;
  60. float yStart = mCenterY - mStartY;
  61. double distancestart = Math.sqrt(xStart * xStart + yStart * yStart);
  62. //计算移动点到圆心的距离
  63. float xMove = e2X - mCenterX;
  64. float yMove = mCenterY - e2Y;
  65. double distanceMove = Math.sqrt(xMove * xMove + yMove * yMove);
  66. double distanceMoveDz = Math.sqrt(dx * dx + dy * dy);
  67. double cosValue = (distancestart * distancestart + distanceMove * distanceMove - distanceMoveDz * distanceMoveDz) / (2 * distancestart * distanceMove);
  68. //多指触控的时候会造成cosValue 大于1,这里控制一下
  69. if (cosValue > 1) {
  70. cosValue = 1;
  71. } else if (cosValue < -1) {
  72. cosValue = -1;
  73. }
  74. double acos = Math.acos(cosValue);
  75. double changeAngleDz = Math.toDegrees(acos);
  76. if (isClockwise) {
  77. } else {
  78. //逆时针
  79. changeAngleDz = changeAngleDz * -1;
  80. }
  81. mOnFlingAnimator = ValueAnimator.ofFloat((float) changeAngleDz, 0);
  82. mOnFlingAnimator.setDuration(1000);
  83. mOnFlingAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
  84. @Override
  85. public void onAnimationUpdate(ValueAnimator animation) {
  86. float animatedX = (float) animation.getAnimatedValue();
  87. mCurrentAngle = mCurrentAngle + animatedX;
  88. setRotate(mCurrentAngle);
  89. }
  90. });
  91. mOnFlingAnimator.start();
  92. return true;
  93. }
  94. }

onScroll方法中计算手指滑动时候转盘转动的角度原理:

三、项目中如何引用

步骤1.将JitPack存储库添加到构建文件中

项目的根build.gradle中添加以下代码:

  1. allprojects {
  2. repositories {
  3. ...
  4. maven { url 'https://jitpack.io' }
  5. }
  6. }

步骤2.build.gradle添加依赖项

  1. dependencies {
  2. implementation 'com.github.hnsycsxhzcsh:TurntableView:v1.1'
  3. }

步骤3. 布局中引用控件(控件需要放在一个父布局中,父布局中放一个图片按钮)

  1. <RelativeLayout
  2. android:layout_width="match_parent"
  3. android:layout_height="wrap_content">
  4. <com.turntableview.TurntableView
  5. android:id="@+id/turntable"
  6. android:layout_width="match_parent"
  7. android:layout_height="wrap_content"
  8. android:layout_centerInParent="true" />
  9. <ImageView
  10. android:id="@+id/iv_node"
  11. android:layout_width="wrap_content"
  12. android:layout_height="wrap_content"
  13. android:layout_centerInParent="true"
  14. android:background="@mipmap/node" />
  15. </RelativeLayout>

步骤4. activity中添加监听

  1. mIvGo.setOnClickListener(new View.OnClickListener() {
  2. @Override
  3. public void onClick(View v) {
  4. mTurntable.startRotate(new ITurntableListener() {
  5. @Override
  6. public void onStart() {
  7. Toast.makeText(MainActivity.this, "开始抽奖", Toast.LENGTH_SHORT).show();
  8. }
  9. @Override
  10. public void onEnd(int position, String name) {
  11. mTvResult.setText("抽奖结束抽中第" + (position + 1) + "位置的奖品:" + name);
  12. }
  13. });
  14. }
  15. });

备注:

可以在github上下载我的项目:https://github.com/hnsycsxhzcsh/TurntableView,如果我的博客对你有帮助的话,欢迎博客点赞支持,并在github右上角star支持!

 

 

 

 

 

 

 

 

 

 

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/286631?site
推荐阅读
相关标签
  

闽ICP备14008679号