【Android开发日记】之入门篇(十四)——Button控件+自定义Button控件
好久不见,又是一个新的学期开始了,为什么我感觉好惆怅啊!这一周也发生了不少事情,节假日放了三天的假(好久没有这么悠闲过了),实习公司那边被组长半强制性的要求去解决一个后台登陆的问题,结果就是把Android这块放在一边了,滚去看PHP的后台框架了(人家只是一个Android实习生,不带这么玩的),学校那边老师布置了一个hibernate的项目,还说我给你们一个月时间,慢慢看,慢慢学习(结果就是在群上发了一大堆的hibernate的视频教程,还真的是慢慢看慢慢学习了,而且视频还是极老的,hibernate还是版本3),遇到这种老师我也是醉了。顺便求点hibernate的教程,简单易上手最好了。〈(_ _)〉
好了,进入正题吧,今天要做的是button这个控件。按钮在窗口应用程序中是最常见的控件了,也算是程序与用户进行交互的常见手段了。按钮触发的事件处理,我们称为Evenr Handler,而在Android中,按钮事件是由系统的Button.OnClickListener所控制。那么接下来先看看最基本的button控件是怎么实现的。
一、基本Button控件
- 首先第一步就是往布局文件里拖一个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>当然,一个控件的布局属性还有很多,这些都是需要我们多用多熟悉才行。
- 然后再在程序中调用它
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控件就完成了。但当然,这不是我们今天要讲的重点,重点是我们如何自定义一个按钮,而不是使用系统给我们的按钮。
二、自定义按钮
我们先来看看效果图吧
这是一个自带进度条的按钮,它可以显示异步任务的进度,当完成后结束操作。我们来看看具体是怎么实现的吧。
- 拆分这个按钮。仔细观察上面的效果图,我们可以把这个按钮分成3个部分,首先是最简单的外面一圈圆,基本上画出个圆放在那里就行了。接着是中间的三角形,正方形以及完成的勾,这个我们可以使用view里的画图类勾勒出来,再使用简单的动画Animation来切换。最后的一部分是覆盖在圆圈上的不断在表示进度的圆圈,这个我们可以不断调用这个view的ondraw来刷新进度。这就是整个按钮的设计思路。我们来看看实际的代码吧。
- 首先是表示进度的圆圈,我们来新建一个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;
} } - 有了表示进度的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); }最后加上点击按钮时各个状态切换的逻辑关系,这个按钮的布局就完成了。
附上整个类的代码package com.example.mybutton; import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.ScaleAnimation;
import android.view.animation.Animation.AnimationListener;
import android.widget.FrameLayout;
import android.widget.ImageView; public class ButtonLayout extends FrameLayout implements OnClickListener { public CusImage cusView;
public int pix = 0;
public RectF rect;
// 图像视图
// ImageView类可以加载各种来源的图片(如资源或图片库),需要计算图像的尺寸,比便它可以在其他布局中使用,并提供例如缩放和着色(渲染)各种显示选项。
private ImageView circle_image, buttonimage, fillcircle, full_circle_image; // 可以用他来画几何图形、画曲线、画基于路径的文本。这是个绘图的路径类
private Path stop, tick, play, download_triangle, download_rectangle; // 位图类
private Bitmap third_icon_bmp, second_icon_bmp, first_icon_bmp; // 画笔类
private Paint stroke_color, fill_color, icon_color, final_icon_color; // AnimationSet类是Android系统中的动画集合类,用于控制View对象进行多个动作的组合,该类继承于Animation类
private AnimationSet in, out; // RotateAnimation类是Android系统中的旋转变化动画类,用于控制View对象的旋转动作,该类继承于Animation类
// private RotateAnimation arcRotation; // 缩放动画类
private ScaleAnimation new_scale_in, scale_in, scale_out; // 透明度动画
private AlphaAnimation fade_in, fade_out; public int flg_frmwrk_mode = 0;
boolean first_click = false; public ButtonLayout(Context context, AttributeSet attrs) {
super(context, attrs);
setOnClickListener(this); initialise();
setpaint();
setAnimation();
displayMetrics();
iconCreate();
init();
// TODO Auto-generated constructor stub
} public ButtonLayout(Context context) {
super(context);
setOnClickListener(this);
setBackgroundColor(Color.CYAN);
initialise();
setpaint();
setAnimation();
displayMetrics();
iconCreate();
init();
} /**
* 创建各个控件
*/
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 setpaint() { // Setting up color
// Paint.ANTI_ALIAS_FLAG是使位图抗锯齿的标志
stroke_color = new Paint(Paint.ANTI_ALIAS_FLAG);
stroke_color.setAntiAlias(true);
stroke_color.setColor(Color.rgb(0, 161, 234)); // Edit this to change
stroke_color.setStrokeWidth(3);
stroke_color.setStyle(Paint.Style.STROKE); icon_color = new Paint(Paint.ANTI_ALIAS_FLAG);
icon_color.setColor(Color.rgb(0, 161, 234));
// 填充
icon_color.setStyle(Paint.Style.FILL_AND_STROKE); // Edit this to change
icon_color.setAntiAlias(true); final_icon_color = new Paint(Paint.ANTI_ALIAS_FLAG);
final_icon_color.setColor(Color.WHITE); // Edit this to change the final
final_icon_color.setStrokeWidth(12);
final_icon_color.setStyle(Paint.Style.STROKE);
final_icon_color.setAntiAlias(true); fill_color = new Paint(Paint.ANTI_ALIAS_FLAG);
fill_color.setColor(Color.rgb(0, 161, 234)); // Edit this to change the
fill_color.setStyle(Paint.Style.FILL_AND_STROKE);
fill_color.setAntiAlias(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 displayMetrics() {
// Responsible for calculating the size of views and canvas based upon
// screen resolution.
DisplayMetrics metrics = getContext().getResources()
.getDisplayMetrics();
int width = metrics.widthPixels;
int height = metrics.heightPixels;
float scarea = width * height;
pix = (int) Math.sqrt(scarea * 0.0217); } /**
* 设置各个画面的路径
*/
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); } public void animation() { // Starting view animation and setting flag values if (flg_frmwrk_mode == 1) {
//full_circle_image.setVisibility(View.GONE);
buttonimage.startAnimation(out);
} } public void finalAnimation() { // Responsible for final fill up animation buttonimage.setVisibility(View.GONE);
fillcircle.setVisibility(View.VISIBLE);
fillcircle.startAnimation(new_scale_in); } public void stop() { // Responsible for resetting the state of view when Stop is clicked cusView.reset();
buttonimage.setImageBitmap(first_icon_bmp);
flg_frmwrk_mode = 1; } @Override
public void onClick(View v) {
// TODO Auto-generated method stub
animation();
} } 按钮做好了我们可以在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中设置
public class MainActivity extends Activity { private static ButtonLayout buttonLayout; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
buttonLayout = (ButtonLayout) findViewById(R.id.ButtonLayout01);
buttonLayout.setOnClickListener(new OnClickListener() { @Override
public void onClick(View v) {
// TODO Auto-generated method stub
buttonLayout.animation(); // Need to call this method for
// animation and progression if (buttonLayout.flg_frmwrk_mode == 1) { // Start state. Call any method that you want to execute runOnUiThread(new Runnable() { @Override
public void run() {
// TODO Auto-generated method stub
Toast.makeText(MainActivity.this,
"Starting download", Toast.LENGTH_SHORT)
.show();
}
});
new DownLoadSigTask().execute();
}
if (buttonLayout.flg_frmwrk_mode == 2) { // Running state. Call any method that you want to execute new DownLoadSigTask().cancel(true);
buttonLayout.stop();
runOnUiThread(new Runnable() { @Override
public void run() {
// TODO Auto-generated method stub
Toast.makeText(MainActivity.this,
"Download stopped", Toast.LENGTH_SHORT)
.show();
}
});
}
if (buttonLayout.flg_frmwrk_mode == 3) { // End state. Call any method that you want to execute. runOnUiThread(new Runnable() { @Override
public void run() {
// TODO Auto-generated method stub
Toast.makeText(MainActivity.this,
"Download complete", Toast.LENGTH_SHORT)
.show();
}
});
}
} });
} static class DownLoadSigTask extends AsyncTask<String, Integer, String> { @Override
protected void onPreExecute() { } @Override
protected String doInBackground(final String... args) { // Creating dummy task and updating progress for (int i = 0; i <= 100;) {
try {
Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace();
}
if (buttonLayout.flg_frmwrk_mode == 2 &&i<=100){
i++;
publishProgress(i);
}
} return null;
} @Override
protected void onProgressUpdate(Integer... progress) { // publishing progress to progress arc buttonLayout.cusView.setupprogress(progress[0]);
} } }
三、结束语
这个按钮我是仿照一个开源项目写的,它的地址是https://github.com/torryharris/TH-ProgressButton。
我在代码中掺杂了一些网址,这些都是我在看这整个开源代码时查阅的资料,如果你也不懂的话也可以去这些地址看看资料。
说实话,自定义控件设计的东西太多,不适合在入门的时候学习,不过有个概念,以此来抛砖引玉也是挺好的。
接下来不久的时间内我也会把今天遇到的一些概念,比如说animation,path,canvas一一介绍下来的。
那么今天到此结束~
========================================
作者:cpacm
出处:(http://www.cpacm.net/2015/04/01/Android开发日记(十一)——Button控件-自定义Button控件/)
【Android开发日记】之入门篇(十四)——Button控件+自定义Button控件的更多相关文章
- Android开发笔记(一百三十四)协调布局CoordinatorLayout
协调布局CoordinatorLayout Android自5.0之后对UI做了较大的提升.一个重大的改进是推出了MaterialDesign库,而该库的基础即为协调布局CoordinatorLayo ...
- 【Android开发日记】之入门篇(十二)——Android组件间的数据传输
组件我们有了,那么我们缺少一个组件之间传递信息的渠道.利用Intent做载体,这是一个王道的做法.还有呢,可以利用文件系统来做数据共享.也可以使用Application设置全局数据,利用组件来进行控制 ...
- 【Android开发日记】之入门篇(四)——Android四大组件之Activity
在Android中,无论是开发者还是用户,接触最多的就算是Activity.它是Android中最复杂.最核心的组件.Activity组件是负责与用户进行交互的组件,它的设计理念在很多方面都和Web页 ...
- 【Android开发日记】之入门篇(九)——Android四大组件之ContentProvider
数据源组件ContentProvider与其他组件不同,数据源组件并不包括特定的功能逻辑.它只是负责为应用提供数据访问的接口.Android内置的许多数据都是使用ContentProvider形式,供 ...
- 【Android开发日记】之入门篇(十三)——Android的控件解析
Android的控件都派生自android.view.View类,在android.widget包中定义了大量的系统控件供开发者使用,开发者也可以从View类及其子类中,派生出自定义的控件. 一.An ...
- 【Android开发日记】之入门篇(十一)——Android的Intent机制
继续我们的Android之路吧.今天我要介绍的是Android的Intent. 对于基于组件的应用开发而言,不仅需要构造和寻找符合需求的组件,更重要的是要将组件有机的连接起来,互联互通交换信息,才能够 ...
- 【Android开发日记】之入门篇(七)——Android数据存储(上)
在讲解Android的数据源组件——ContentProvider之前我觉得很有必要先弄清楚Android的数据结构. 数据和程序是应用构成的两个核心要素,数据存储永远是应用开发中最重要的主题之一,也 ...
- 【Android开发日记】之入门篇(八)——Android数据存储(下)
废话不多说了,紧接着来讲数据库的操作吧.Come On! 提到数据存储问题,数据库是不得不提的.数据库是用来存储关系型数据的不二利器.Android为开发者提供了强大的数据库支持,可以用来轻松地构造基 ...
- 【Android开发日记】之入门篇(五)——Android四大组件之Service
这几天忙着驾校考试,连电脑都碰不到了,今天总算告一段落了~~Service作为Android的服务组件,默默地在后台为整个程序服务,辅助应用与系统中的其他组件或系统服务进行沟通.它跟Activity的 ...
随机推荐
- Spring MVC自动为对象注入枚举数据
一.实现转换工厂,定义转换实现,如下: package com.mafwo; import org.springframework.core.convert.converter.Convert ...
- Elasticsearch 监控和部署
Elasticsearch: ! [ https://elasticsearch.cn/book/elasticsearch_definitive_guide_2.x/_cluster_health. ...
- C#的Response.BinaryWrite图片乱码问题
今天学习Response对象,该对象的有很多的输出方式,其中有一个binaryWrite可以输出图片,但是在输出图片一开始出现了乱码,后来通过百度得到解决: 代码: FileStream stream ...
- web相关基础知识2
2017-12-14 17:14:22 块元素 典型代表,Div,h1-h6,p,ul,li 特点: ★独占一行 ★可以设置宽高 ★ 嵌套(包含)下,子块元素宽度(没有定义情况下)和父块元素宽度默认 ...
- PAT 1065 单身狗
https://pintia.cn/problem-sets/994805260223102976/problems/994805266942377984 “单身狗”是中文对于单身人士的一种爱称.本题 ...
- 【Python】- 如何使用Visual Studio 2013编写python?
安装Visual Studio 2013 1.VS2013下载安装略 安装python2.7 1.从官网下载python2.7,下载地址:https://www.python.org/getit/ ...
- 【历史】- UNIX发展史(BSD,GNU,linux)
先前的一個理想 UNIX 系统自 1969 年 Ken Thompson 与 Dennis Ritchie 在美国贝尔电话实验室(Bell Telephone Laboratories)发展出雏形至今 ...
- delphi数据库进行增加操作时,怎么判断插入的这个值是否已经存在?
//增 procedure TForm1.btnAddClick(Sender: TObject); begin ADOQuery1.Close; ADOQuery1.SQL.Clear; ADOQu ...
- [SCOI2012]喵星球上的点名——堪称十种方法做的题
题意: 给你N个串对,M个询问串,对每个询问串求是多少串对的子串(在串对的某一个中作为子串),以及每个串对最终是包含了多少询问串 方法众多.. 可谓字符串家族八仙过海各显神通. 复杂度不尽相同,O(n ...
- hive Illegal Operation state transition from CLOSED to ERROR的处理
异常堆栈如下: 2015-11-24 16:49:11,495 ERROR org.apache.hive.service.cli.operation.Operation: Error running ...