【Android的从零单排开发日记】之入门篇(十四)——Button控件+自定义Button控件

    好久不见,又是一个新的学期开始了,为什么我感觉好惆怅啊!这一周也发生了不少事情,节假日放了三天的假(好久没有这么悠闲过了),实习公司那边被组长半强制性的要求去解决一个后台登陆的问题,结果就是把Android这块放在一边了,滚去看PHP的后台框架了(人家只是一个Android实习生,不带这么玩的),学校那边老师布置了一个hibernate的项目,还说我给你们一个月时间,慢慢看,慢慢学习(结果就是在群上发了一大堆的hibernate的视频教程,还真的是慢慢看慢慢学习了,而且视频还是极老的,hibernate还是版本3),遇到这种老师我也是醉了。顺便求点hibernate的教程,简单易上手最好了。〈(_ _)〉

    好了,进入正题吧,今天要做的是button这个控件。按钮在窗口应用程序中是最常见的控件了,也算是程序与用户进行交互的常见手段了。按钮触发的事件处理,我们称为Evenr Handler,而在Android中,按钮事件是由系统的Button.OnClickListener所控制。那么接下来先看看最基本的button控件是怎么实现的。

 

一、基本Button控件

  1. 首先第一步就是往布局文件里拖一个Button控件,当然自己码出来也可以。XML布局如下
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    
        xmlns:tools="http://schemas.android.com/tools"
    
        android:layout_width="match_parent"
    
        android:layout_height="match_parent"
    
        
    
         >
    
    
    
        <Button
    
            android:id="@+id/button1"             <!-- button按钮的id号,程序通过这个id号来查找相应的控件 -->
    
            android:layout_width="wrap_content"   <!-- button按钮的宽度 当前意思是 根据内容自动拉伸,其他的还有match_parent,表示根据父控件来调整大小-->
    
            android:layout_height="wrap_content"  <!-- button按钮的长度-->
    
            android:layout_alignParentTop="true"  <!-- RelativeLayout布局中,将控件的上边缘和父控件的上边缘对齐 -->
    
            android:layout_centerHorizontal="true"<!-- RelativeLayout布局中,水平居中的意思 -->
    
            android:layout_marginTop="150dp"      <!-- RelativeLayout布局中,距离父控件顶端的距离 -->
    
            android:text="Button" />              <!-- button按钮上显示的文字信息 -->
    
    
    
    </RelativeLayout>

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

  2. 然后再在程序中调用它
    public class MainActivity extends Activity {
    
        
    
        private Button myButton;
    
    
    
        @Override
    
        protected void onCreate(Bundle savedInstanceState) {
    
            super.onCreate(savedInstanceState);
    
            setContentView(R.layout.activity_main);
    
            //通过id寻找控件,记得寻找控件前一定要先设置好布局文件
    
            myButton = (Button)findViewById(R.id.button1);
    
            myButton.setOnClickListener(new OnClickListener() {
    
                
    
                @Override
    
                public void onClick(View v) {
    
                    // TODO Auto-generated method stub
    
                    //这里填写单击按钮后要执行的事件
    
                }
    
                
    
            });
    
            myButton.setOnTouchListener(new OnTouchListener(){...});//设置触碰到按钮的监听器
    
            myButton.setOnLongClickListener(new OnLongClickListener(){...});//设置长按按钮的监听器
    
            myButton.setOnHoverListener(new OnHoverListener(){...});//设置界面覆盖按钮时的监听器
    
            //还有其它的的监听器,我们可以根据不同的需求来调用相应的监听器
    
        }
    
    
    
    
    
    }

    或者这样设置监听器

    public class MainActivity extends Activity implements OnClickListener{
    
        
    
        private Button myButton;
    
    
    
        @Override
    
        protected void onCreate(Bundle savedInstanceState) {
    
            super.onCreate(savedInstanceState);
    
            setContentView(R.layout.activity_main);
    
            //寻找控件,记得寻找控件前一定要先设置好布局文件
    
            myButton = (Button)findViewById(R.id.button1);
    
            myButton.setOnClickListener(this);
    
                
    
    
    
        }
    
    
    
        @Override
    
        public void onClick(View v) {
    
            // TODO Auto-generated method stub
    
            //获取点击的View
    
            switch(v.getId()){
    
            //根据View的id来进行相关操作
    
            case R.id.button1:
    
                //按钮点击时处理相关的事件
    
                break;
    
            }
    
        }
    
    
    
    
    
    }

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

二、自定义按钮

我们先来看看效果图吧

