里面包括了自定义图文框,自定义的仿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