继承View 重写 三个构造
public class MyView extends View {
privatePaint mPaint;
publicMyView(Context context, AttributeSet attrs, int defStyle) {
}
publicMyView(Context context, AttributeSet attrs) {
}
publicMyView(Context context) {
}
这三个构造是自动匹配调用
重写onDraw
onDraw方法给我们提过canvas(画布) 我们自己要生成画笔(Paint)以及给画笔设置颜色和字体大小
@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
Paint mPaint = new Paint();
mPaint.setTextSize(dimension);
mPaint.setColor(color);
mPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
canvas.drawText("我被画出来了", 50, 100, mPaint);
}
在布局xml里面我们只需要全类名使用即可
<com.cym.custom.MyView // 全类名使用即可
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
如果想要给自定义控件添加自定义属性
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
xmlns:myView="http://schemas.android.com/apk/res/com.cym.custom"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
androidrientation="vertical" >
<com.cym.custom.MyView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
myView:color="@color/white"
myView:fontsize="@dimen/fontsize"
/>
我们就要为自定义属性写xml
Attrs.xml:
<?xmlversion="1.0"encoding="utf-8"?>
<resources>
<declare-styleablename="myView"> 标识名
<attrname="color"format="color"/> 制定名字及属性格式
<attrname="fontsize"format="dimension"/> 制定名字及属性格式
</declare-styleable>
</resources>
选择属性项
Colors.xml
<?xmlversion="1.0"encoding="utf-8"?>
<resources>
<colorname="white">#ffffffff</color> 制定相应属性内容
</resources>
Domenson.xml
<?xmlversion="1.0"encoding="utf-8"?>
<resources>
<dimenname="fontsize">100dp</dimen> 制定相应属性内容
</resources>
获得自定义属性内容
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint();
从属性布局文件拿到所有布局属性
TypedArray array =context.obtainStyledAttributes(attrs, R.styleable.myView);
根据不同的属性资源ID拿取相应的值
float dimension =array.getDimension(R.styleable.myView_fontsize,10);
int color =array.getColor(R.styleable.myView_color,Color.RED);
mPaint.setTextSize(dimension);
mPaint.setColor(color);
array.recycle();
}
自定义音量条
public class MyView extends View{
private Paint paint; // 画笔
private Context context; // 上下文
private AudioManager am; // 音量管理器
private int musicMax; // 最大音量
private Bitmap bitmap; // 绿色图片
private Bitmap bitmap1; // 灰色图片
//图片宽高
private int bitmapWidth;
private int bitmapHeight;
// 控件宽高
private int w;
private int h;
public MyView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
paint = new Paint();
this.context = context;
init();
// TODO Auto-generated constructor stub
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
paint = new Paint();
this.context = context;
init();
// TODO Auto-generated constructor stub
}
public MyView(Context context) {
super(context);
paint = new Paint();
this.context = context;
init();
// TODO Auto-generated constructor stub
}
@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
// 当前音量
int index = am.getStreamVolume(AudioManager.STREAM_MUSIC);
int reverseIndex = musicMax - index;
//画灰色的格子
for(int i = 0;i<reverseIndex;i++){
canvas.drawBitmap(
bitmap1,
null,
new Rect(0, 10*i, bitmapWidth, bitmapHeight+10*i),
paint);
}
for(int i =reverseIndex;i!=musicMax;i++){
canvas.drawBitmap(
bitmap,
null,
new Rect(0, 10*i, bitmapWidth, bitmapHeight+10*i),
paint);
}
}
// 定义一个初始化方法
private void init(){
// 得到音量管理器
am = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
// 得到最大音量
musicMax = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.sound_line);
bitmap1 = BitmapFactory.decodeResource(getResources(),R.drawable.sound_line1);
bitmapWidth = bitmap.getWidth();
bitmapHeight = bitmap.getHeight();
}
// 对要绘制的控件进行测量 调用两次
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
super.onMeasure(widthMeasureSpec,heightMeasureSpec);
w = resolveSize(w, widthMeasureSpec);
h = resolveSize(h, heightMeasureSpec);
// 设置数据
setMeasuredDimension(w, h);
}
//当布局被加载完成的时候,会调用一个方法
@Override
protected void onFinishInflate() {
// TODO Auto-generated method stub
super.onFinishInflate();
w = bitmapWidth;
h = bitmapHeight * 15 + 5 * 14;
}
// 触摸事件
@Override
public boolean onTouchEvent(MotionEventevent) {
// TODO Auto-generated method stub
float y = event.getY();
int index = (int)y/9;
int contol_index = 15 -index;
if(contol_index > -1&& contol_index <= 15){
am.setStreamVolume(AudioManager.STREAM_MUSIC, contol_index, AudioManager.FLAG_PLAY_SOUND);
// 控件重绘
invalidate();
}
return true;
}
}
课后问题
为什么要自定义控件?
因为系统提供的控件无法满足我们的需求,所以要使用自定义控件.
自定义控件的步骤
重写三个构造,重写onDraw(绘制)方法,如果要自定义属性的话,要写配置属性xml,属性选择项xml,使用时在布局文件里面声明引用,才可以使用自定义属性。
如果业务稍微复杂还重写到
onFinishInflate(布局加载后调用该方法)
onMeasure(对绘制控件进行测量)
以及频繁修改视图则会用到
Invalidate()控件重绘