【Android的从零单排开发日记】之入门篇(十四)——Button控件+自定义Button控件

 

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

  1. 拆分这个按钮。仔细观察上面的效果图,我们可以把这个按钮分成3个部分,首先是最简单的外面一圈圆,基本上画出个圆放在那里就行了。接着是中间的三角形,正方形以及完成的勾,这个我们可以使用view里的画图类勾勒出来,再使用简单的动画Animation来切换。最后的一部分是覆盖在圆圈上的不断在表示进度的圆圈,这个我们可以不断调用这个view的ondraw来刷新进度。这就是整个按钮的设计思路。我们来看看实际的代码吧。
  2. 首先是表示进度的圆圈,我们来新建一个CusImage继承view类,实时的传入进度参数。
    package com.example.mybutton;
    
    
    
    import android.annotation.SuppressLint;
    
    import android.content.Context;
    
    import android.graphics.Canvas;
    
    import android.graphics.Color;
    
    import android.graphics.Paint;
    
    import android.graphics.RectF;
    
    import android.util.AttributeSet;
    
    import android.util.DisplayMetrics;
    
    import android.util.Log;
    
    import android.view.View;
    
    
    
    @SuppressLint("ViewConstructor") 
    
    public class CusImage extends View {
    
    
    
        private ButtonLayout b;
    
        private Paint myPaint;
    
        private float startAngle, sweepAngle;
    
        private RectF rect;
    
        // 默认控件大小
    
        private int pix = 160;
    
    
    
        public CusImage(Context context, ButtonLayout b) {
    
            super(context);
    
            this.b = b;
    
            init();
    
            // TODO Auto-generated constructor stub
    
        }
    
    
    
        public CusImage(Context context, AttributeSet attrs, ButtonLayout b) {
    
            super(context, attrs);
    
            this.b = b;
    
            init();
    
            // TODO Auto-generated constructor stub
    
        }
    
    
    
        private void init() {
    
            myPaint = new Paint();
    
            DisplayMetrics metrics = getContext().getResources()
    
                    .getDisplayMetrics();
    
            int width = metrics.widthPixels;
    
            int height = metrics.heightPixels;
    
            Log.d("TAG", width + "");
    
            Log.d("TAG", height + "");
    
            float scarea = width * height;
    
            pix = (int) Math.sqrt(scarea * 0.0217);
    
    
    
            //抗锯齿
    
            myPaint.setAntiAlias(true);
    
            //stroke表示空心,Fill表示实心
    
            myPaint.setStyle(Paint.Style.STROKE);
    
            //颜色
    
            myPaint.setColor(Color.rgb(0, 161, 234));
    
            //设置线条粗细
    
            myPaint.setStrokeWidth(7);
    
    
    
            float startx = (float) (pix * 0.05);
    
            float endx = (float) (pix * 0.95);
    
            float starty = (float) (pix * 0.05);
    
            float endy = (float) (pix * 0.95);
    
            //矩形区域
    
            rect = new RectF(startx, starty, endx, endy);
    
        }
    
    
    
        @Override
    
        protected void onDraw(Canvas canvas) {
    
            // 画弧线
    
            // 在rect这个区域内画,开始的角度,扫过的度数而不是结束的角度,false表示不与圆心连线,true通常用来画扇形,画笔。
    
            canvas.drawArc(rect, startAngle, sweepAngle, false, myPaint);
    
            startAngle = -90;
    
    
    
            //小于1圈
    
            if (sweepAngle < 360 &&b.flg_frmwrk_mode == 2) {
    
                invalidate();
    
            }else if(b.flg_frmwrk_mode == 1){
    
                        
    
            }else {//扫完一圈,调用b.finalAnimation()
    
                sweepAngle = 0;
    
                startAngle = -90;
    
                b.finalAnimation();
    
    
    
            }
    
            super.onDraw(canvas);
    
        }
    
    
    
        /**
    
         * 控制控件的大小 http://blog.csdn.net/pi9nc/article/details/18764863
    
         **/
    
        @Override
    
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    
            int desiredWidth = pix;
    
            int desiredHeight = pix;
    
            int widthMode = MeasureSpec.getMode(widthMeasureSpec);
    
            int widthSize = MeasureSpec.getSize(widthMeasureSpec);
    
            int heightMode = MeasureSpec.getMode(heightMeasureSpec);
    
            int heightSize = MeasureSpec.getSize(heightMeasureSpec);
    
    
    
            int width;
    
            int height;
    
    
    
            // 如果控件宽度是指定大小,宽度为指定的尺寸
    
            if (widthMode == MeasureSpec.EXACTLY) {
    
                width = widthSize;
    
            } else if (widthMode == MeasureSpec.AT_MOST) { // 没有限制,默认内容大小
    
                width = Math.min(desiredWidth, widthSize);
    
            } else {
    
                width = desiredWidth;
    
            }
    
    
    
            // 如果控件高度是指定大小,高度为指定的尺寸
    
            if (heightMode == MeasureSpec.EXACTLY) {
    
                height = heightSize;
    
            } else if (heightMode == MeasureSpec.AT_MOST) {// 没有限制,默认内容大小
    
                height = Math.min(desiredHeight, heightSize);
    
            } else {
    
                height = desiredHeight;
    
            }
    
            // 设定控件大小
    
            setMeasuredDimension(width, height);
    
        }
    
        // 传入参数
    
        public void setupprogress(int progress) {
    
            sweepAngle = (float) (progress * 3.6);
    
        }
    
    
    
        public void reset() {
    
            startAngle = -90;
    
        }
    
    
    
    }

     

  3. 有了表示进度的view之后,我们要在一个viewgroup控件中组装各个部分来实现整个按钮,这里我用的是framelayout
    这里代码写在一起了,我把它们一个一个拎出来讲解。
    首先是ImageView的初始化
    /**
    
         * 创建各个控件
    
         */
    
        private void initialise() {
    
            // 按钮的进度条
    
            cusView = new CusImage(getContext(), this);
    
            // 按钮中间的形状
    
            buttonimage = new ImageView(getContext());
    
            // 完成进度后显示的图像
    
            fillcircle = new ImageView(getContext());
    
            //外面一圈圆
    
            full_circle_image = new ImageView(getContext());
    
            // 设置控件不接受点击事件
    
            cusView.setClickable(false);
    
            buttonimage.setClickable(false);
    
            fillcircle.setClickable(false);
    
            full_circle_image.setClickable(false);
    
    
    
            setClickable(true);
    
    
    
        }

    然后是设置动画

    /**
    
         * 设置动画及动画监听器
    
         */
    
        private void setAnimation() {
    
    
    
            // Setting up and defining view animations.
    
    
    
            // http://blog.csdn.net/congqingbin/article/details/7889778
    
            // RELATIVE_TO_PARENT:与父控件的的中心为重点;RELATIVE_TO_SELF以自己为中心
    
            // 左上角 分别为0.0f 0.0f 中心点为0.5f,0.5f 右下角1.0f,1.0f
    
            /*
    
             * arcRotation = new RotateAnimation(0.0f, 360.0f,
    
             * Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
    
             */
    
            // 持续时间1000ms
    
            // arcRotation.setDuration(500);
    
    
    
            in = new AnimationSet(true);
    
            out = new AnimationSet(true);
    
    
    
            // http://blog.csdn.net/jason0539/article/details/16370405
    
            out.setInterpolator(new AccelerateDecelerateInterpolator());
    
            in.setInterpolator(new AccelerateDecelerateInterpolator());
    
    
    
            // http://blog.csdn.net/xsl1990/article/details/17096501
    
            scale_in = new ScaleAnimation(0.0f, 1.0f, 0.0f, 1.0f,
    
                    Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
    
                    0.5f);
    
            scale_out = new ScaleAnimation(1.0f, 3.0f, 1.0f, 3.0f,
    
                    Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
    
                    0.5f);
    
    
    
            // 缩放动画,起始x轴的缩放为0,y轴的缩放为0,动画后,x,y轴大小与图像尺寸相同
    
            // x,y可以把它当做宽度和高度
    
            new_scale_in = new ScaleAnimation(0.0f, 1.0f, 0.0f, 1.0f,
    
                    Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
    
                    0.5f);
    
    
    
            new_scale_in.setDuration(200);
    
    
    
            // 透明度的动画
    
            fade_in = new AlphaAnimation(0.0f, 1.0f);
    
            fade_out = new AlphaAnimation(1.0f, 0.0f);
    
    
    
            scale_in.setDuration(150);
    
            scale_out.setDuration(150);
    
            fade_in.setDuration(150);
    
            fade_out.setDuration(150);
    
    
    
            // 进入的动画集
    
            in.addAnimation(scale_in);
    
            in.addAnimation(fade_in);
    
            // 退出的动画集
    
            out.addAnimation(fade_out);
    
            out.addAnimation(scale_out);
    
    
    
            out.setAnimationListener(new AnimationListener() {
    
    
    
                @Override
    
                public void onAnimationStart(Animation animation) {
    
                    // TODO Auto-generated method stub
    
                    System.out.println("print this");
    
                }
    
    
    
                @Override
    
                public void onAnimationRepeat(Animation animation) {
    
                    // TODO Auto-generated method stub
    
    
    
                }
    
    
    
                @Override
    
                public void onAnimationEnd(Animation animation) {
    
                    // TODO Auto-generated method stub
    
    
    
                    buttonimage.setVisibility(View.GONE);
    
                    buttonimage.setImageBitmap(second_icon_bmp);
    
                    buttonimage.setVisibility(View.VISIBLE);
    
                    buttonimage.startAnimation(in);
    
                    full_circle_image.setVisibility(View.VISIBLE);
    
                    cusView.setVisibility(View.VISIBLE);
    
    
    
                    flg_frmwrk_mode = 2;
    
    
    
                    System.out.println("flg_frmwrk_mode" + flg_frmwrk_mode);
    
    
    
                }
    
            });
    
    
    
            new_scale_in.setAnimationListener(new AnimationListener() {
    
    
    
                @Override
    
                public void onAnimationStart(Animation animation) {
    
                    // TODO Auto-generated method stub
    
    
    
                }
    
    
    
                @Override
    
                public void onAnimationRepeat(Animation animation) {
    
                    // TODO Auto-generated method stub
    
    
    
                }
    
    
    
                @Override
    
                public void onAnimationEnd(Animation animation) {
    
                    // TODO Auto-generated method stub
    
                    cusView.setVisibility(View.GONE);
    
                    buttonimage.setVisibility(View.VISIBLE);
    
                    buttonimage.setImageBitmap(third_icon_bmp);
    
                    flg_frmwrk_mode = 3;
    
                    buttonimage.startAnimation(in);
    
    
    
                }
    
            });
    
    
    
        }

    再接着是画出各个形状

    /**
    
         * 设置各个画面的路径
    
         */
    
        private void iconCreate() {
    
    
    
            // Creating icons using path
    
            // Create your own icons or feel free to use these
    
    
    
            play = new Path();
    
            play.moveTo(pix * 40 / 100, pix * 36 / 100);
    
            play.lineTo(pix * 40 / 100, pix * 63 / 100);
    
            play.lineTo(pix * 69 / 100, pix * 50 / 100);
    
            play.close();
    
    
    
            stop = new Path();
    
            stop.moveTo(pix * 38 / 100, pix * 38 / 100);
    
            stop.lineTo(pix * 62 / 100, pix * 38 / 100);
    
            stop.lineTo(pix * 62 / 100, pix * 62 / 100);
    
            stop.lineTo(pix * 38 / 100, pix * 62 / 100);
    
            stop.close();
    
    
    
            download_triangle = new Path();
    
            download_triangle.moveTo(pix * 375 / 1000, (pix / 2)
    
                    + (pix * 625 / 10000) - (pix * 3 / 100));
    
            download_triangle.lineTo(pix / 2, (pix * 625 / 1000)
    
                    + (pix * 625 / 10000) - (pix * 3 / 100));
    
            download_triangle.lineTo(pix * 625 / 1000, (pix / 2)
    
                    + (pix * 625 / 10000) - (pix * 3 / 100));
    
            download_triangle.close();
    
    
    
            download_rectangle = new Path();
    
            download_rectangle.moveTo(pix * 4375 / 10000, (pix / 2)
    
                    + (pix * 625 / 10000) - (pix * 3 / 100));
    
            download_rectangle.lineTo(pix * 5625 / 10000, (pix / 2)
    
                    + (pix * 625 / 10000) - (pix * 3 / 100));
    
            download_rectangle.lineTo(pix * 5625 / 10000, (pix * 375 / 1000)
    
                    + (pix * 625 / 10000) - (pix * 3 / 100));
    
            download_rectangle.lineTo(pix * 4375 / 10000, (pix * 375 / 1000)
    
                    + (pix * 625 / 10000) - (pix * 3 / 100));
    
            download_rectangle.close();
    
    
    
            tick = new Path();
    
            tick.moveTo(pix * 30 / 100, pix * 50 / 100);
    
            tick.lineTo(pix * 45 / 100, pix * 625 / 1000);
    
            tick.lineTo(pix * 65 / 100, pix * 350 / 1000);
    
    
    
        }
    
    
    
        /**
    
         * 创建各个bitmap添加到framelayout中
    
         */
    
        public void init() {
    
    
    
            // Defining and drawing bitmaps and assigning views to the layout
    
    
    
            FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
    
                    FrameLayout.LayoutParams.WRAP_CONTENT,
    
                    FrameLayout.LayoutParams.WRAP_CONTENT);
    
    
    
            lp.setMargins(10, 10, 10, 10);
    
    
    
            fillcircle.setVisibility(View.GONE);
    
    
    
            Bitmap.Config conf = Bitmap.Config.ARGB_8888; // see other conf types
    
            Bitmap full_circle_bmp = Bitmap.createBitmap(pix, pix, conf);
    
            Bitmap fill_circle_bmp = Bitmap.createBitmap(pix, pix, conf);
    
    
    
            first_icon_bmp = Bitmap.createBitmap(pix, pix, conf); // Bitmap to draw
    
                                                                    // first icon(
    
                                                                    // Default -
    
                                                                    // Play )
    
    
    
            second_icon_bmp = Bitmap.createBitmap(pix, pix, conf); // Bitmap to draw
    
                                                                    // second icon(
    
                                                                    // Default -
    
                                                                    // Stop )
    
    
    
            third_icon_bmp = Bitmap.createBitmap(pix, pix, conf); // Bitmap to draw
    
                                                                    // third icon(
    
                                                                    // Default -
    
                                                                    // Tick )
    
    
    
            Canvas first_icon_canvas = new Canvas(first_icon_bmp);
    
            Canvas second_icon_canvas = new Canvas(second_icon_bmp);
    
            Canvas third_icon_canvas = new Canvas(third_icon_bmp);
    
            Canvas fill_circle_canvas = new Canvas(fill_circle_bmp);
    
            Canvas full_circle_canvas = new Canvas(full_circle_bmp);
    
            float startx = (float) (pix * 0.05);
    
            float endx = (float) (pix * 0.95);
    
            System.out.println("full circle " + full_circle_canvas.getWidth()
    
                    + full_circle_canvas.getHeight());
    
            float starty = (float) (pix * 0.05);
    
            float endy = (float) (pix * 0.95);
    
            rect = new RectF(startx, starty, endx, endy);
    
    
    
            first_icon_canvas.drawPath(play, fill_color); // Draw second icon on
    
                                                            // canvas( Default -
    
                                                            // Stop ).
    
                                                            // *****Set your second
    
                                                            // icon here****
    
    
    
            second_icon_canvas.drawPath(stop, icon_color); // Draw second icon on
    
                                                            // canvas( Default -
    
                                                            // Stop ).
    
                                                            // *****Set your second
    
                                                            // icon here****
    
    
    
            third_icon_canvas.drawPath(tick, final_icon_color); // Draw second icon
    
                                                                // on canvas(
    
                                                                // Default - Stop ).
    
                                                                // *****Set your
    
                                                                // second icon
    
                                                                // here****
    
    
    
            full_circle_canvas.drawArc(rect, 0, 360, false, stroke_color);
    
            fill_circle_canvas.drawArc(rect, 0, 360, false, fill_color);
    
    
    
            buttonimage.setImageBitmap(first_icon_bmp);
    
            flg_frmwrk_mode = 1;
    
            fillcircle.setImageBitmap(fill_circle_bmp);
    
            full_circle_image.setImageBitmap(full_circle_bmp);
    
    
    
            cusView.setVisibility(View.GONE);
    
    
    
            addView(full_circle_image, lp);
    
            addView(fillcircle, lp);
    
            addView(buttonimage, lp);
    
            addView(cusView, lp);
    
    
    
        }

    最后加上点击按钮时各个状态切换的逻辑关系,这个按钮的布局就完成了。
    附上整个类的代码

      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(0, 161, 234)); // 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(0, 161, 234));
    
    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(0, 161, 234)); // 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(10, 10, 10, 10);
    
    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, 0, 360, false, stroke_color);
    
    381         fill_circle_canvas.drawArc(rect, 0, 360, false, 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 
    
    434 }
    View Code
  4. 按钮做好了我们可以在Activity中调用它了
    首先是写入到布局文件中

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    
        xmlns:tools="http://schemas.android.com/tools"
    
        android:layout_width="match_parent"
    
        android:layout_height="match_parent"
    
        
    
         >
    
    
    
        <com.example.mybutton.ButtonLayout
    
            android:id="@+id/ButtonLayout01"
    
            android:layout_width="wrap_content"
    
            android:layout_height="wrap_content"
    
            android:layout_centerHorizontal="true"
    
            android:layout_centerVertical="true"
    
            android:clickable="true" >
    
        </com.example.mybutton.ButtonLayout>
    
    
    
    </RelativeLayout>


    然后在activity中设置

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

     

 

三、结束语

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

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

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

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

那么今天到此结束~

 

========================================

 

作者:cpacm
出处:(http://www.cpacm.net/2015/03/26/Android开发日记(九)——Android组件间的数据传输/

 

你可能感兴趣的:(android)