Android入门篇——Button控件+自定义Button控件

移动开发 Android
首先第一步就是往布局文件里拖一个Button控件,当然自己码出来也可以。XML布局如下

首先***步就是往布局文件里拖一个Button控件,当然自己码出来也可以。XML布局如下

  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
  2.     xmlns:tools="http://schemas.android.com/tools" 
  3.     android:layout_width="match_parent" 
  4.     android:layout_height="match_parent" 
  5.      
  6.      > 
  7.  
  8.     <Button 
  9.         android:id="@+id/button1"             <!-- button按钮的id号,程序通过这个id号来查找相应的控件 --> 
  10.         android:layout_width="wrap_content"   <!-- button按钮的宽度 当前意思是 根据内容自动拉伸,其他的还有match_parent,表示根据父控件来调整大小--> 
  11.         android:layout_height="wrap_content"  <!-- button按钮的长度--> 
  12.         android:layout_alignParentTop="true"  <!-- RelativeLayout布局中,将控件的上边缘和父控件的上边缘对齐 --> 
  13.         android:layout_centerHorizontal="true"<!-- RelativeLayout布局中,水平居中的意思 --> 
  14.         android:layout_marginTop="150dp"      <!-- RelativeLayout布局中,距离父控件顶端的距离 --> 
  15.         android:text="Button" />              <!-- button按钮上显示的文字信息 --> 
  16.  
  17. </RelativeLayout> 

当然,一个控件的布局属性还有很多,这些都是需要我们多用多熟悉才行。

