自定义View_留声机效果


(Values下)attrs.xml

[html]  view plain  copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <resources>  
  3.     <declare-styleable name="GramophoneView">  
  4.         <attr name="picture_radiu" format="dimension"/>            //中间图片的半径  
  5.         <attr name="src" format="reference"/>                //图片  
  6.         <attr name="disk_rotate_speed" format="float"/>     //唱片旋转的速度  
  7.     </declare-styleable>  
  8. </resources>  

自定义View

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

mainActivity.xml

[html]  view plain  copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     xmlns:app="http://schemas.android.com/apk/res-auto"  
  4.     xmlns:tools="http://schemas.android.com/tools"  
  5.     android:layout_width="match_parent"  
  6.     android:layout_height="match_parent"  
  7.     android:orientation="vertical"  
  8.     tools:context="com.example.jinmuyan.phonograph.MainActivity">  
  9.   
  10.     <com.example.jinmuyan.phonograph.GramophoneView  
  11.         android:id="@+id/gramophone"  
  12.         app:src="@drawable/lang"  
  13.         app:picture_radiu="80dp"  
  14.         app:disk_rotate_speed="1"  
  15.         android:layout_width="wrap_content"  
  16.         android:layout_height="wrap_content"  
  17.         />  
  18.   
  19.     <Button  
  20.         android:layout_marginTop="60dp"  
  21.         android:onClick="pauseOrstart"  
  22.         android:text="切换播放状态"  
  23.         android:layout_width="wrap_content"  
  24.         android:layout_height="wrap_content" />  
  25.   
  26. </LinearLayout>  

MainActivity

[java]  view plain  copy
  1. public class MainActivity extends AppCompatActivity {  
  2.   
  3.     private GramophoneView gramophoneView;  
  4.     @Override  
  5.     protected void onCreate(Bundle savedInstanceState) {  
  6.         super.onCreate(savedInstanceState);  
  7.         setContentView(R.layout.activity_main);  
  8.   
  9.         gramophoneView = (GramophoneView) findViewById(R.id.gramophone);  
  10.     }  
  11.   
  12.     public void pauseOrstart(View view) {  
  13.         gramophoneView.pauseOrstart();  
  14.     }  
  15. }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值