自定义音乐播放转盘

  1. public class GramophoneView extends View {  
  2.   
  3.   
  4.     /**  
  5.      * 尺寸计算设计说明:  
  6.      * 1、唱片有两个主要尺寸:中间图片的半径、黑色圆环的宽度。  
  7.      * 黑色圆环的宽度 = 图片半径的一半。  
  8.      * 2、唱针分为“手臂”和“头”,手臂分两段,一段长的一段短的,头也是一段长的一段短的。  
  9.      * 唱针四个部分的尺寸求和 = 唱片中间图片的半径+黑色圆环的宽度  
  10.      * 唱针各部分长度 比例——长的手臂:短的手臂:长的头:短的头 = 8:4:2:1  
  11.      * 3、唱片黑色圆环顶部到唱针顶端的距离 = 唱针长的手臂的长。度  
  12.      */  
  13.   
  14.     private final float DEFUALT_DISK_ROTATE_SPEED = 1f;      //磁盘旋转的速度  
  15.     private final float DEFUALT_PICTURE_RAUID = 200;         //中间图片默认半径  
  16.     private final float DEFUALT_PAUSE_NEEDLE_DEGREE = -45;  //暂停状态时唱针的旋转角度  
  17.     private final float DEFUALT_PLAYING_NEEDLE_DEGREE = -15;     //播放状态时唱针的旋转角度  
  18.   
  19.     private int pictrueRadio;   //中间图片的半径  
  20.   
  21.     //指针  
  22.     private int smallCircleRadiu = 10;  //唱针顶部小圆半径,减小了一半  
  23.     private int bigCircleRadiu = 15;    //唱针顶部大圆半径,减小了一半  
  24.   
  25.     private int shortArmLength;  
  26.     private int longArmleLength;         // 唱针手臂,较长那段的长度  
  27.     private int shortHeadLength;         // 唱针的头,较短那段的长度  
  28.     private int longHeadLength;  
  29.     private Paint needlePaint;  
  30.   
  31.     //唱片  
  32.     private float halfMeasureWidth;  
  33.     private int diskRingWidth;            // 黑色圆环宽度  
  34.     private float diskRotateSpeed;        // 唱片旋转速度  
  35.     private Bitmap pictureBitmap;  
  36.     private Paint diskPaint;  
  37.   
  38.     //状态控制  
  39.     private boolean isPlaying;  
  40.     private float currentDiskDegree;            // 唱片旋转角度  
  41.     private float currentNeddleDegree = DEFUALT_PLAYING_NEEDLE_DEGREE;  // 唱针旋转角度  
  42.   
  43.   
  44.     public GramophoneView(Context context) {  
  45.         this(context,null);  
  46.     }  
  47.   
  48.     public GramophoneView(Context context, @Nullable AttributeSet attrs) {  
  49.         super(context, attrs);  
  50.         needlePaint = new Paint(Paint.ANTI_ALIAS_FLAG);//抗锯齿  
  51.         diskPaint = new Paint(Paint.ANTI_ALIAS_FLAG);  
  52.         TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.GramophoneView);  
  53.   
  54. //        拿到xml中的图片和图片半径和,旋转的度数  
  55.         pictrueRadio = (int) typedArray.getDimension(R.styleable.GramophoneView_picture_radiu, DEFUALT_PICTURE_RAUID);  
  56.         diskRotateSpeed = typedArray.getFloat(R.styleable.GramophoneView_disk_rotate_speed, DEFUALT_DISK_ROTATE_SPEED);  
  57.         Drawable drawable = typedArray.getDrawable(R.styleable.GramophoneView_src);  
  58.         if (drawable == null) {  
  59.             pictureBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);  
  60.         } else {  
  61.             pictureBitmap = ((BitmapDrawable)drawable).getBitmap();  
  62.         }  
  63.   
  64.         //初始化唱片的变量  
  65.         diskRingWidth = pictrueRadio >> 1;  
  66.   
  67.         shortHeadLength = (pictrueRadio + diskRingWidth) / 15;    //图片半径和黑色圆环的和 等于 指针的总长度  
  68.         longHeadLength = shortHeadLength << 1;    //左移相当于乘以2  
  69.         shortArmLength = longHeadLength << 1;  
  70.         longArmleLength = shortArmLength << 1;  
  71.     }  
  72.   
  73.     /**  
  74.      * 理想的宽高是,取决于picture的 半径的  
  75.      *  
  76.      * @param widthMeasureSpec  
  77.      * @param heightMeasureSpec  
  78.      */  
  79.     @Override  
  80.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  81.         super.onMeasure(widthMeasureSpec, heightMeasureSpec);  
  82.         //我们想要的理想宽高  
  83.         int width = (pictrueRadio+diskRingWidth)*2;  
  84.         int hight = (pictrueRadio+diskRingWidth)*2+longArmleLength;  
  85.   
  86.         //根据我们理想的宽和高 和xml中设置的宽高,按resolveSize规则做最后的取舍  
  87.         //resolveSize规则 1、精确模式,按  
  88.         int measurewidth = resolveSize(width,widthMeasureSpec);  
  89.         int measurehight = resolveSize(hight,heightMeasureSpec);  
  90.   
  91.         setMeasuredDimension(measurewidth,measurehight);//设置测量的长度  
  92.     }  
  93.   
  94.     @Override  
  95.     protected void onDraw(Canvas canvas) {  
  96.         super.onDraw(canvas);  
  97.         halfMeasureWidth = getMeasuredWidth() >> 1;  
  98.         drawDisk(canvas);   //画唱片  
  99.         drawNeedle(canvas);//画指针  
  100.   
  101.   
  102.         if (currentNeddleDegree > DEFUALT_PAUSE_NEEDLE_DEGREE) {  
  103.             invalidate();  
  104.         }  
  105.     }  
  106.   
  107.     private void drawNeedle(Canvas canvas) {//指针  
  108.   
  109.         canvas.save();//保存  
  110.         //移动坐标原点,画指针第一段  
  111.         canvas.translate(halfMeasureWidth, 0);  
  112.         canvas.rotate(currentNeddleDegree);  
  113.         needlePaint.setColor(Color.parseColor("#C0C0C0"));  
  114.         needlePaint.setStrokeWidth(10);  
  115.         canvas.drawLine(0, 0, 0, longArmleLength, needlePaint);  
  116.         //画指针第二段  
  117.         canvas.translate(0, longArmleLength);  
  118.         canvas.rotate(-30);//  
  119.         needlePaint.setStrokeWidth(10);  
  120.         canvas.drawLine(0, 0, 0, shortArmLength, needlePaint);  
  121.   
  122.   
  123.         //画指针第三段  
  124.         canvas.translate(0, shortArmLength);  
  125.         needlePaint.setStrokeWidth(15);  
  126.         canvas.drawLine(0, 0, 0, longHeadLength, needlePaint);  
  127.   
  128.         //画指针的第四段  
  129.         canvas.translate(0, longHeadLength);  
  130.         needlePaint.setStrokeWidth(25);  
  131.         canvas.drawLine(0, 0, 0, shortHeadLength, needlePaint);  
  132.         canvas.restore();  
  133.   
  134.   
  135.         //画指针的支点  
  136.         canvas.save();  
  137.         canvas.translate(halfMeasureWidth, 0);  
  138.         needlePaint.setColor(Color.parseColor("#8A8A8A"));  
  139.         needlePaint.setStyle(Paint.Style.FILL);  
  140.         canvas.drawCircle(0, 0, bigCircleRadiu, needlePaint);  
  141.   
  142.         needlePaint.setColor(Color.parseColor("#C0C0C0"));  
  143.         canvas.drawCircle(0, 0, smallCircleRadiu, needlePaint);  
  144.         canvas.restore();  
  145.   
  146.         //当前如果是播放的话,就移动到播放的位置 ,因为逆时针旋转度数是负的所以,-  + 需要注意  
  147.         if (isPlaying) {  
  148.             if (currentNeddleDegree < DEFUALT_PLAYING_NEEDLE_DEGREE) {  //不是暂停状态,就是播放状态,或者是切换中状态  
  149.                 currentNeddleDegree += 3;  //切换中状态指针是要有动画效果的,所有要改变指针的度数  
  150.             }  
  151.         } else {  
  152.             if (currentNeddleDegree > DEFUALT_PAUSE_NEEDLE_DEGREE) {  
  153.                 currentNeddleDegree -3;  
  154.             }  
  155.         }  
  156.     }  
  157.   
  158.     private void drawDisk(Canvas canvas) {  
  159.         currentDiskDegree = currentDiskDegree % 360 + diskRotateSpeed;  
  160.   
  161.         canvas.save();  
  162.         canvas.translate(halfMeasureWidth, longArmleLength + diskRingWidth + pictrueRadio);  
  163.         canvas.rotate(currentDiskDegree);  
  164.         diskPaint.setColor(Color.BLACK);  
  165.         diskPaint.setStyle(Paint.Style.STROKE);  
  166.         diskPaint.setStrokeWidth(pictrueRadio / 2);  
  167. //        diskPaint.setStrokeWidth(20);  
  168.         canvas.drawCircle(0, 0, pictrueRadio + diskRingWidth / 2, diskPaint);  
  169.   
  170.   
  171.         Path path = new Path();       // 裁剪的path路径 (为了裁剪成圆形图片,其实是将画布剪裁成了圆形)  
  172.         path.addCircle(0, 0, pictrueRadio, Path.Direction.CW);  
  173.         canvas.clipPath(path);  
  174.   
  175.         Rect src = new Rect();                  //将要画bitmap的那个范围  
  176.         src.set(0, 0, pictureBitmap.getWidth(), pictureBitmap.getHeight());  
  177.         Rect dst = new Rect();  
  178.         dst.set(-pictrueRadio, -pictrueRadio, pictrueRadio, pictrueRadio);      //将要将bitmap画要坐标系的那个位置  
  179.         canvas.drawBitmap(pictureBitmap, src, dst, null);  
  180.         canvas.restore();  
  181.     }  
  182.   
  183.   
  184.   
  185.     public void pauseOrstart(){  
  186.         isPlaying =!isPlaying;  
  187.         invalidate();  
  188.     }  
  189.     /**  
  190.      * 设置图片半径  
  191.      *  
  192.      * @param pictureRadius 图片半径  
  193.      */  
  194.     public void setPictureRadius(int pictureRadius) {  
  195.         this.pictrueRadio = pictureRadius;  
  196.     }  
  197.   
  198.   
  199.     /**  
  200.      * 设置唱片旋转速度  
  201.      *  
  202.      * @param diskRotateSpeed 旋转速度  
  203.      */  
  204.     public void setDiskRotateSpeed(float diskRotateSpeed) {  
  205.         this.diskRotateSpeed = diskRotateSpeed;  
  206.     }  
  207.   
  208.     /**  
  209.      * 设置图片资源id  
  210.      *  
  211.      * @param resId 图片资源id  
  212.      */  
  213.     public void setPictureRes(int resId) {  
  214.         pictureBitmap = BitmapFactory.decodeResource(getContext().getResources(), resId);  
  215.         invalidate();  
  216.     }  
