第三章--自定义控件

1 dp,sp,px

  • 名词解释
  • px:像素,就是屏幕上的点,如图片的像素大小为32*32,这就是指的像素
  • dpi:每英寸点数,即每英寸包括的像素个数,用对角线上像素点数/对角线长度。
  • dp:设备独立像素,与像素密度密切相关。在dpi=160的设备上,1dp=1px.
  • sp:相当于dp,常用于文字修饰
  • dip:=dp
  • 使用
  • 常用尺寸大小dp
  • 文字尺寸用sp
  • 在屏幕上画一个分割线可以用px,比如1px
  • m,h,xh,xxh,xxxh.1.5倍的等比

2 LayoutInflater

将xml文件解析为视图

  • 获得LayoutInflater实例的三种方法
  • LayoutInflater m1 = getLayoutInflater()
  • LayoutInflater layoutInflater = getSystemService(LATOU_INFLATER_SERVICE)
  • LayoutInflater layoutInflater = LayoutInflater.from(Context)
  • 从源码来看,三种方法其实都是一种,就是第二种
    /**
     * Obtains the LayoutInflater from the given context.
     */
    public static LayoutInflater from(Context context) {
        LayoutInflater LayoutInflater =
                (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        if (LayoutInflater == null) {
            throw new AssertionError("LayoutInflater not found.");
        }
        return LayoutInflater;
    }

从上面from()的源码来看,方法里就调用了getSystemService(),所以殊途同归。
tips:getLayoutInflater()还没找到

3 提取布局属性:theme&style

当控件的很多属性有重合的时候,可以把它们相同的属性提取出来,这样可以减少代码的冗余度。

这里写图片描述

也可用parent继承已有的style,在代码中是这样引用的


这里写图片描述

4 如何自定义属性

深入理解android的自定义属性,写的更加易懂,以下参考了这篇博客。

  • 创建属性
  • value下新建资源文件,命名attrs_+类名
  • <declare-styleable><declare-styleable/>:声明属性。这个标签是必须的吗?答案否。可以把这个去掉,直接声明属性。但是如果没有这个标签,有些工作需要我们去做,比如,编写常量(属性的下标,int[]数组)如,在R.java中生成的代码就要我们去编写
public static final class attr{
    public static final int backgroundColor=0x7f0100b3;
}
public static final class styleable {

    public static final int[] RedTextButton = {
            0x7f0100b3, 0x7f0100b4
        };
    public static final int RedTextButton_backgroundColor = 0;
    public static final int RedTextButton_textSize = 1;
}

所以有了这个标签,我们就可以只去关注这些属性的编写了,更加高效。

  • <attr/>name:名称;format:设置类型
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="RedTextButton">
        <attr name="backgroundColor" format="color"/>
        <attr name="textSize" format="integer"/>
        <attr name="text" format="string"/>
    </declare-styleable>
</resources>
  • 然后在CustomView代码中获取这些属性
    public void init(Context context, AttributeSet attrs){
   
        this.setOnClickListener(this);

        TypedArray typedArray = context.obtainStyledAttributes(
                attrs,R.styleable.RedTextButton);
        mBackGroundColor = typedArray.getColor(
                R.styleable.RedTextButton_backgroundColor, Color.BLUE);
                   mText = typedArray.getString(R.styleable.RedTextButton_text);
        typedArray.recycle();
               //
        mTextSize = typedArray.getInteger(R.styleable.RedTextButton_textSize, 18);
    }

AttributeSet:参数的集合,其实可以通过getAttributeName()和getAttributeValue()获得所有属性的key和value。但是为什么还要使用TypeArray呢?因为如果value是引用类型如"@string/app_name",那么它获得的value将是@+一串数字,如果要把这些数字解析出来,则还需要写代码完成这项工作,而TypeArray是简化了我们的工作。参考TextView获取属性的代码,可见系统也是这样做的

        /*
         * Look the appearance up without checking first if it exists because
         * almost every TextView has one and it greatly simplifies the logic
         * to be able to parse the appearance first and then let specific tags
         * for this View override it.
         */
        TypedArray a = theme.obtainStyledAttributes(attrs,
                com.android.internal.R.styleable.TextViewAppearance, defStyleAttr, defStyleRes);
        TypedArray appearance = null;
        int ap = a.getResourceId(
                com.android.internal.R.styleable.TextViewAppearance_textAppearance, -1);
        a.recycle();
        ....
  • 如果直接使用系统的属性,则直接在attrs.xml中声明
<resources>
    <declare-styleable name="RedTextButton">
        <attr name="backgroundColor" format="color"/>
        <attr name="textSize" format="integer"/>
        <attr name="android:text"/>
    </declare-styleable>
</resources>

5 自定义控件的步骤

步骤如下:

  1. 自定义属性
  2. 在customView中获取这些属性
  3. 重写onMesure。老师没有说,但是不写好像有一丢丢的问题
  4. 重写onDraw。绘制
    既然步骤知道了,那就开始。自定义属性和获取属性上面已经介绍一遍了,接下来就是重写一系列方法
  • 重写draw方法
      /**
     *
     * @param canvas 绘图工具
     */
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        mPanit.setTextSize(mTextSize);
        //获取文字四周的矩形,文字,开始的位置,结束的位置,把文字的四周边距计算出来放在mRect中
        mPanit.getTextBounds(mText, 0, mText.length(), mRect);

        float textWidth = mRect.width();
        float textHeight = mRect.height();

        mPanit.setColor(mBackGroundColor);
        canvas.drawRect(0f, 0f, getMeasuredWidth(),getMeasuredHeight() ,mPanit);

        //中间一个白色的数字
        mPanit.setColor(Color.WHITE);
        canvas.drawText(mText, getWidth() / 2 - textWidth / 2, getHeight() / 2 + textHeight / 2, mPanit);

        mPanit.setColor(Color.YELLOW);
        canvas.drawLine(0, getHeight() / 2, getWidth(), getHeight() / 2, mPanit);

    }

