自定义控件<一>

来源:互联网 发布:淘宝联盟分享店铺 编辑:程序博客网 时间:2024/06/11 06:38

View的工作流主要是指measure、layout、draw,即测量、布局和绘制。

  • measure确定View的测量宽/高
  • layout确定View最终的宽高和四个顶点的位置。
  • draw则将View绘制到屏幕上

案例:做一个圆形的控件

public class CircleView extends View {    private int mColor = Color.RED;    //设置画笔    private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);    public CircleView(Context context) {        super(context);        initView();    }    public CircleView(Context context, AttributeSet attrs) {        super(context, attrs);        initView();    }    public CircleView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        initView();    }    private void initView() {        mPaint.setColor(mColor);    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        int paddingRight = getPaddingRight();        int paddingLeft = getPaddingLeft();        int paddingBottom = getPaddingBottom();        int paddingTop = getPaddingTop();        //获取控件的宽和高        int width = getWidth() - paddingRight - paddingLeft;        int height = getHeight() - paddingBottom - paddingTop;        //获取控件宽和高中最小值,然后除以2,得到控件的半径        int radiu = Math.min(width, height) / 2;        //绘制View        canvas.drawCircle(width / 2 + paddingLeft, height / 2 + paddingTop, radiu, mPaint);    }}

上述代码是自定义的红色的圆形控件。但是有两个问题:

问题一:

<zx.demo.zx_circle_view.view.CircleView    android:layout_width="match_parent"    android:layout_height="match_parent"    /><zx.demo.zx_circle_view.view.CircleView    android:layout_width="wrap_content"    android:layout_height="wrap_content"    />

两种布局的效果一样,都是第一种的match_parent效果,那么怎样设定一个wrap_content效果?

解决方法:

想要解决这个问题,那么就需要引入MeasureSpec。

@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {    super.onMeasure(widthMeasureSpec, heightMeasureSpec);    int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);    int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);    int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);    int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);    if (widthSpecMode == MeasureSpec.AT_MOST            && heightSpecMode == MeasureSpec.AT_MOST) {        setMeasuredDimension(500, 500);    } else if (widthSpecMode == MeasureSpec.AT_MOST) {        setMeasuredDimension(500, heightSpecSize);    } else if (heightSpecMode == MeasureSpec.AT_MOST) {        setMeasuredDimension(widthSpecSize, 500);    }}

问题二:
怎样添加自定义属性,比如添加控件选择控件的颜色。

解决方法:

第一步、在values目录下创建自定义属性的XML。

第二步、在View的构造方法中解析自定义属性的值并做相应处理。

public CircleView(Context context, AttributeSet attrs) {    super(context, attrs);    //加载自定义属性集合CircleView    TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CircleView);    //解析CircleView中的circle_color属性,如果默认情况下为红色    mColor = typedArray.getColor(R.styleable.CircleView_circle_color, Color.RED);    //释放资源    typedArray.recycle();    initView();}

第三步、在布局文件中使用自定义属性

<RelativeLayout    xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    android:id="@+id/activity_main"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:gravity="center">    <zx.demo.zx_circle_view.view.CircleView        android:layout_width="300dp"        android:layout_height="300dp"        app:circle_color="@color/colorPrimary"        /></RelativeLayout>

注意:xmlns:app=”http://schemas.android.com/apk/res-auto”

app:自定义属性的前缀,可以换其他名字,但是CircleView中的自定义属性的前缀必须和它一致。

还有一种声明方式是:xmlns:app=”http://schemas.android.com/apk/res/zx.demo.zx_circle_view”,在apk/res/后面加上包名。

MeasureSpec理解:

第二个问题的解决很好理解,但是第一个问题解决方案中的MeasureSpec是什么东西呢?

MeasureSpec代表一个32位int值,其中最高的2位代表SpecMode,后面的30为代表SpecSize。

一个MeasureSpec封装了父布局传递给子布局的布局要求,每个MeasureSpec代表了一组宽度和高度的要求,一个MeasureSpec由大小和模式组成,它有三种模式:

  1. UNSPECIFIED(未指定):父容器不对View有任何限制,要多大给多大,这种情况一般用于系统内部,表示一种测量状态。
  2. EXACTLY(完全):父容器已经检测到View所需要的精确大小,这个时候View的最终大小就是SpecSize所指定的值。它对应于LayoutParams中的match_parent和具体的数值这两种模式。
  3. AT_MOST(至多):父容器指定了一个可用大小即SpecSize,View的的大小不能大于这个值,具体是什么值要看不同View的具体实现。它对应于LayoutParams中的wrap_content。
0 0
原创粉丝点击