然后再在程序中调用它

  1. public class MainActivity extends Activity { 
  2.      
  3.     private Button myButton; 
  4.  
  5.     @Override 
  6.     protected void onCreate(Bundle savedInstanceState) { 
  7.         super.onCreate(savedInstanceState); 
  8.         setContentView(R.layout.activity_main); 
  9.         //通过id寻找控件,记得寻找控件前一定要先设置好布局文件 
  10.         myButton = (Button)findViewById(R.id.button1); 
  11.         myButton.setOnClickListener(new OnClickListener() { 
  12.              
  13.             @Override 
  14.             public void onClick(View v) { 
  15.                 // TODO Auto-generated method stub 
  16.                 //这里填写单击按钮后要执行的事件 
  17.             } 
  18.              
  19.         }); 
  20.         myButton.setOnTouchListener(new OnTouchListener(){...});//设置触碰到按钮的监听器 
  21.         myButton.setOnLongClickListener(new OnLongClickListener(){...});//设置长按按钮的监听器 
  22.         myButton.setOnHoverListener(new OnHoverListener(){...});//设置界面覆盖按钮时的监听器 
  23.         //还有其它的的监听器,我们可以根据不同的需求来调用相应的监听器 
  24.     } 
  25.  
  26.  

或者这样设置监听器

  1. public class MainActivity extends Activity implements OnClickListener{ 
  2.      
  3.     private Button myButton; 
  4.  
  5.     @Override 
  6.     protected void onCreate(Bundle savedInstanceState) { 
  7.         super.onCreate(savedInstanceState); 
  8.         setContentView(R.layout.activity_main); 
  9.         //寻找控件,记得寻找控件前一定要先设置好布局文件 
  10.         myButton = (Button)findViewById(R.id.button1); 
  11.         myButton.setOnClickListener(this); 
  12.              
  13.  
  14.     } 
  15.  
  16.     @Override 
  17.     public void onClick(View v) { 
  18.         // TODO Auto-generated method stub 
  19.         //获取点击的View 
  20.         switch(v.getId()){ 
  21.         //根据View的id来进行相关操作 
  22.         case R.id.button1: 
  23.             //按钮点击时处理相关的事件 
  24.             break
  25.         } 
  26.     } 
  27.  
  28.  

这样一个基础功能的button控件就完成了。但当然,这不是我们今天要讲的重点,重点是我们如何自定义一个按钮,而不是使用系统给我们的按钮。

二、自定义按钮

我们先来看看效果图吧

这是一个自带进度条的按钮,它可以显示异步任务的进度,当完成后结束操作。我们来看看具体是怎么实现的吧。

  1. 拆分这个按钮。仔细观察上面的效果图,我们可以把这个按钮分成3个部分,首先是 最简单的外面一圈圆,基本上画出个圆放在那里就行了。接着是中间的三角形,正方形以及完成的勾,这个我们可以使用view里的画图类勾勒出来,再使用简单 的动画Animation来切换。***的一部分是覆盖在圆圈上的不断在表示进度的圆圈,这个我们可以不断调用这个view的ondraw来刷新进度。这就 是整个按钮的设计思路。我们来看看实际的代码吧。
  2. 首先是表示进度的圆圈,我们来新建一个CusImage继承view类,实时的传入进度参数。
  1. package com.example.mybutton; 
  2.  
  3. import android.annotation.SuppressLint; 
  4. import android.content.Context; 
  5. import android.graphics.Canvas; 
  6. import android.graphics.Color; 
  7. import android.graphics.Paint; 
  8. import android.graphics.RectF; 
  9. import android.util.AttributeSet; 
  10. import android.util.DisplayMetrics; 
  11. import android.util.Log; 
  12. import android.view.View; 
  13.  
  14. @SuppressLint("ViewConstructor")  
  15. public class CusImage extends View { 
  16.  
  17.     private ButtonLayout b; 
  18.     private Paint myPaint; 
  19.     private float startAngle, sweepAngle; 
  20.     private RectF rect; 
  21.     // 默认控件大小 
  22.     private int pix = 160
  23.  
  24.     public CusImage(Context context, ButtonLayout b) { 
  25.         super(context); 
  26.         this.b = b; 
  27.         init(); 
  28.         // TODO Auto-generated constructor stub 
  29.     } 
  30.  
  31.     public CusImage(Context context, AttributeSet attrs, ButtonLayout b) { 
  32.         super(context, attrs); 
  33.         this.b = b; 
  34.         init(); 
  35.         // TODO Auto-generated constructor stub 
  36.     } 
  37.  
  38.     private void init() { 
  39.         myPaint = new Paint(); 
  40.         DisplayMetrics metrics = getContext().getResources() 
  41.                 .getDisplayMetrics(); 
  42.         int width = metrics.widthPixels; 
  43.         int height = metrics.heightPixels; 
  44.         Log.d("TAG", width + ""); 
  45.         Log.d("TAG", height + ""); 
  46.         float scarea = width * height; 
  47.         pix = (int) Math.sqrt(scarea * 0.0217); 
  48.  
  49.         //抗锯齿 
  50.         myPaint.setAntiAlias(true); 
  51.         //stroke表示空心,Fill表示实心 
  52.         myPaint.setStyle(Paint.Style.STROKE); 
  53.         //颜色 
  54.         myPaint.setColor(Color.rgb(0161234)); 
  55.         //设置线条粗细 
  56.         myPaint.setStrokeWidth(7); 
  57.  
  58.         float startx = (float) (pix * 0.05); 
  59.         float endx = (float) (pix * 0.95); 
  60.         float starty = (float) (pix * 0.05); 
  61.         float endy = (float) (pix * 0.95); 
  62.         //矩形区域 
  63.         rect = new RectF(startx, starty, endx, endy); 
  64.     } 
  65.  
  66.     @Override 
  67.     protected void onDraw(Canvas canvas) { 
  68.         // 画弧线 
  69.         // 在rect这个区域内画,开始的角度,扫过的度数而不是结束的角度,false表示不与圆心连线,true通常用来画扇形,画笔。 
  70.         canvas.drawArc(rect, startAngle, sweepAngle, false, myPaint); 
  71.         startAngle = -90
  72.  
  73.         //小于1圈 
  74.         if (sweepAngle < 360 &&b.flg_frmwrk_mode == 2) { 
  75.             invalidate(); 
  76.         }else if(b.flg_frmwrk_mode == 1){ 
  77.                      
  78.         }else {//扫完一圈,调用b.finalAnimation() 
  79.             sweepAngle = 0
  80.             startAngle = -90
  81.             b.finalAnimation(); 
  82.  
  83.         } 
  84.         super.onDraw(canvas); 
  85.     } 
  86.  
  87.     /** 
  88.      * 控制控件的大小 http://blog.csdn.net/pi9nc/article/details/18764863 
  89.      **/ 
  90.     @Override 
  91.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
  92.         int desiredWidth = pix; 
  93.         int desiredHeight = pix; 
  94.         int widthMode = MeasureSpec.getMode(widthMeasureSpec); 
  95.         int widthSize = MeasureSpec.getSize(widthMeasureSpec); 
  96.         int heightMode = MeasureSpec.getMode(heightMeasureSpec); 
  97.         int heightSize = MeasureSpec.getSize(heightMeasureSpec); 
  98.  
  99.         int width; 
  100.         int height; 
  101.  
  102.         // 如果控件宽度是指定大小,宽度为指定的尺寸 
  103.         if (widthMode == MeasureSpec.EXACTLY) { 
  104.             width = widthSize; 
  105.         } else if (widthMode == MeasureSpec.AT_MOST) { // 没有限制,默认内容大小 
  106.             width = Math.min(desiredWidth, widthSize); 
  107.         } else { 
  108.             width = desiredWidth; 
  109.         } 
  110.  
  111.         // 如果控件高度是指定大小,高度为指定的尺寸 
  112.         if (heightMode == MeasureSpec.EXACTLY) { 
  113.             height = heightSize; 
  114.         } else if (heightMode == MeasureSpec.AT_MOST) {// 没有限制,默认内容大小 
  115.             height = Math.min(desiredHeight, heightSize); 
  116.         } else { 
  117.             height = desiredHeight; 
  118.         } 
  119.         // 设定控件大小 
  120.         setMeasuredDimension(width, height); 
  121.     } 
  122.     // 传入参数 
  123.     public void setupprogress(int progress) { 
  124.         sweepAngle = (float) (progress * 3.6); 
  125.     } 
  126.  
  127.     public void reset() { 
  128.         startAngle = -90
  129.     } 
  130.  

有了表示进度的view之后,我们要在一个viewgroup控件中组装各个部分来实现整个按钮,这里我用的是framelayout

 

这里代码写在一起了,我把它们一个一个拎出来讲解。

 

首先是ImageView的初始化

 

  1. /** 
  2.      * 创建各个控件 
  3.      */ 
  4.     private void initialise() { 
  5.         // 按钮的进度条 
  6.         cusView = new CusImage(getContext(), this); 
  7.         // 按钮中间的形状 
  8.         buttonimage = new ImageView(getContext()); 
  9.         // 完成进度后显示的图像 
  10.         fillcircle = new ImageView(getContext()); 
  11.         //外面一圈圆 
  12.         full_circle_image = new ImageView(getContext()); 
  13.         // 设置控件不接受点击事件 
  14.         cusView.setClickable(false); 
  15.         buttonimage.setClickable(false); 
  16.         fillcircle.setClickable(false); 
  17.         full_circle_image.setClickable(false); 
  18.  
  19.         setClickable(true); 
  20.  
  21.     } 

然后是设置动画

  1. /** 
  2.      * 设置动画及动画监听器 
  3.      */ 
  4.     private void setAnimation() { 
  5.  
  6.         // Setting up and defining view animations. 
  7.  
  8.         // http://blog.csdn.net/congqingbin/article/details/7889778 
  9.         // RELATIVE_TO_PARENT:与父控件的的中心为重点;RELATIVE_TO_SELF以自己为中心 
  10.         // 左上角 分别为0.0f 0.0f 中心点为0.5f,0.5f 右下角1.0f,1.0f 
  11.         /* 
  12.          * arcRotation = new RotateAnimation(0.0f, 360.0f, 
  13.          * Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); 
  14.          */ 
  15.         // 持续时间1000ms 
  16.         // arcRotation.setDuration(500); 
  17.  
  18.         in = new AnimationSet(true); 
  19.         out = new AnimationSet(true); 
  20.  
  21.         // http://blog.csdn.net/jason0539/article/details/16370405 
  22.         out.setInterpolator(new AccelerateDecelerateInterpolator()); 
  23.         in.setInterpolator(new AccelerateDecelerateInterpolator()); 
  24.  
  25.         // http://blog.csdn.net/xsl1990/article/details/17096501 
  26.         scale_in = new ScaleAnimation(0.0f, 1.0f, 0.0f, 1.0f, 
  27.                 Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 
  28.                 0.5f); 
  29.         scale_out = new ScaleAnimation(1.0f, 3.0f, 1.0f, 3.0f, 
  30.                 Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 
  31.                 0.5f); 
  32.  
  33.         // 缩放动画,起始x轴的缩放为0,y轴的缩放为0,动画后,x,y轴大小与图像尺寸相同 
  34.         // x,y可以把它当做宽度和高度 
  35.         new_scale_in = new ScaleAnimation(0.0f, 1.0f, 0.0f, 1.0f, 
  36.                 Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 
  37.                 0.5f); 
  38.  
  39.         new_scale_in.setDuration(200); 
  40.  
  41.         // 透明度的动画 
  42.         fade_in = new AlphaAnimation(0.0f, 1.0f); 
  43.         fade_out = new AlphaAnimation(1.0f, 0.0f); 
  44.  
  45.         scale_in.setDuration(150); 
  46.         scale_out.setDuration(150); 
  47.         fade_in.setDuration(150); 
  48.         fade_out.setDuration(150); 
  49.  
  50.         // 进入的动画集 
  51.         in.addAnimation(scale_in); 
  52.         in.addAnimation(fade_in); 
  53.         // 退出的动画集 
  54.         out.addAnimation(fade_out); 
  55.         out.addAnimation(scale_out); 
  56.  
  57.         out.setAnimationListener(new AnimationListener() { 
  58.  
  59.             @Override 
  60.             public void onAnimationStart(Animation animation) { 
  61.                 // TODO Auto-generated method stub 
  62.                 System.out.println("print this"); 
  63.             } 
  64.  
  65.             @Override 
  66.             public void onAnimationRepeat(Animation animation) { 
  67.                 // TODO Auto-generated method stub 
  68.  
  69.             } 
  70.  
  71.             @Override 
  72.             public void onAnimationEnd(Animation animation) { 
  73.                 // TODO Auto-generated method stub 
  74.  
  75.                 buttonimage.setVisibility(View.GONE); 
  76.                 buttonimage.setImageBitmap(second_icon_bmp); 
  77.                 buttonimage.setVisibility(View.VISIBLE); 
  78.                 buttonimage.startAnimation(in); 
  79.                 full_circle_image.setVisibility(View.VISIBLE); 
  80.                 cusView.setVisibility(View.VISIBLE); 
  81.  
  82.                 flg_frmwrk_mode = 2
  83.  
  84.                 System.out.println("flg_frmwrk_mode" + flg_frmwrk_mode); 
  85.  
  86.             } 
  87.         }); 
  88.  
  89.         new_scale_in.setAnimationListener(new AnimationListener() { 
  90.  
  91.             @Override 
  92.             public void onAnimationStart(Animation animation) { 
  93.                 // TODO Auto-generated method stub 
  94.  
  95.             } 
  96.  
  97.             @Override 
  98.             public void onAnimationRepeat(Animation animation) { 
  99.                 // TODO Auto-generated method stub 
  100.  
  101.             } 
  102.  
  103.             @Override 
  104.             public void onAnimationEnd(Animation animation) { 
  105.                 // TODO Auto-generated method stub 
  106.                 cusView.setVisibility(View.GONE); 
  107.                 buttonimage.setVisibility(View.VISIBLE); 
  108.                 buttonimage.setImageBitmap(third_icon_bmp); 
  109.                 flg_frmwrk_mode = 3
  110.                 buttonimage.startAnimation(in); 
  111.  
  112.             } 
  113.         }); 
  114.  
  115.     } 

再接着是画出各个形状

  1. * 设置各个画面的路径 
  2.    */ 
  3.   private void iconCreate() { 
  4.  
  5.       // Creating icons using path 
  6.       // Create your own icons or feel free to use these 
  7.  
  8.       play = new Path(); 
  9.       play.moveTo(pix * 40 / 100, pix * 36 / 100); 
  10.       play.lineTo(pix * 40 / 100, pix * 63 / 100); 
  11.       play.lineTo(pix * 69 / 100, pix * 50 / 100); 
  12.       play.close(); 
  13.  
  14.       stop = new Path(); 
  15.       stop.moveTo(pix * 38 / 100, pix * 38 / 100); 
  16.       stop.lineTo(pix * 62 / 100, pix * 38 / 100); 
  17.       stop.lineTo(pix * 62 / 100, pix * 62 / 100); 
  18.       stop.lineTo(pix * 38 / 100, pix * 62 / 100); 
  19.       stop.close(); 
  20.  
  21.       download_triangle = new Path(); 
  22.       download_triangle.moveTo(pix * 375 / 1000, (pix / 2
  23.               + (pix * 625 / 10000) - (pix * 3 / 100)); 
  24.       download_triangle.lineTo(pix / 2, (pix * 625 / 1000
  25.               + (pix * 625 / 10000) - (pix * 3 / 100)); 
  26.       download_triangle.lineTo(pix * 625 / 1000, (pix / 2
  27.               + (pix * 625 / 10000) - (pix * 3 / 100)); 
  28.       download_triangle.close(); 
  29.  
  30.       download_rectangle = new Path(); 
  31.       download_rectangle.moveTo(pix * 4375 / 10000, (pix / 2
  32.               + (pix * 625 / 10000) - (pix * 3 / 100)); 
  33.       download_rectangle.lineTo(pix * 5625 / 10000, (pix / 2
  34.               + (pix * 625 / 10000) - (pix * 3 / 100)); 
  35.       download_rectangle.lineTo(pix * 5625 / 10000, (pix * 375 / 1000
  36.               + (pix * 625 / 10000) - (pix * 3 / 100)); 
  37.       download_rectangle.lineTo(pix * 4375 / 10000, (pix * 375 / 1000
  38.               + (pix * 625 / 10000) - (pix * 3 / 100)); 
  39.       download_rectangle.close(); 
  40.  
  41.       tick = new Path(); 
  42.       tick.moveTo(pix * 30 / 100, pix * 50 / 100); 
  43.       tick.lineTo(pix * 45 / 100, pix * 625 / 1000); 
  44.       tick.lineTo(pix * 65 / 100, pix * 350 / 1000); 
  45.  
  46.   } 
  47.  
  48.   /** 
  49.    * 创建各个bitmap添加到framelayout中 
  50.    */ 
  51.   public void init() { 
  52.  
  53.       // Defining and drawing bitmaps and assigning views to the layout 
  54.  
  55.       FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams( 
  56.               FrameLayout.LayoutParams.WRAP_CONTENT, 
  57.               FrameLayout.LayoutParams.WRAP_CONTENT); 
  58.  
  59.       lp.setMargins(10101010); 
  60.  
  61.       fillcircle.setVisibility(View.GONE); 
  62.  
  63.       Bitmap.Config conf = Bitmap.Config.ARGB_8888; // see other conf types 
  64.       Bitmap full_circle_bmp = Bitmap.createBitmap(pix, pix, conf); 
  65.       Bitmap fill_circle_bmp = Bitmap.createBitmap(pix, pix, conf); 
  66.  
  67.       first_icon_bmp = Bitmap.createBitmap(pix, pix, conf); // Bitmap to draw 
  68.                                                               // first icon( 
  69.                                                               // Default - 
  70.                                                               // Play ) 
  71.  
  72.       second_icon_bmp = Bitmap.createBitmap(pix, pix, conf); // Bitmap to draw 
  73.                                                               // second icon( 
  74.                                                               // Default - 
  75.                                                               // Stop ) 
  76.  
  77.       third_icon_bmp = Bitmap.createBitmap(pix, pix, conf); // Bitmap to draw 
  78.                                                               // third icon( 
  79.                                                               // Default - 
  80.                                                               // Tick ) 
  81.  
  82.       Canvas first_icon_canvas = new Canvas(first_icon_bmp); 
  83.       Canvas second_icon_canvas = new Canvas(second_icon_bmp); 
  84.       Canvas third_icon_canvas = new Canvas(third_icon_bmp); 
  85.       Canvas fill_circle_canvas = new Canvas(fill_circle_bmp); 
  86.       Canvas full_circle_canvas = new Canvas(full_circle_bmp); 
  87.       float startx = (float) (pix * 0.05); 
  88.       float endx = (float) (pix * 0.95); 
  89.       System.out.println("full circle " + full_circle_canvas.getWidth() 
  90.               + full_circle_canvas.getHeight()); 
  91.       float starty = (float) (pix * 0.05); 
  92.       float endy = (float) (pix * 0.95); 
  93.       rect = new RectF(startx, starty, endx, endy); 
  94.  
  95.       first_icon_canvas.drawPath(play, fill_color); // Draw second icon on 
  96.                                                       // canvas( Default - 
  97.                                                       // Stop ). 
  98.                                                       // *****Set your second 
  99.                                                       // icon here**** 
  100.  
  101.       second_icon_canvas.drawPath(stop, icon_color); // Draw second icon on 
  102.                                                       // canvas( Default - 
  103.                                                       // Stop ). 
  104.                                                       // *****Set your second 
  105.                                                       // icon here**** 
  106.  
  107.       third_icon_canvas.drawPath(tick, final_icon_color); // Draw second icon 
  108.                                                           // on canvas( 
  109.                                                           // Default - Stop ). 
  110.                                                           // *****Set your 
  111.                                                           // second icon 
  112.                                                           // here**** 
  113.  
  114.       full_circle_canvas.drawArc(rect, 0360false, stroke_color); 
  115.       fill_circle_canvas.drawArc(rect, 0360false, fill_color); 
  116.  
  117.       buttonimage.setImageBitmap(first_icon_bmp); 
  118.       flg_frmwrk_mode = 1
  119.       fillcircle.setImageBitmap(fill_circle_bmp); 
  120.       full_circle_image.setImageBitmap(full_circle_bmp); 
  121.  
  122.       cusView.setVisibility(View.GONE); 
  123.  
  124.       addView(full_circle_image, lp); 
  125.       addView(fillcircle, lp); 
  126.       addView(buttonimage, lp); 
  127.       addView(cusView, lp); 
  128.  
  129.   } 

***加上点击按钮时各个状态切换的逻辑关系,这个按钮的布局就完成了。

 

附上整个类的代码

 

 

 

  1. package com.example.mybutton; 
  2.  
  3. import android.content.Context; 
  4. import android.graphics.Bitmap; 
  5. import android.graphics.Canvas; 
  6. import android.graphics.Color; 
  7. import android.graphics.Paint; 
  8. import android.graphics.Path; 
  9. import android.graphics.RectF; 
  10. import android.util.AttributeSet; 
  11. import android.util.DisplayMetrics; 
  12. import android.view.View; 
  13. import android.view.View.OnClickListener; 
  14. import android.view.animation.AccelerateDecelerateInterpolator; 
  15. import android.view.animation.AlphaAnimation; 
  16. import android.view.animation.Animation; 
  17. import android.view.animation.AnimationSet; 
  18. import android.view.animation.ScaleAnimation; 
  19. import android.view.animation.Animation.AnimationListener; 
  20. import android.widget.FrameLayout; 
  21. import android.widget.ImageView; 
  22.  
  23. public class ButtonLayout extends FrameLayout implements OnClickListener { 
  24.  
  25.     public CusImage cusView; 
  26.     public int pix = 0
  27.     public RectF rect; 
  28.     // 图像视图 
  29.     // ImageView类可以加载各种来源的图片(如资源或图片库),需要计算图像的尺寸,比便它可以在其他布局中使用,并提供例如缩放和着色(渲染)各种显示选项。 
  30.     private ImageView circle_image, buttonimage, fillcircle, full_circle_image; 
  31.  
  32.     // 可以用他来画几何图形、画曲线、画基于路径的文本。这是个绘图的路径类 
  33.     private Path stop, tick, play, download_triangle, download_rectangle; 
  34.  
  35.     // 位图类 
  36.     private Bitmap third_icon_bmp, second_icon_bmp, first_icon_bmp; 
  37.  
  38.     // 画笔类 
  39.     private Paint stroke_color, fill_color, icon_color, final_icon_color; 
  40.  
  41.     // AnimationSet类是Android系统中的动画集合类,用于控制View对象进行多个动作的组合,该类继承于Animation类 
  42.     private AnimationSet in, out; 
  43.  
  44.     // RotateAnimation类是Android系统中的旋转变化动画类,用于控制View对象的旋转动作,该类继承于Animation类 
  45.     // private RotateAnimation arcRotation; 
  46.  
  47.     // 缩放动画类 
  48.     private ScaleAnimation new_scale_in, scale_in, scale_out; 
  49.  
  50.     // 透明度动画 
  51.     private AlphaAnimation fade_in, fade_out; 
  52.  
  53.     public int flg_frmwrk_mode = 0
  54.     boolean first_click = false
  55.  
  56.     public ButtonLayout(Context context, AttributeSet attrs) { 
  57.         super(context, attrs); 
  58.         setOnClickListener(this); 
  59.  
  60.         initialise(); 
  61.         setpaint(); 
  62.         setAnimation(); 
  63.         displayMetrics(); 
  64.         iconCreate(); 
  65.         init(); 
  66.         // TODO Auto-generated constructor stub 
  67.     } 
  68.  
  69.     public ButtonLayout(Context context) { 
  70.         super(context); 
  71.         setOnClickListener(this); 
  72.         setBackgroundColor(Color.CYAN); 
  73.         initialise(); 
  74.         setpaint(); 
  75.         setAnimation(); 
  76.         displayMetrics(); 
  77.         iconCreate(); 
  78.         init(); 
  79.     } 
  80.  
  81.     /** 
  82.      * 创建各个控件 
  83.      */ 
  84.     private void initialise() { 
  85.         // 按钮的进度条 
  86.         cusView = new CusImage(getContext(), this); 
  87.         // 按钮中间的形状 
  88.         buttonimage = new ImageView(getContext()); 
  89.         // 完成进度后显示的图像 
  90.         fillcircle = new ImageView(getContext()); 
  91.         //外面一圈圆 
  92.         full_circle_image = new ImageView(getContext()); 
  93.         // 设置控件不接受点击事件 
  94.         cusView.setClickable(false); 
  95.         buttonimage.setClickable(false); 
  96.         fillcircle.setClickable(false); 
  97.         full_circle_image.setClickable(false); 
  98.  
  99.         setClickable(true); 
  100.  
  101.     } 
  102.  
  103.     /** 
  104.      * 设置各类画笔 
  105.      */ 
  106.     private void setpaint() { 
  107.  
  108.         // Setting up color 
  109.         // Paint.ANTI_ALIAS_FLAG是使位图抗锯齿的标志 
  110.         stroke_color = new Paint(Paint.ANTI_ALIAS_FLAG); 
  111.         stroke_color.setAntiAlias(true); 
  112.         stroke_color.setColor(Color.rgb(0161234)); // Edit this to change 
  113.         stroke_color.setStrokeWidth(3); 
  114.         stroke_color.setStyle(Paint.Style.STROKE); 
  115.  
  116.         icon_color = new Paint(Paint.ANTI_ALIAS_FLAG); 
  117.         icon_color.setColor(Color.rgb(0161234)); 
  118.         // 填充 
  119.         icon_color.setStyle(Paint.Style.FILL_AND_STROKE); // Edit this to change 
  120.         icon_color.setAntiAlias(true); 
  121.  
  122.         final_icon_color = new Paint(Paint.ANTI_ALIAS_FLAG); 
  123.         final_icon_color.setColor(Color.WHITE); // Edit this to change the final 
  124.         final_icon_color.setStrokeWidth(12); 
  125.         final_icon_color.setStyle(Paint.Style.STROKE); 
  126.         final_icon_color.setAntiAlias(true); 
  127.  
  128.         fill_color = new Paint(Paint.ANTI_ALIAS_FLAG); 
  129.         fill_color.setColor(Color.rgb(0161234)); // Edit this to change the 
  130.         fill_color.setStyle(Paint.Style.FILL_AND_STROKE); 
  131.         fill_color.setAntiAlias(true); 
  132.  
  133.     } 
  134.  
  135.     /** 
  136.      * 设置动画及动画监听器 
  137.      */ 
  138.     private void setAnimation() { 
  139.  
  140.         // Setting up and defining view animations. 
  141.  
  142.         // http://blog.csdn.net/congqingbin/article/details/7889778 
  143.         // RELATIVE_TO_PARENT:与父控件的的中心为重点;RELATIVE_TO_SELF以自己为中心 
  144.         // 左上角 分别为0.0f 0.0f 中心点为0.5f,0.5f 右下角1.0f,1.0f 
  145.         /* 
  146.          * arcRotation = new RotateAnimation(0.0f, 360.0f, 
  147.          * Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); 
  148.          */ 
  149.         // 持续时间1000ms 
  150.         // arcRotation.setDuration(500); 
  151.  
  152.         in = new AnimationSet(true); 
  153.         out = new AnimationSet(true); 
  154.  
  155.         // http://blog.csdn.net/jason0539/article/details/16370405 
  156.         out.setInterpolator(new AccelerateDecelerateInterpolator()); 
  157.         in.setInterpolator(new AccelerateDecelerateInterpolator()); 
  158.  
  159.         // http://blog.csdn.net/xsl1990/article/details/17096501 
  160.         scale_in = new ScaleAnimation(0.0f, 1.0f, 0.0f, 1.0f, 
  161.                 Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 
  162.                 0.5f); 
  163.         scale_out = new ScaleAnimation(1.0f, 3.0f, 1.0f, 3.0f, 
  164.                 Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 
  165.                 0.5f); 
  166.  
  167.         // 缩放动画,起始x轴的缩放为0,y轴的缩放为0,动画后,x,y轴大小与图像尺寸相同 
  168.         // x,y可以把它当做宽度和高度 
  169.         new_scale_in = new ScaleAnimation(0.0f, 1.0f, 0.0f, 1.0f, 
  170.                 Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 
  171.                 0.5f); 
  172.  
  173.         new_scale_in.setDuration(200); 
  174.  
  175.         // 透明度的动画 
  176.         fade_in = new AlphaAnimation(0.0f, 1.0f); 
  177.         fade_out = new AlphaAnimation(1.0f, 0.0f); 
  178.  
  179.         scale_in.setDuration(150); 
  180.         scale_out.setDuration(150); 
  181.         fade_in.setDuration(150); 
  182.         fade_out.setDuration(150); 
  183.  
  184.         // 进入的动画集 
  185.         in.addAnimation(scale_in); 
  186.         in.addAnimation(fade_in); 
  187.         // 退出的动画集 
  188.         out.addAnimation(fade_out); 
  189.         out.addAnimation(scale_out); 
  190.  
  191.         out.setAnimationListener(new AnimationListener() { 
  192.  
  193.             @Override 
  194.             public void onAnimationStart(Animation animation) { 
  195.                 // TODO Auto-generated method stub 
  196.                 System.out.println("print this"); 
  197.             } 
  198.  
  199.             @Override 
  200.             public void onAnimationRepeat(Animation animation) { 
  201.                 // TODO Auto-generated method stub 
  202.  
  203.             } 
  204.  
  205.             @Override 
  206.             public void onAnimationEnd(Animation animation) { 
  207.                 // TODO Auto-generated method stub 
  208.  
  209.                 buttonimage.setVisibility(View.GONE); 
  210.                 buttonimage.setImageBitmap(second_icon_bmp); 
  211.                 buttonimage.setVisibility(View.VISIBLE); 
  212.                 buttonimage.startAnimation(in); 
  213.                 full_circle_image.setVisibility(View.VISIBLE); 
  214.                 cusView.setVisibility(View.VISIBLE); 
  215.  
  216.                 flg_frmwrk_mode = 2
  217.  
  218.                 System.out.println("flg_frmwrk_mode" + flg_frmwrk_mode); 
  219.  
  220.             } 
  221.         }); 
  222.  
  223.         new_scale_in.setAnimationListener(new AnimationListener() { 
  224.  
  225.             @Override 
  226.             public void onAnimationStart(Animation animation) { 
  227.                 // TODO Auto-generated method stub 
  228.  
  229.             } 
  230.  
  231.             @Override 
  232.             public void onAnimationRepeat(Animation animation) { 
  233.                 // TODO Auto-generated method stub 
  234.  
  235.             } 
  236.  
  237.             @Override 
  238.             public void onAnimationEnd(Animation animation) { 
  239.                 // TODO Auto-generated method stub 
  240.                 cusView.setVisibility(View.GONE); 
  241.                 buttonimage.setVisibility(View.VISIBLE); 
  242.                 buttonimage.setImageBitmap(third_icon_bmp); 
  243.                 flg_frmwrk_mode = 3
  244.                 buttonimage.startAnimation(in); 
  245.  
  246.             } 
  247.         }); 
  248.  
  249.     } 
  250.  
  251.     /** 
  252.      * 设置自定义控件的大小 
  253.      */ 
  254.     private void displayMetrics() { 
  255.         // Responsible for calculating the size of views and canvas based upon 
  256.         // screen resolution. 
  257.         DisplayMetrics metrics = getContext().getResources() 
  258.                 .getDisplayMetrics(); 
  259.         int width = metrics.widthPixels; 
  260.         int height = metrics.heightPixels; 
  261.         float scarea = width * height; 
  262.         pix = (int) Math.sqrt(scarea * 0.0217); 
  263.  
  264.     } 
  265.  
  266.     /** 
  267.      * 设置各个画面的路径 
  268.      */ 
  269.     private void iconCreate() { 
  270.  
  271.         // Creating icons using path 
  272.         // Create your own icons or feel free to use these 
  273.  
  274.         play = new Path(); 
  275.         play.moveTo(pix * 40 / 100, pix * 36 / 100); 
  276.         play.lineTo(pix * 40 / 100, pix * 63 / 100); 
  277.         play.lineTo(pix * 69 / 100, pix * 50 / 100); 
  278.         play.close(); 
  279.  
  280.         stop = new Path(); 
  281.         stop.moveTo(pix * 38 / 100, pix * 38 / 100); 
  282.         stop.lineTo(pix * 62 / 100, pix * 38 / 100); 
  283.         stop.lineTo(pix * 62 / 100, pix * 62 / 100); 
  284.         stop.lineTo(pix * 38 / 100, pix * 62 / 100); 
  285.         stop.close(); 
  286.  
  287.         download_triangle = new Path(); 
  288.         download_triangle.moveTo(pix * 375 / 1000, (pix / 2
  289.                 + (pix * 625 / 10000) - (pix * 3 / 100)); 
  290.         download_triangle.lineTo(pix / 2, (pix * 625 / 1000
  291.                 + (pix * 625 / 10000) - (pix * 3 / 100)); 
  292.         download_triangle.lineTo(pix * 625 / 1000, (pix / 2
  293.                 + (pix * 625 / 10000) - (pix * 3 / 100)); 
  294.         download_triangle.close(); 
  295.  
  296.         download_rectangle = new Path(); 
  297.         download_rectangle.moveTo(pix * 4375 / 10000, (pix / 2
  298.                 + (pix * 625 / 10000) - (pix * 3 / 100)); 
  299.         download_rectangle.lineTo(pix * 5625 / 10000, (pix / 2
  300.                 + (pix * 625 / 10000) - (pix * 3 / 100)); 
  301.         download_rectangle.lineTo(pix * 5625 / 10000, (pix * 375 / 1000
  302.                 + (pix * 625 / 10000) - (pix * 3 / 100)); 
  303.         download_rectangle.lineTo(pix * 4375 / 10000, (pix * 375 / 1000
  304.                 + (pix * 625 / 10000) - (pix * 3 / 100)); 
  305.         download_rectangle.close(); 
  306.  
  307.         tick = new Path(); 
  308.         tick.moveTo(pix * 30 / 100, pix * 50 / 100); 
  309.         tick.lineTo(pix * 45 / 100, pix * 625 / 1000); 
  310.         tick.lineTo(pix * 65 / 100, pix * 350 / 1000); 
  311.  
  312.     } 
  313.  
  314.     /** 
  315.      * 创建各个bitmap添加到framelayout中 
  316.      */ 
  317.     public void init() { 
  318.  
  319.         // Defining and drawing bitmaps and assigning views to the layout 
  320.  
  321.         FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams( 
  322.                 FrameLayout.LayoutParams.WRAP_CONTENT, 
  323.                 FrameLayout.LayoutParams.WRAP_CONTENT); 
  324.  
  325.         lp.setMargins(10101010); 
  326.  
  327.         fillcircle.setVisibility(View.GONE); 
  328.  
  329.         Bitmap.Config conf = Bitmap.Config.ARGB_8888; // see other conf types 
  330.         Bitmap full_circle_bmp = Bitmap.createBitmap(pix, pix, conf); 
  331.         Bitmap fill_circle_bmp = Bitmap.createBitmap(pix, pix, conf); 
  332.  
  333.         first_icon_bmp = Bitmap.createBitmap(pix, pix, conf); // Bitmap to draw 
  334.                                                                 // first icon( 
  335.                                                                 // Default - 
  336.                                                                 // Play ) 
  337.  
  338.         second_icon_bmp = Bitmap.createBitmap(pix, pix, conf); // Bitmap to draw 
  339.                                                                 // second icon( 
  340.                                                                 // Default - 
  341.                                                                 // Stop ) 
  342.  
  343.         third_icon_bmp = Bitmap.createBitmap(pix, pix, conf); // Bitmap to draw 
  344.                                                                 // third icon( 
  345.                                                                 // Default - 
  346.                                                                 // Tick ) 
  347.  
  348.         Canvas first_icon_canvas = new Canvas(first_icon_bmp); 
  349.         Canvas second_icon_canvas = new Canvas(second_icon_bmp); 
  350.         Canvas third_icon_canvas = new Canvas(third_icon_bmp); 
  351.         Canvas fill_circle_canvas = new Canvas(fill_circle_bmp); 
  352.         Canvas full_circle_canvas = new Canvas(full_circle_bmp); 
  353.         float startx = (float) (pix * 0.05); 
  354.         float endx = (float) (pix * 0.95); 
  355.         System.out.println("full circle " + full_circle_canvas.getWidth() 
  356.                 + full_circle_canvas.getHeight()); 
  357.         float starty = (float) (pix * 0.05); 
  358.         float endy = (float) (pix * 0.95); 
  359.         rect = new RectF(startx, starty, endx, endy); 
  360.  
  361.         first_icon_canvas.drawPath(play, fill_color); // Draw second icon on 
  362.                                                         // canvas( Default - 
  363.                                                         // Stop ). 
  364.                                                         // *****Set your second 
  365.                                                         // icon here**** 
  366.  
  367.         second_icon_canvas.drawPath(stop, icon_color); // Draw second icon on 
  368.                                                         // canvas( Default - 
  369.                                                         // Stop ). 
  370.                                                         // *****Set your second 
  371.                                                         // icon here**** 
  372.  
  373.         third_icon_canvas.drawPath(tick, final_icon_color); // Draw second icon 
  374.                                                             // on canvas( 
  375.                                                             // Default - Stop ). 
  376.                                                             // *****Set your 
  377.                                                             // second icon 
  378.                                                             // here**** 
  379.  
  380.         full_circle_canvas.drawArc(rect, 0360false, stroke_color); 
  381.         fill_circle_canvas.drawArc(rect, 0360false, fill_color); 
  382.  
  383.         buttonimage.setImageBitmap(first_icon_bmp); 
  384.         flg_frmwrk_mode = 1
  385.         fillcircle.setImageBitmap(fill_circle_bmp); 
  386.         full_circle_image.setImageBitmap(full_circle_bmp); 
  387.  
  388.         cusView.setVisibility(View.GONE); 
  389.  
  390.         addView(full_circle_image, lp); 
  391.         addView(fillcircle, lp); 
  392.         addView(buttonimage, lp); 
  393.         addView(cusView, lp); 
  394.  
  395.     } 
  396.  
  397.     public void animation() { 
  398.  
  399.         // Starting view animation and setting flag values 
  400.  
  401.         if (flg_frmwrk_mode == 1) { 
  402.             //full_circle_image.setVisibility(View.GONE); 
  403.             buttonimage.startAnimation(out); 
  404.         } 
  405.  
  406.     } 
  407.  
  408.     public void finalAnimation() { 
  409.  
  410.         // Responsible for final fill up animation 
  411.  
  412.         buttonimage.setVisibility(View.GONE); 
  413.         fillcircle.setVisibility(View.VISIBLE); 
  414.         fillcircle.startAnimation(new_scale_in); 
  415.  
  416.     } 
  417.  
  418.     public void stop() { 
  419.  
  420.         // Responsible for resetting the state of view when Stop is clicked 
  421.  
  422.         cusView.reset(); 
  423.         buttonimage.setImageBitmap(first_icon_bmp); 
  424.         flg_frmwrk_mode = 1
  425.  
  426.     } 
  427.  
  428.     @Override 
  429.     public void onClick(View v) { 
  430.         // TODO Auto-generated method stub 
  431.         animation(); 
  432.     } 
  433.  

按钮做好了我们可以在Activity中调用它了

 

首先是写入到布局文件中

 

  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
  2.     xmlns:tools="http://schemas.android.com/tools" 
  3.     android:layout_width="match_parent" 
  4.     android:layout_height="match_parent" 
  5.      
  6.      > 
  7.  
  8.     <com.example.mybutton.ButtonLayout 
  9.         android:id="@+id/ButtonLayout01" 
  10.         android:layout_width="wrap_content" 
  11.         android:layout_height="wrap_content" 
  12.         android:layout_centerHorizontal="true" 
  13.         android:layout_centerVertical="true" 
  14.         android:clickable="true" > 
  15.     </com.example.mybutton.ButtonLayout> 
  16.  
  17. </RelativeLayout> 

然后在activity中设置

  1.  public class MainActivity extends Activity { 
  2.   2  
  3.   3     private static ButtonLayout buttonLayout; 
  4.   4  
  5.   5     @Override 
  6.   6     protected void onCreate(Bundle savedInstanceState) { 
  7.   7         super.onCreate(savedInstanceState); 
  8.   8         setContentView(R.layout.activity_main); 
  9.   9         buttonLayout = (ButtonLayout) findViewById(R.id.ButtonLayout01); 
  10.  10         buttonLayout.setOnClickListener(new OnClickListener() { 
  11.  11  
  12.  12             @Override 
  13.  13             public void onClick(View v) { 
  14.  14                 // TODO Auto-generated method stub 
  15.  15                 buttonLayout.animation(); // Need to call this method for 
  16.  16                 // animation and progression 
  17.  17  
  18.  18                 if (buttonLayout.flg_frmwrk_mode == 1) { 
  19.  19  
  20.  20                     // Start state. Call any method that you want to execute 
  21.  21  
  22.  22                     runOnUiThread(new Runnable() { 
  23.  23  
  24.  24                         @Override 
  25.  25                         public void run() { 
  26.  26                             // TODO Auto-generated method stub 
  27.  27                             Toast.makeText(MainActivity.this
  28.  28                                     "Starting download", Toast.LENGTH_SHORT) 
  29.  29                                     .show(); 
  30.  30                         } 
  31.  31                     }); 
  32.  32                     new DownLoadSigTask().execute(); 
  33.  33                 } 
  34.  34                 if (buttonLayout.flg_frmwrk_mode == 2) { 
  35.  35  
  36.  36                     // Running state. Call any method that you want to execute 
  37.  37  
  38.  38                     new DownLoadSigTask().cancel(true); 
  39.  39                     buttonLayout.stop(); 
  40.  40                     runOnUiThread(new Runnable() { 
  41.  41  
  42.  42                         @Override 
  43.  43                         public void run() { 
  44.  44                             // TODO Auto-generated method stub 
  45.  45                             Toast.makeText(MainActivity.this
  46.  46                                     "Download stopped", Toast.LENGTH_SHORT) 
  47.  47                                     .show(); 
  48.  48                         } 
  49.  49                     }); 
  50.  50                 } 
  51.  51                 if (buttonLayout.flg_frmwrk_mode == 3) { 
  52.  52  
  53.  53                     // End state. Call any method that you want to execute. 
  54.  54  
  55.  55                     runOnUiThread(new Runnable() { 
  56.  56  
  57.  57                         @Override 
  58.  58                         public void run() { 
  59.  59                             // TODO Auto-generated method stub 
  60.  60                             Toast.makeText(MainActivity.this
  61.  61                                     "Download complete", Toast.LENGTH_SHORT) 
  62.  62                                     .show(); 
  63.  63                         } 
  64.  64                     }); 
  65.  65                 } 
  66.  66             } 
  67.  67  
  68.  68         }); 
  69.  69     } 
  70.  70  
  71.  71     static class DownLoadSigTask extends AsyncTask<String, Integer, String> { 
  72.  72  
  73.  73         @Override 
  74.  74         protected void onPreExecute() { 
  75.  75  
  76.  76         } 
  77.  77  
  78.  78         @Override 
  79.  79         protected String doInBackground(final String... args) { 
  80.  80  
  81.  81             // Creating dummy task and updating progress 
  82.  82  
  83.  83             for (int i = 0; i <= 100;) { 
  84.  84                 try { 
  85.  85                     Thread.sleep(50); 
  86.  86  
  87.  87                 } catch (InterruptedException e) { 
  88.  88  
  89.  89                     e.printStackTrace(); 
  90.  90                 } 
  91.  91                 if (buttonLayout.flg_frmwrk_mode == 2 &&i<=100){ 
  92.  92                     i++; 
  93.  93                     publishProgress(i); 
  94.  94                 } 
  95.  95             } 
  96.  96  
  97.  97             return null
  98.  98         } 
  99.  99  
  100. 100         @Override 
  101. 101         protected void onProgressUpdate(Integer... progress) { 
  102. 102  
  103. 103             // publishing progress to progress arc 
  104. 104  
  105. 105             buttonLayout.cusView.setupprogress(progress[0]); 
  106. 106         } 
  107. 107  
  108. 108     } 
  109. 109  
  110. 110 } 

三、结束语

这个按钮我是仿照一个开源项目写的,它的地址是https://github.com/torryharris/TH-ProgressButton。

我在代码中掺杂了一些网址,这些都是我在看这整个开源代码时查阅的资料,如果你也不懂的话也可以去这些地址看看资料。

说实话,自定义控件设计的东西太多,不适合在入门的时候学习,不过有个概念,以此来抛砖引玉也是挺好的。

接下来不久的时间内我也会把今天遇到的一些概念,比如说animation,path,canvas一一介绍下来的。

那么今天到此结束~

责任编辑:chenqingxiang 来源: cnblogs
相关推荐

2009-08-05 17:03:37

C#自定义控件

2015-02-11 17:49:35

Android源码自定义控件

2009-08-10 14:16:59

ASP.NET自定义控

2009-06-08 20:13:36

Eclipse自定义控

2013-04-19 10:14:24

2010-08-05 09:05:14

Flex Button

2015-01-22 15:59:07

Android源码日期时间控件SelectTime

2010-01-19 10:12:39

VB.NET Butt

2017-02-17 09:37:12

Android自定义控件方法总结

2009-09-03 13:34:03

.NET自定义控件

2009-08-03 13:34:06

自定义C#控件

2009-08-03 13:39:46

C#自定义用户控件

2009-08-06 09:18:01

ASP.NET自定义控ASP.NET控件开发

2009-08-06 17:13:56

ASP.NET自定义控

2021-08-25 10:14:51

鸿蒙HarmonyOS应用

2009-02-10 12:55:39

自定义控件AJAX.NET

2011-07-05 18:51:51

QT 控件 鼠标

2021-08-16 14:45:38

鸿蒙HarmonyOS应用

2017-04-21 14:27:21

Android控件QQ未读消息

2011-06-20 16:03:03

Qt 控件 鼠标
点赞
收藏

51CTO技术栈公众号