里面包括了自定义图文框,自定义的仿ios菊花样式的ProgressBar,两种方法,一种是自己出来的,通过重写view,自己实现,其实这个重写就是自定义View的过程,另一种是网络上传的,直接通过定义动画转动实现,第一种方式拓展性比较好,做复杂点可以实现各种样式,当然仅仅是一个菊花的进度条,并不需要这么大费周章的写一个类。我练的是方法。
自定义控件,大体上的流程分为两种,一种是已有的控件,进行组合,一种是自己手动绘画出一个控件,当然,这里的绘画可以导入图片资源文件,通过转化为bitmap的对象再操作,如果是图片的适应操作,安卓官方文档有给出例子,我自己也认真看了下,感觉里面都是精华把。可以多看。我的笔记如下:
http://blog.csdn.net/u013755250/article/details/50224219
我看过箭头抽屉的开源项目,其实它也是写了这么一个Drawable的View,里面是通过画笔直接绘制图形,,再通过线性排插法进行变化,进行变化。
自定义控件,去google搜下,都有流程,大体是,measure,layout,draw。相对应的就是,测量,然后布局控件位置,再就是把控件的样子画出来。
我写组合控件的时候就深有体会。因为组合就不需要重写上述的三种方法,只要在构造方法中完成业务逻辑。这就有个问题了,构造方法是在new的时候就执行,它比View中的任何其他方法都要早执行。意味着,在构造方法中写控件,难免要用到控件的总的大小,可这时的所有getter方法获取的只都为0,因为根本就没测量过,就不会有数据。这时如何获取宽高呢?
我本来是想模仿自定属性时的方式,通过获取attrs.xml中属性定义的方式,来获取android:开头的属性,可是,肯能是思路有错,研究了好久,还是没找到正确的。后面想了个折中的方法,在dimens.xml中事先定义一个控件所要用的宽高,在UI的xml中设置时,就直接引用dimen的。这样就不存在重复定义的问题了,只要改一个地方的值,就可以整体适配,利于多次利用
个人觉得,写每个类的时候,都应该往多次利用的方向上靠。这样才复合继承的思想,可以多次利用,省去许多重复的业务。
效果图:
图文输入框:
package com.hs.cv; import android.annotation.TargetApi; import android.content.Context; import android.content.res.TypedArray; import android.graphics.drawable.Drawable; import android.os.Build; import android.text.InputType; import android.text.method.PasswordTransformationMethod; import android.util.AttributeSet; import android.view.Gravity; import android.widget.EditText; import android.widget.ImageView; import android.widget.LinearLayout; import com.hs.customview.R; import com.hs.cv.utils.BitmapUtil; /** * 图文加载控件 * 使用方法,最好在dimen中第一控件的宽高,并且在xml中统一使用 * 一些属性设置,可以引用对象,重新设置 * * @author Holy-Spirit * */ @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) public class CustomImageTxtView extends LinearLayout { /* * 控件内EditText对象 */ private EditText mText = null; /* * 控件内ImageView对象 */ private ImageView mImage = null; public CustomImageTxtView(Context context) { super(context); } public CustomImageTxtView(Context context, AttributeSet attrs) { super(context, attrs); /* * 控件的宽 */ final int vWidth = context.getResources().getDimensionPixelSize( R.dimen.defWidth); /* * 控件的高 */ final int vHeight = context.getResources().getDimensionPixelSize( R.dimen.defHeight); /* * 控件内imag的高 */ final int imgHeight = vHeight * 3 / 10; /* * 控件内imag的宽 */ final int imgWidth = imgHeight; /* * 控件内imag的与其他控件的间隔 */ final int imgMargin = vHeight / 5; /* * 控件内容放置的重心 */ final int contentGra = Gravity.CENTER_VERTICAL; /* * 控件内txt文本的宽度 */ final int txtWidth = vWidth - 2 * imgMargin - imgWidth; /* * 控件内txt文本的高度 */ final int txtHeight = vHeight; /* * 属性的id */ int resId = -1; /*设置整个View的重心*/ this.setGravity(contentGra); /*获取自定义的属性数组*/ TypedArray mArray = context.obtainStyledAttributes(attrs, R.styleable.CustomImageTxtView); /*设置Image*/ mImage = new ImageView(context); this.setImageLayoutParams(imgWidth, imgHeight, imgMargin); /*设置Edit*/ mText = new EditText(context); this.setTextGravity(contentGra); this.setTextLayoutParams(txtWidth, txtHeight); this.hideBottomLine(context.getResources().getDrawable( R.drawable.round_background)); this.setIsSingleLine(true); /*获取xml中设置的属性*/ int length = mArray.getIndexCount(); for (int i = 0; i < length; i++) { int attr = mArray.getIndex(i); switch (attr) { case R.styleable.CustomImageTxtView_Oriental: /*设置方向*/ resId = mArray.getInt(R.styleable.CustomImageTxtView_Oriental, 0); this.setOrientation((resId == 1) ? LinearLayout.HORIZONTAL : LinearLayout.VERTICAL); break; case R.styleable.CustomImageTxtView_Text: /*设置文本内容*/ resId = mArray.getResourceId(R.styleable.CustomImageTxtView_Text, 0); mText.setText(resId > 0 ? mArray.getResources().getText(resId) : mArray.getString(R.styleable.CustomImageTxtView_Text)); break; case R.styleable.CustomImageTxtView_Src: /*设置图片资源*/ resId = mArray.getResourceId(R.styleable.CustomImageTxtView_Src, 0); mImage.setImageBitmap(resId > 0 ? BitmapUtil .decodeSampleBitmapFromResource(getResources(), resId, imgWidth, imgHeight) : BitmapUtil .decodeSampleBitmapFromResource(getResources(), R.drawable.ic_launcher, imgWidth, imgHeight)); break; case R.styleable.CustomImageTxtView_Content: /*设置文本类型*/ resId = mArray.getInt(R.styleable.CustomImageTxtView_Content, 1); if (resId == 1) { this.setTextInputType(InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS); } else if (resId == 2) { this.setTextInputType(InputType.TYPE_TEXT_VARIATION_PASSWORD); this.setTextTransformationMethod(); } else { this.setTextInputType(InputType.TYPE_CLASS_TEXT); } break; case R.styleable.CustomImageTxtView_TextColor: /*设置文字颜色*/ resId = mArray.getResourceId( R.styleable.CustomImageTxtView_TextColor, 0); if (resId > 0) this.setTextColor(context.getResources().getColor(resId)); break; case R.styleable.CustomImageTxtView_TextSize: /*设置文字大小*/ resId = mArray.getResourceId( R.styleable.CustomImageTxtView_TextSize, 0); if (resId > 0) this.setTextSize(context.getResources() .getDimensionPixelSize(resId)); break; default: break; } } /*添加控件到父控件*/ addView(mImage); addView(mText); /*回收资源*/ mArray.recycle(); } /* * 设置密码输入 */ public void setTextTransformationMethod() { mText.setTransformationMethod(PasswordTransformationMethod .getInstance()); } /* * 设置内容类型 */ public void setTextInputType(int type) { mText.setInputType(type); } /* * 设置内容字体大小 */ public void setTextSize(int size) { mText.setTextSize(size); } /* * 设置内容字体颜色 */ public void setTextColor(int color) { mText.setTextColor(color); } /* * 设置Imag布局 */ public void setImageLayoutParams(int reqWidth, int reqHeight, int margin) { LinearLayout.LayoutParams mParams = new LayoutParams(reqWidth, reqHeight); mParams.setMargins(margin, margin, margin, margin); mImage.setLayoutParams(mParams); } /* * 设置文本单行 */ public void setIsSingleLine(boolean isSingleLine) { mText.setSingleLine(isSingleLine); } /* * 隐藏原本EditText的下划线 */ public void hideBottomLine(Drawable bg) { mText.setBackground(bg); } /* * 设置文本内容重心 */ public void setTextGravity(int gravity) { mText.setGravity(gravity); } /* * 设置文本布局 */ public void setTextLayoutParams(int txtWidth, int txtHeight) { mText.setLayoutParams(new LayoutParams(txtWidth, txtHeight)); } }
自定义菊花样式ProgressBar:
基本的实现策略是在ondraw中画出菊花的图形,通过颜色轮转重画实现感觉图形一直在动的效果,你可以任意定义一组颜色,打到你想要的效果。可以在UI线程中定义一个handler,定时刷新
package com.hs.cv; import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.content.Context; import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.Paint; import android.os.Build; import android.util.AttributeSet; import android.view.View; import com.hs.customview.R; /** * 自定义菊花样式的Progress * UI线程定义handler定时刷新 * * @author Holy-Spirit */ @TargetApi(Build.VERSION_CODES.HONEYCOMB) @SuppressLint("DrawAllocation") public class CustomProgressBar extends View { /* * 画笔 */ private Paint mPaint = null; /* * 每个指针的颜色 */ private static final int[] colors = new int[]{R.color.color_top, R.color.color_right_top, R.color.color_right, R.color.color_right_bottom, R.color.color_bottom, R.color.color_left_bottom, R.color.color_left, R.color.color_left_top}; /* * android res资源对象 */ private Resources res = null; /* * 颜色值轮转指针 */ private int i = 0; public CustomProgressBar(Context context) { super(context); } public CustomProgressBar(Context context, AttributeSet attrs) { super(context, attrs); res = context.getResources();// 获取资源对象,用来获取color值 } public void refreshView() { invalidate();// 触发onDraw()方法,重绘Progress } /* * color循环变化 */ private int calculateIndex(int in) { return in % (colors.length - 1); } /* * 设置指针颜色 */ public void setLineColor(int index) { mPaint.setColor(res.getColor(colors[calculateIndex(index)])); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); final float roundWidth; final int width = canvas.getWidth(); final int height = canvas.getHeight(); roundWidth = width > height ? height : width; final float halfRoundWidth = roundWidth / 2;// 获取画布的半长 mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setStrokeWidth(roundWidth / 15);// 设置为画布的十五分之一 float f1 = halfRoundWidth / 5; float f2 = (float) Math.sqrt(f1 * f1 / 2);// 中心点到指针的长度在x,y轴上的投影 float f3 = (float) Math.sqrt(f1 * f1 * 9) / 2;//指针长在x,y轴上的投影 float f5 = halfRoundWidth - f3 - f1;//画布四哥点到指针的长度在x,y轴上的投影 // top this.setLineColor(0 + i); canvas.drawLine(halfRoundWidth, halfRoundWidth / 5, halfRoundWidth, halfRoundWidth / 5 * 4, mPaint); // right top this.setLineColor(1 + i); canvas.drawLine(roundWidth - f5, f5, halfRoundWidth + f2, halfRoundWidth - f2, mPaint); // right this.setLineColor(2 + i); canvas.drawLine(halfRoundWidth / 5 * 9, halfRoundWidth, halfRoundWidth / 5 * 6, halfRoundWidth, mPaint); // right bottom this.setLineColor(3 + i); canvas.drawLine(roundWidth - f5, roundWidth - f5, halfRoundWidth + f2, halfRoundWidth + f2, mPaint); // bottom this.setLineColor(4 + i); canvas.drawLine(halfRoundWidth, halfRoundWidth / 5 * 9, halfRoundWidth, halfRoundWidth / 5 * 6, mPaint); // left bottom this.setLineColor(5 + i); canvas.drawLine(f5, roundWidth - f5, halfRoundWidth - f2, halfRoundWidth + f2, mPaint); // left this.setLineColor(6 + i); canvas.drawLine(halfRoundWidth / 5, halfRoundWidth, halfRoundWidth / 5 * 4, halfRoundWidth, mPaint); // // left top this.setLineColor(7 + i); canvas.drawLine(f5, f5, halfRoundWidth - f2, halfRoundWidth - f2, mPaint); i++; } }
通过定义的动画的方式实现菊花样式的Progressbar:
第一步:
<?xml version="1.0" encoding="utf-8"?> <animated-rotate xmlns:android="http://schemas.android.com/apk/res/android" android:drawable="@drawable/pic_rotate" android:pivotX="50%" android:pivotY="50%" />
引用的图片就是你要让它动的图片
第二部在UI的xml中引用
<ProgressBar android:id="@+id/logining" android:layout_width="15dp" android:layout_height="15dp" android:indeterminateDrawable="@drawable/circle_loading" android:layout_alignTop="@+id/cancel" android:layout_alignRight="@+id/count" android:layout_alignEnd="@+id/count"/>
demo下载:
http://download.csdn.net/detail/u013755250/9341283