布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >

    <com.example.myactionbardemo.RedTextButton
        android:id="@+id/my"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_marginLeft="2dp"
        android:layout_marginTop="2dp"
        app:text="10"
        app:backgroundColor="@color/myColor"
        app:textSize="70sp"/>
  
</LinearLayout>

显示如下


这里写图片描述

如果把宽高改成wrapcontent,则会变成(数字我设置了点击事件所以变了)。不符合


这里写图片描述

所以需要重写onMesure方法
重写之前了解 MeasureSpec 的 specMode,一共分为三种类型:
EXACTLY:一般表示设置了 明确值,或者 match_parent ;
AT_MOST:表示子控件限制在一个最大值内,一般为 wrap_content;
UNSPECIFIED:表示子控件像多大就多大,很少使用

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        int width;
        int height;

        if (widthMode == MeasureSpec.EXACTLY){
            width = widthSize;
        }else {

            mPanit.setTextSize(mTextSize);
            //获取文字四周的矩形,文字,开始的位置,结束的位置,把文字的四周边距计算出来放在mRecr中
            mPanit.getTextBounds(mText, 0, mText.length(), mRect);
            int desired = getPaddingLeft() + getPaddingRight() + mRect.width();
            width = desired;
        }

        if (heightMode == MeasureSpec.EXACTLY)
        {
            height = heightSize;
        } else
        {

            mPanit.setTextSize(mTextSize);
            //获取文字四周的矩形,文字,开始的位置,结束的位置,把文字的四周边距计算出来放在mRecr中
            mPanit.getTextBounds(mText, 0, mText.length(), mRect);
            int desired = (getPaddingTop()  + getPaddingBottom() + mRect.height());
            height = desired;
        }
       setMeasuredDimension(width, height);
    }

然后wrapcontent就会变成

这里写图片描述

但是还有一个问题就是文字看上去不是那么居中,这篇博客关于文字居中写得特别的详细怎么绘制居中文字,码着学习。
最后给view添加一个点击事件,点击一下数字会减少

    @Override
    public void onClick(View view) {

        int mNumber = Integer.parseInt(mText);
        if (mNumber > 0){
            mNumber--;

        }else {
            mNumber = 10;
        }
        mText=String.valueOf(mNumber);
        invalidate();
    }

tips:
自定义控件水太深
我现在有点饿

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容