[html] view plain copy
  1. <span style="font-size:24px;color:#ff0000;"><strong>values文件下的Attrs</strong></span>  
[html] view plain copy
  1.   
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="GramophoneView">
        <attr name="picture_radiu" format="dimension"/>            //中间图片的半径
        <attr name="src" format="reference"/>                //图片
        <attr name="disk_rotate_speed" format="float"/>     //唱片旋转的速度
    </declare-styleable>

</resources>
xml布局如下
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns: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:orientation="vertical"
    android:layout_height="match_parent"
    tools:context="com.bawei.com.miniti.MainActivity">


    <com.bawei.com.miniti.GramophoneView
        android:id="@+id/gramophone"
        app:src="@drawable/lang"
        app:picture_radiu="80dp"
        app:disk_rotate_speed="1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />

    <Button
        android:layout_marginTop="60dp"
        android:onClick="pauseOrstart"
        android:text="切换播放状态"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

[html] view plain copy
  1.   
MainActivity代码如下
package com.bawei.com.miniti;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;

public class MainActivity extends AppCompatActivity {
    private GramophoneView gramophoneView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        gramophoneView = (GramophoneView) findViewById(R.id.gramophone);


    }
    public void pauseOrstart(View view) {
        gramophoneView.pauseOrstart();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值