Android控件架构与自定义控件
来源:互联网 发布:全民枪战刷龙软件 编辑:程序博客网 时间:2024/06/13 22:14
View 的测量
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); }
如果查看 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
会发现,最终会调用setMeasuredDimension(width,height)
这个方法,所以我们就可以直接传递width和height到这个方法中
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)); }
测量模式可以分为以下三种
- EXACTLY 精确值模式
对自定义view的width和height需指定具体的dip.
android:layout_width="100dp"
- AT_MOST 最大值模式
控件的layout_width 和layout_height 属性制定为warp_content是,控件大小一般随着控件的子空间或者内容的变化而变化,只要不超过父控件允许的最大尺寸即可 - UNSPECIFIED 无规定模式
不指定测量大小,像多大多大.
view中重写onMeasure()方法
自定义view重写`onMeasure()`,只支持 EXACTLY模式,所以如果在自定义控件的时候补充些onMeasu()方法的话,就只能使用EXACTLY模式.控件可以响应你制定的具体狂傲值或者是match_parent.而如果要自定义view支持warp_content属性,那么就必须重写onMeasure()方法来制定warp_conte时的大小
measureWidth()
private int measureWidth(int measureSpec) { int result = 0; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); if (specMode == MeasureSpec.EXACTLY) { result = specSize; } else { result = 200; if (specMode == MeasureSpec.AT_MOST) { result = Math.min(result, specSize); } } return result; }
measureHeight();
和measureWidth()差不多.
onMeasure();
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //这里直接调用setMeasuredDimension();传进去宽高. setMeasuredDimension( measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec)); }
| | | | √
自定义VIew
自定义view分为三种情况
- 对现有控件进行拓展
- 通过组合来实现新的控件
- 重写view来实现全新的控件
1.对现有控件进行拓展
重写TextView,进行拓展
@Override protected void onDraw(Canvas canvas) { //在回调父类方法之前,实现自己的逻辑,对TextView来说即是在绘制文本内容前 super.onDraw(canvas); //在回调父类方法之后,实现自己的逻辑,对TextView来说即是在绘制文本内容后 }
实例化自己的画笔
private void initView() { //首先将画笔实例化 mPaint1 = new Paint(); mPaint1.setColor(getResources().getColor( android.R.color.holo_blue_light)); mPaint1.setStyle(Paint.Style.FILL); mPaint2 = new Paint(); mPaint2.setColor(Color.YELLOW); mPaint2.setStyle(Paint.Style.FILL); }
重写onDraw(Canvas canvas)
@Override protected void onDraw(Canvas canvas) { // 绘制外层矩形 canvas.drawRect( 0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint1); // 绘制内层矩形,将 边距 调整为10 距离外围 canvas.drawRect( 10, 10, getMeasuredWidth() - 10, getMeasuredHeight() - 10, mPaint2); canvas.save(); // 绘制文字前平移10像素 canvas.translate(10, 0); // 父类完成的方法,即绘制文本 super.onDraw(canvas); canvas.restore(); }
完整代码
public class MyTextView extends TextView { private Paint mPaint1, mPaint2; public MyTextView(Context context) { super(context); initView(); } public MyTextView(Context context, AttributeSet attrs) { super(context, attrs); initView(); } public MyTextView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initView(); } private void initView() { //首先将画笔实例化 mPaint1 = new Paint(); mPaint1.setColor(getResources().getColor( android.R.color.holo_blue_light)); mPaint1.setStyle(Paint.Style.FILL); mPaint2 = new Paint(); mPaint2.setColor(Color.YELLOW); mPaint2.setStyle(Paint.Style.FILL); } @Override protected void onDraw(Canvas canvas) { // 绘制外层矩形 canvas.drawRect( 0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint1); // 绘制内层矩形,将 边距 调整为10 距离外围 canvas.drawRect( 10, 10, getMeasuredWidth() - 10, getMeasuredHeight() - 10, mPaint2); canvas.save(); // 绘制文字前平移10像素 canvas.translate(10, 0); // 父类完成的方法,即绘制文本 super.onDraw(canvas); canvas.restore(); }}
2.创建复合控件(TopBar)
原理
- 实现RelativeLayout
- 在初始化方法中,接收自定义属性的值
- 通过new 的方法来实现你需要的控件,例如 Button but = new Button(Context);
- 通过set******();将自定义属性传到空间当中
- 自定义控件的 布局属性 LayoutParams
- addView(View,LayoutParams);将控件以及布局属性,添加到主布局当中去.
2.1为自己的view自定义属性
<declare-styleable name="TopBar"><!--添加了9个属性,分别是左右Button和中间的Title的text,textColor,TextSize--> <attr name="title" format="string" /> <attr name="titleTextSize" format="dimension" /> <attr name="titleTextColor" format="color" /> <attr name="leftTextColor" format="color" /> <attr name="leftBackground" format="reference|color" /> <attr name="leftText" format="string" /> <attr name="rightTextColor" format="color" /> <attr name="rightBackground" format="reference|color" /> <attr name="rightText" format="string" /> </declare-styleable>
2.2接受自定义的属性,
其中最重要的就是
TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.TopBar);
通过这个方法,将你在atts.xml中定义的declare-styleable 的所有属性的值存储到TypedArray中
// 通过这个方法,将你在atts.xml中定义的declare-styleable // 的所有属性的值存储到TypedArray中 TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.TopBar); // 从TypedArray中取出对应的值来为要设置的属性赋值 mLeftTextColor = ta.getColor( R.styleable.TopBar_leftTextColor, 0); mLeftBackground = ta.getDrawable( R.styleable.TopBar_leftBackground); mLeftText = ta.getString(R.styleable.TopBar_leftText); mRightTextColor = ta.getColor( R.styleable.TopBar_rightTextColor, 0); mRightBackground = ta.getDrawable( R.styleable.TopBar_rightBackground); mRightText = ta.getString(R.styleable.TopBar_rightText); mTitleTextSize = ta.getDimension( R.styleable.TopBar_titleTextSize, 10); mTitleTextColor = ta.getColor( R.styleable.TopBar_titleTextColor, 0); mTitle = ta.getString(R.styleable.TopBar_title); // 获取完TypedArray的值后,一般要调用 // recyle方法来避免重新创建的时候的错误 ta.recycle();
2.3 实例化控件,并将获取到的自定义属性,set到控件当中.
mLeftButton = new Button(context); mRightButton = new Button(context); mTitleView = new TextView(context); // 为创建的组件元素赋值 // 值就来源于我们在引用的xml文件中给对应属性的赋值 mLeftButton.setTextColor(mLeftTextColor); mLeftButton.setBackground(mLeftBackground); mLeftButton.setText(mLeftText); mRightButton.setTextColor(mRightTextColor); mRightButton.setBackground(mRightBackground); mRightButton.setText(mRightText); mTitleView.setText(mTitle); mTitleView.setTextColor(mTitleTextColor); mTitleView.setTextSize(mTitleTextSize); mTitleView.setGravity(Gravity.CENTER);
2.4 addView(View,LayoutParams);
// 为组件元素设置相应的布局元素 mLeftParams = new LayoutParams( LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT); mLeftParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT, TRUE); // 添加到ViewGroup addView(mLeftButton, mLeftParams); mRightParams = new LayoutParams( LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT); mRightParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, TRUE); addView(mRightButton, mRightParams); mTitlepParams = new LayoutParams( LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT); mTitlepParams.addRule(RelativeLayout.CENTER_IN_PARENT, TRUE); addView(mTitleView, mTitlepParams);
到这整个布局都写完了.基本上是可以显示的没有问题,下面的话就是添加一个特有的属性,比如说,onClick();
2.4 对左右Button添加OnClick();
摘要
1. 定义Interface,添加回调方法
2. 类中添加 Interface属性,并设置气setter,方法,用于外部调用
3. 控件添加onclick()
2.4.1 定义Interface,添加回调方法
// 接口对象,实现回调机制,在回调方法中 // 通过映射的接口对象调用接口中的方法 // 而不用去考虑如何实现,具体的实现由调用者去创建 public interface topbarClickListener { // 左按钮点击事件 void leftClick(); // 右按钮点击事件 void rightClick(); }
2.4.2 类中添加 Interface属性,并设置气setter,方法,用于外部调用
// 映射传入的接口对象 private topbarClickListener mListener; // 暴露一个方法给调用者来注册接口回调 // 通过接口来获得回调者对接口方法的实现 public void setOnTopbarClickListener(topbarClickListener mListener) { this.mListener = mListener; }
2.4.3 控件添加onclick()
// 按钮的点击事件,不需要具体的实现, // 只需调用接口的方法,回调的时候,会有具体的实现 mRightButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { //判断当前接口对象,是否已经实例化,如果没有实例化的话,直接点解是会报错的! if (mListener!=null) mListener.rightClick(); } }); mLeftButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (mListener!=null) mListener.leftClick(); } });
3.重写View实现全新的控件
这里的话就实现一个 音频条形图
首先来分析一下这个效果是如何实现的,之后在一步一步来实现
既然是条形图,那就是一个个的矩形了.先画出多个矩形,两两之间的距离是5dip,也就是说,矩形的横坐标平移5个单位长度. 其中的颜色渐变用到了 Lineargradient extends Shard 是shard的子类.可以用paint.setShard();来设置渐变色.
1. 矩形的宽度是一定的,但是高度不同,所以需要生成一个随机数. Math.random();
2. 画矩形
3. 实现渐变色
onDraw();
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //循环生成12个矩形, for (int i = 0; i < mRectCount; i++) { //生成0~1之间的随机数,之后 * 屏幕的高度,就是矩形的高度.小于屏幕的高度. mRandom = Math.random(); float currentHeight = (float) (mRectHeight * mRandom); //mWidth 获取到两侧 空余出来的空白的 坐标的宽度. canvas.drawRect( (float) (mWidth * 0.4 / 2 + mRectWidth * i + offset), currentHeight, (float) (mWidth * 0.4 / 2 + mRectWidth * (i + 1)), mRectHeight, mPaint); } //300ms延迟之后重新 绘制新的图形 postInvalidateDelayed(300); }
关于渐变色,
@Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mWidth = getWidth(); mRectHeight = getHeight(); //给两边各剩余 两份 的空间, 中间显示的宽度占6分,再分为12份 mRectWidth = (int) (mWidth * 0.6 / mRectCount); mLinearGradient = new LinearGradient( 0, 0, mRectWidth, mRectHeight, Color.YELLOW, Color.BLUE, Shader.TileMode.MIRROR); mPaint.setShader(mLinearGradient); }
LinearGradient extends Shard 的使用
Paint p=new Paint();LinearGradient lg=new LinearGradient(0,0,100,100,Color.RED,Color.BLUE,Shader.TileMode.MIRROR);
参数一为渐变起初点坐标x位置,参数二为y轴位置,参数三和四分辨对应渐变终点,最后参数为平铺方式,这里设置为镜像
Gradient是基于Shader类,所以我们通过Paint的setShader方法来设置这个渐变,代码如下: mPaint.setShader(lg);
canvas.drawCircle(0,0,200,mPaint); //参数3为画圆的半径,类型为float型。
它除了定义开始颜色和结束颜色以外还可以定义,多种颜色组成的分段渐变效果
LinearGradient shader = new LinearGradient(0, 0, endX, endY, new int[]{startColor, midleColor, endColor},new float[]{0 , 0.5f, 1.0f}, TileMode.MIRROR);
其中参数new int[]{startColor, midleColor, endColor}是参与渐变效果的颜色集合,
其中参数new float[]{0 , 0.5f, 1.0f}是定义每个颜色处于的渐变相对位置,
这个参数可以为null,如果为null表示所有的颜色按顺序均匀的分布
http://blog.csdn.net/qaz13177_58_/article/details/7852389
先写到这了,后期慢慢来!
- Android控件架构与自定义控件详解
- Android控件架构与自定义控件(一)
- Android控件架构与自定义控件(二)
- Android控件架构与自定义控件详解
- Android控件架构与自定义控件详解
- Android控件架构与自定义控件
- Android控件架构与自定义控件
- Android 控件架构与自定义控件详解
- Android 控件架构与自定义控件(一)
- Android 控件架构与自定义控件(二)
- Android 控件架构与自定义控件(三)
- Android 控件架构与自定义控件(四)
- Android控件架构与自定义控件
- Android群英传之Android控件架构与自定义控件
- Android控件架构与自定义控件详解(一)
- 3.Android群英传读书笔记-控件架构与自定义控件
- Android群英传 第三章-控件架构与自定义控件
- 第3章 Android控件架构与自定义控件详解
- Eclipse调试时,显示变量的十六进制值
- iOS UI篇13 - 获取键盘的高度
- hdu2795 Billboard --单点更新
- eclipse项目导入
- js实现刷新页面后select标签保持选中状态
- Android控件架构与自定义控件
- 让你的app提升一个档次-Android酷炫自定义控件
- Windows路由表配置:双网卡同时上公司内外网
- JS函数写错时是否执行问题
- ffplay.c数据结构分析
- easyui-combobox多选下拉框
- mysql sql语句
- 【POJ】1383 - Labyrinth(树的直径)
- 互联网时代