欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

SeniorUI33_自定义控件的概括

程序员文章站 2022-05-28 19:56:19
...

SeniorUI_高级UI汇总目录
自定义控件一般分为三类:继承控件、自绘控件、组合控件
可以直接看第四部分: 自定义控件onMeasure的常见“套路”

一 继承控件

指继承系统的原生控件,修改或者装饰系统控件某些方法

  • 看系统控件里面是否有控件 能够支持 (50%-80%)产品功能
  • 在原有基础上 添加特定场景的产品功能。

1 Demo

public class ASpecImageView extends ImageView {

    public ASpecImageView(Context context) {
        super(context);
    }

    public ASpecImageView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public ASpecImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int desiredSizeWidth;
        float aspect;

        Drawable d = getDrawable();
        if (d == null) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            return;
        }

        desiredSizeWidth = d.getIntrinsicWidth();
        aspect = (float) d.getIntrinsicWidth() / (float) d.getIntrinsicHeight();

        int widthsSize = View.resolveSize(desiredSizeWidth, widthMeasureSpec);

        int heightSize = (int) (widthsSize/ aspect);
        int specMode = MeasureSpec.getMode(heightMeasureSpec);
        int specSize = MeasureSpec.getSize(heightMeasureSpec);

        if (specMode == MeasureSpec.AT_MOST || specMode == MeasureSpec.EXACTLY) {
            if (heightSize > specSize) {
                heightSize = specSize;
                widthsSize = (int) (heightSize * aspect);
            }
        }
        setMeasuredDimension(widthsSize, heightSize);
    }
}

2 效果

SeniorUI33_自定义控件的概括

3 代码地址

AspecImageViewActivity

二 自绘控件

  • 系统的控件库中找不到 相似逻辑的额控件
  • 完成 产品逻辑不规则 / 较为特殊的产品需求, 需要自己进行绘制
  • 封装性/适配性
  • 知识点 canvas path
    invalidate();
    postInvalidate();

1 Demo

public class DoubleImageView extends View {

    /*Image Contents*/
    private Drawable mLeftDrawable, mRightDrawable;
    /*Text Contents*/
    private CharSequence mText;
    private StaticLayout mTextLayout;
    /*Text Drawing*/
    private TextPaint mTextPaint;
    private Point mTextOrigin;
    private int mSpacing;
    private int desiredWidth;


    public DoubleImageView(Context context) {
        this(context, null);
    }

    public DoubleImageView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public DoubleImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView(context, attrs, defStyleAttr);
    }

    private void initView(Context context, AttributeSet attrs, int defStyle) {
        mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
        mTextOrigin = new Point(0, 0);

        TypedArray a = context.obtainStyledAttributes(attrs,
                R.styleable.DoubleImageView, 0, defStyle);
        Drawable d = a.getDrawable(R.styleable.DoubleImageView_android_drawableLeft);
        if (d != null) {
            setLeftDrawable(d);
        }
        d = a.getDrawable(R.styleable.DoubleImageView_android_drawableRight);
        if (d != null) {
            setRightDrawable(d);
        }

        int spacing = a.getDimensionPixelOffset(R.styleable.DoubleImageView_android_spacing, 0);
        setSpacing(spacing);

        int color = a.getColor(R.styleable.DoubleImageView_android_textColor, 0);
        mTextPaint.setColor(color);

        int rawSize = a.getDimensionPixelSize(R.styleable.DoubleImageView_android_textSize, 0);
        mTextPaint.setTextSize(rawSize);

        CharSequence text = a.getText(R.styleable.DoubleImageView_android_text);
        setText(text);
        a.recycle();
    }


    public void setLeftDrawableResource(int resId) {
        Drawable d = getResources().getDrawable(resId);
        setLeftDrawable(d);
    }

    public void setLeftDrawable(Drawable left) {
        mLeftDrawable = left;
        updateContentBounds();
        invalidate();
    }

    public void setRightDrawableResource(int resId) {
        Drawable d = getResources().getDrawable(resId);
        setRightDrawable(d);
    }

    public void setRightDrawable(Drawable right) {
        mRightDrawable = right;
        updateContentBounds();
        invalidate();
    }

    public void setSpacing(int spacing) {
        mSpacing = spacing;
        updateContentBounds();
        invalidate();
    }

    public void setText(CharSequence text) {
        if (!TextUtils.equals(mText, text)) {
            mText = text;
            updateContentBounds();
            invalidate();
        }
    }

    private void updateContentBounds() {
        if (mText == null) {
            mText = "";
        }
        float textWidth = mTextPaint.measureText(mText, 0, mText.length());
        mTextLayout = new StaticLayout(mText, mTextPaint, (int) textWidth, Layout.Alignment.ALIGN_CENTER, 1f, 0f, true);
        int left = (getWidth() - getDesiredWidth()) / 2;
        int top = (getHeight() - getDesireHeight()) / 2;

        if(mLeftDrawable != null){
            mLeftDrawable.setBounds(left, top, left + mLeftDrawable.getIntrinsicWidth(), top + mLeftDrawable.getIntrinsicHeight());
            left += (mLeftDrawable.getIntrinsicWidth() * 0.33f);
            top += (mLeftDrawable.getIntrinsicHeight() * 0.33f);
        }


        if (mRightDrawable != null) {
            mRightDrawable.setBounds(left, top, left + mRightDrawable.getIntrinsicWidth(), top + mRightDrawable.getIntrinsicHeight());
            left = mRightDrawable.getBounds().right + mSpacing;
        }


        if (mTextLayout != null) {
            top = (getHeight() - mTextLayout.getHeight()) /2;
            mTextOrigin.set(left, top);
        }
    }


    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        if (w != oldw || h != oldh) {
            updateContentBounds();
            invalidate();
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (mLeftDrawable != null) {
            mLeftDrawable.draw(canvas);
        }
        if (mTextLayout != null) {
            canvas.save();
            canvas.translate(mTextOrigin.x, mTextOrigin.y);
            mTextLayout.draw(canvas);
            canvas.restore();
        }
        if (mRightDrawable != null) {
            mRightDrawable.draw(canvas);
        }
    }

    public int getDesiredWidth() {
        int leftWidth;
        if (mLeftDrawable == null) {
            leftWidth = 0;
        } else {
            leftWidth = mLeftDrawable.getIntrinsicWidth();
        }
        int rightWidth;
        if (mRightDrawable == null) {
            rightWidth = 0;
        } else {
            rightWidth = mRightDrawable.getIntrinsicWidth();
        }
        int textWidth;
        if (mTextLayout == null) {
            textWidth = 0;
        } else {
            textWidth = mTextLayout.getWidth();
        }
        return (int) (leftWidth * 0.67f) + (int) (rightWidth * 0.67f) + mSpacing + textWidth;
    }

    private int getDesireHeight(){
        int leftHeight;
        if (mLeftDrawable == null) {
            leftHeight = 0;
        } else {
            leftHeight = mLeftDrawable.getIntrinsicHeight();
        }

        int rightHeight;
        if (mRightDrawable == null) {
            rightHeight = 0;
        } else {
            rightHeight = mRightDrawable.getIntrinsicHeight();
        }
        return (int)(leftHeight * 0.67f) + (int)(rightHeight * 0.67f);
    }

}

2 效果图

SeniorUI33_自定义控件的概括

3 代码

DoubleImageViewActivity

三 组合控件

比较简单,注意属性的声明

1 Demo

public class CustomTextView extends RelativeLayout{

    //文字
    private String leftTvString;//左边文字
    private String rightTvString;//右边文字
    private String centerTvString;//中间文字
    private String leftTopTvString;//左上文字
    private String leftBottomTvString;//左下文字
    private int leftTvSize;//左边文字大小
    private int rightTvSize;//右边文字大小
    private int centerTvSize;//中间文字大小
    private int leftTopTvSize;//左上文字大小
    private int leftBottomTvSize;//左下文字大小
    private int leftTvMarginleft;//左边文字左边距
    private int rightTvMarginright;//右边文字右边距
    private int leftTopTvColor;//左上文字颜色
    private int leftBottomTvColor;//左下文字颜色
    private int leftTvColor;//左边文字颜色
    private int rightTvColor;//右边文字颜色
    private int centerTvColor;//中间文字颜色

    //图片
    private Drawable rightImgRes;//右边图片资源
    private Drawable leftImgRes;//左边图片资源
    private int leftImgWidht;//左边图片宽带
    private int leftImgHeight;//左边图片高度
    private int rightImgWidht;//右边图片宽带
    private int rightImgHeight;//右边图片高度
    private int leftImgMarginleft;//左边图片左边距
    private int rightImgMarginright;//右边图片右边距
    private int centerTVMarginleft;//中间文字左边距
    private int leftTopTvMarginTop;//左上文字上边距
    private int leftTopTvMarginleft;//左上文字左边就
    private int leftBottomTvMarginleft;//左下文字左边距
    private int leftButtomTvMarginBottom;//左下文字下边距
    //下划线margin
    private int bottomLineMargin;
    private boolean bottomLineShow;
    private int bottomLineHeight;
    private int bottomcolor;

    //一些默认属性
    private int defaultTvColor = 0xFF373737;//文字默认颜色
    private TextView leftTv, centerTv, rightTv,leftTopTv,leftBottomTv;
    private ImageView leftIV, rightIV;
    private View bottomView;
    private Context mContext;


    private OnTextViewClickListener OnTextViewClickListener;

    public CustomTextView setOnTextViewClickListener(OnTextViewClickListener listener) {
        this.OnTextViewClickListener = listener;
        return this;
    }

    public CustomTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.mContext = context;
        initAttr(attrs);
        initLayout();
        this.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (OnTextViewClickListener != null) {
                    OnTextViewClickListener.OnTextViewClick();
                }
            }
        });
    }

    private void initAttr(AttributeSet attrs) {
        TypedArray typedArray = mContext.obtainStyledAttributes(attrs, R.styleable.CustomTextView);
        leftTvString = typedArray.getString(R.styleable.CustomTextView_leftTvString);
        rightTvString = typedArray.getString(R.styleable.CustomTextView_rightTvString);
        centerTvString = typedArray.getString(R.styleable.CustomTextView_centerTvString);
        leftTopTvString = typedArray.getString(R.styleable.CustomTextView_leftTopTvString);
        leftBottomTvString = typedArray.getString(R.styleable.CustomTextView_leftBottomTvString);
        leftTvSize = typedArray.getDimensionPixelOffset(R.styleable.CustomTextView_leftTvSize, 16);
        rightTvSize = typedArray.getDimensionPixelOffset(R.styleable.CustomTextView_rightTvSize, 16);
        centerTvSize = typedArray.getDimensionPixelOffset(R.styleable.CustomTextView_centerTvSize, 16);
        leftImgRes = typedArray.getDrawable(R.styleable.CustomTextView_leftImg);
        rightImgRes = typedArray.getDrawable(R.styleable.CustomTextView_rightImg);
        leftTvColor = typedArray.getColor(R.styleable.CustomTextView_leftTvColor, defaultTvColor);
        rightTvColor = typedArray.getColor(R.styleable.CustomTextView_rightTvColor, defaultTvColor);
        centerTvColor = typedArray.getColor(R.styleable.CustomTextView_centerTvColor, defaultTvColor);
        leftImgWidht = typedArray.getDimensionPixelOffset(R.styleable.CustomTextView_leftImgWight, 0);
        leftImgHeight = typedArray.getDimensionPixelOffset(R.styleable.CustomTextView_leftImgHeight, 0);
        rightImgWidht = typedArray.getDimensionPixelOffset(R.styleable.CustomTextView_rightImgWidht, 0);
        rightImgHeight = typedArray.getDimensionPixelOffset(R.styleable.CustomTextView_rightImgHeight, 0);
        leftTvMarginleft = typedArray.getDimensionPixelOffset(R.styleable.CustomTextView_leftTvMarginleft, 0);
        rightTvMarginright = typedArray.getDimensionPixelOffset(R.styleable.CustomTextView_rightTvMarginright, 0);
        leftImgMarginleft = typedArray.getDimensionPixelOffset(R.styleable.CustomTextView_leftImgMarginleft, 0);
        rightImgMarginright = typedArray.getDimensionPixelOffset(R.styleable.CustomTextView_rightImgMarginright, 0);
        bottomLineMargin = typedArray.getDimensionPixelOffset(R.styleable.CustomTextView_bottomLineMargin, 0);
        bottomLineShow = typedArray.getBoolean(R.styleable.CustomTextView_bottomLineShow, false);
        bottomLineHeight = typedArray.getDimensionPixelOffset(R.styleable.CustomTextView_bottomLineHeight, 1);
        bottomcolor = typedArray.getColor(R.styleable.CustomTextView_bottomcolor, defaultTvColor);
        centerTVMarginleft = typedArray.getDimensionPixelOffset(R.styleable.CustomTextView_centerTVMarginleft, 0);
        leftTopTvMarginTop = typedArray.getDimensionPixelOffset(R.styleable.CustomTextView_leftTopTvMarginTop, 0);
        leftTopTvMarginleft = typedArray.getDimensionPixelOffset(R.styleable.CustomTextView_leftTopTvMarginleft, 0);
        leftBottomTvMarginleft = typedArray.getDimensionPixelOffset(R.styleable.CustomTextView_leftBottomTvMarginleft, 0);
        leftButtomTvMarginBottom = typedArray.getDimensionPixelOffset(R.styleable.CustomTextView_leftButtomTvMarginBottom, 0);
        leftTopTvSize = typedArray.getDimensionPixelOffset(R.styleable.CustomTextView_leftTopTvSize, 16);
        leftBottomTvSize = typedArray.getDimensionPixelOffset(R.styleable.CustomTextView_leftBottomTvSize, 16);
        leftTopTvColor = typedArray.getColor(R.styleable.CustomTextView_leftTopTvColor, defaultTvColor);
        leftBottomTvColor = typedArray.getColor(R.styleable.CustomTextView_leftBottomTvColor, defaultTvColor);

        typedArray.recycle();
    }

    private void initLayout() {
        //左边图片初始化
        if (leftImgRes != null) {
            initLeftImg();
        }
        //左边文字初始化
        if (!TextUtils.isEmpty(leftTvString)) {
            initLeftTv();
        }
        //中间文字初始化
        if (!TextUtils.isEmpty(centerTvString)) {
            initCenterTv();
        }
        //左上文字初始化
        if(!TextUtils.isEmpty(leftTopTvString)){
            initLeftTopTv();
        }
        //左下文字初始化
        if(!TextUtils.isEmpty(leftBottomTvString)){
            initLeftBottomTv();
        }

        //右边图片初始化
        if (rightImgRes != null) {
            initRightImg();
        }
        //右边的文字初始
        if (!TextUtils.isEmpty(rightTvString)) {
            initRightTv();
        }
        //下边线初始化
        if (bottomLineShow) {
            initBottomLine();
        }
    }

    //以下是设置字体和图片的属性,,为了适配最好不要动态设置与数字有关的属性
    //代码设置左边文字
    public CustomTextView setLeftTv(String tvStr, String tvColor) {
        leftTvString = TextUtils.isEmpty(tvStr) ? leftTvString : tvStr;
        leftTvColor = TextUtils.isEmpty(tvColor) ? leftTvColor : Color.parseColor(tvColor);
        if (leftTv == null) {
            initLeftTv();
        } else {
            leftTv.setText(leftTvString);
            leftTv.setTextColor(leftTvColor);
        }
        return this;
    }

    //代码设置右边文字
    public CustomTextView setRightTv(String tvStr, String tvColor) {
        rightTvString = TextUtils.isEmpty(tvStr) ? rightTvString : tvStr;
        rightTvColor = TextUtils.isEmpty(tvColor) ? rightTvColor : Color.parseColor(tvColor);
        if (rightTv == null) {
            initRightTv();
        } else {
            rightTv.setText(rightTvString);
            rightTv.setTextColor(rightTvColor);
        }

        return this;
    }

    //代码设置中间文字
    public CustomTextView setCenterTv(String tvStr, String tvColor) {
        centerTvString = TextUtils.isEmpty(tvStr) ? centerTvString : tvStr;
        centerTvColor = TextUtils.isEmpty(tvColor) ? centerTvColor : Color.parseColor(tvColor);
        if (centerTv == null) {
            initCenterTv();
        } else {
            centerTv.setText(centerTvString);
            centerTv.setTextColor(centerTvColor);
        }
        return this;
    }

    //代码设置左上文字颜色
    public CustomTextView setLeftTopTv(String tvStr,String tvColor){
        leftTopTvString=TextUtils.isEmpty(tvStr)?leftTopTvString:tvStr;
        leftTopTvColor=TextUtils.isEmpty(tvColor)?leftTopTvColor:Color.parseColor(tvColor);
        if(leftTopTv==null){
            initLeftTopTv();
        }else{
            leftTopTv.setTextColor(leftTopTvColor);
            leftTopTv.setText(leftTopTvString);
        }
        return this;
    }
    //代码设置左下文字颜色
    public CustomTextView setLeftBottomTv(String tvStr,String tvColor){
        leftBottomTvString=TextUtils.isEmpty(tvStr)?leftBottomTvString:tvStr;
        leftBottomTvColor=TextUtils.isEmpty(tvColor)?leftBottomTvColor:Color.parseColor(tvColor);
        if(leftBottomTv==null){
            initLeftBottomTv();
        }else{
            leftBottomTv.setTextColor(leftBottomTvColor);
            leftBottomTv.setText(leftBottomTvString);
        }
        return this;
    }


    //代码设置布局背景颜色
    public CustomTextView setCustomTvBackground(String strColor){
        CustomTextView.this.setBackgroundColor(Color.parseColor(strColor));
        return this;
    }


    //代码设置左边图片
    public CustomTextView setLeftImg(Drawable icRes) {
        leftImgRes = icRes;
        if (leftIV == null) {
            initLeftImg();
        } else {
            leftIV.setImageDrawable(leftImgRes);
        }
        return this;
    }

    //代码设置右边图片
    public CustomTextView setRightImg(Drawable icRes) {
        rightImgRes = icRes;
        if (rightIV == null) {
            initRightImg();
        } else {
            rightIV.setImageDrawable(rightImgRes);
        }
        return this;
    }

    //设置下划线
    public CustomTextView setBottomLine(String color) {
        bottomcolor = TextUtils.isEmpty(color) ? bottomcolor : Color.parseColor(color);
        if (bottomView == null) {
            initBottomLine();
        } else {
            bottomView.setBackgroundColor(bottomcolor);
        }
        return this;
    }

    private void initLeftImg() {
        leftIV = new ImageView(mContext);
        int width = leftImgWidht != 0 ? leftImgWidht : LayoutParams.WRAP_CONTENT;
        int height = leftImgHeight != 0 ? leftImgHeight : LayoutParams.WRAP_CONTENT;
        LayoutParams leftImgParams = new LayoutParams(width, height);
        leftImgParams.addRule(ALIGN_PARENT_LEFT, TRUE);
        leftImgParams.addRule(RelativeLayout.CENTER_VERTICAL, TRUE);
        leftImgParams.setMargins(leftImgMarginleft, 0, 0, 0);
        leftIV.setScaleType(ImageView.ScaleType.FIT_XY);
        leftIV.setId(R.id.leftImg);
        leftIV.setLayoutParams(leftImgParams);
        leftIV.setImageDrawable(leftImgRes);
        leftIV.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (OnTextViewClickListener != null) {
                    OnTextViewClickListener.OnLeftImgClick();
                }
            }
        });
        addView(leftIV);
    }

    private void initLeftTv() {
        leftTv = new TextView(mContext);
        LayoutParams leftTvParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
        leftTvParams.addRule(RelativeLayout.CENTER_VERTICAL, TRUE);
        leftTvParams.addRule(RelativeLayout.RIGHT_OF, R.id.leftImg);
        leftTvParams.setMargins(leftTvMarginleft, 0, 0, 0);
        leftTv.setLayoutParams(leftTvParams);
        leftTv.setTextColor(leftTvColor);
        leftTv.setId(R.id.leftTv);
        leftTv.setTextSize(TypedValue.COMPLEX_UNIT_PX, leftTvSize);
        leftTv.setText(leftTvString);
        addView(leftTv);
    }

    private void initCenterTv() {
        centerTv = new TextView(mContext);
        LayoutParams centerTvParams = new LayoutParams(LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        centerTvParams.addRule(centerTVMarginleft != 0 && !TextUtils.isEmpty(leftTvString) ? RelativeLayout.RIGHT_OF : RelativeLayout.CENTER_IN_PARENT, centerTVMarginleft != 0 && !TextUtils.isEmpty(leftTvString) ? R.id.leftTv : TRUE);
        centerTvParams.addRule(RelativeLayout.CENTER_VERTICAL);
        centerTvParams.setMargins(centerTVMarginleft, 0, 0, 0);
        centerTv.setLayoutParams(centerTvParams);
        centerTv.setTextColor(centerTvColor);
        centerTv.setTextSize(TypedValue.COMPLEX_UNIT_PX, centerTvSize);
        centerTv.setText(centerTvString);
        addView(centerTv);
    }

    private void initLeftTopTv(){
        leftTopTv=new TextView(mContext);
        LayoutParams leftTopTvParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
        leftTopTvParams.addRule(RelativeLayout.RIGHT_OF, R.id.leftImg);
        leftTopTvParams.addRule(RelativeLayout.ALIGN_PARENT_TOP,TRUE);
        leftTopTvParams.setMargins(leftTopTvMarginleft,leftTopTvMarginTop,0,0);
        leftTopTv.setLayoutParams(leftTopTvParams);
        leftTopTv.setTextSize(TypedValue.COMPLEX_UNIT_PX,leftTopTvSize);
        leftTopTv.setTextColor(leftTopTvColor);
        leftTopTv.setText(leftTopTvString);
        addView(leftTopTv);
    }

    private void initLeftBottomTv(){
        leftBottomTv=new TextView(mContext);
        LayoutParams leftBottomTvParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
        leftBottomTvParams.addRule(RelativeLayout.RIGHT_OF, R.id.leftImg);
        leftBottomTvParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM,TRUE);
        leftBottomTvParams.setMargins(leftBottomTvMarginleft,0,0,leftButtomTvMarginBottom);
        leftBottomTv.setLayoutParams(leftBottomTvParams);
        leftBottomTv.setTextSize(TypedValue.COMPLEX_UNIT_PX,leftBottomTvSize);
        leftBottomTv.setTextColor(leftBottomTvColor);
        leftBottomTv.setText(leftBottomTvString);
        addView(leftBottomTv);
    }


    private void initRightImg() {
        rightIV = new ImageView(mContext);
        int width = rightImgWidht != 0 ? rightImgWidht : LayoutParams.WRAP_CONTENT;
        int height = rightImgHeight != 0 ? rightImgHeight : LayoutParams.WRAP_CONTENT;
        LayoutParams rightIVParams = new LayoutParams(width, height);
        rightIVParams.addRule(RelativeLayout.CENTER_VERTICAL, TRUE);
        rightIVParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, TRUE);
        rightIVParams.setMargins(0, 0, rightImgMarginright, 0);
        rightIV.setScaleType(ImageView.ScaleType.FIT_XY);
        rightIV.setId(R.id.rightImg);
        rightIV.setLayoutParams(rightIVParams);
        rightIV.setImageDrawable(rightImgRes);
        rightIV.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (OnTextViewClickListener != null) {
                    OnTextViewClickListener.OnRightImgClick();
                }
            }
        });
        addView(rightIV);

    }

    private void initRightTv() {
        rightTv = new TextView(mContext);
        LayoutParams rightTvParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
        rightTvParams.addRule(rightImgRes != null ? RelativeLayout.LEFT_OF : RelativeLayout.ALIGN_PARENT_RIGHT, rightImgRes != null ? R.id.rightImg : TRUE);
        rightTvParams.addRule(RelativeLayout.CENTER_VERTICAL);
        rightTvParams.setMargins(0, 0, rightTvMarginright, 0);
        rightTv.setLayoutParams(rightTvParams);
        rightTv.setTextColor(rightTvColor);
        rightTv.setTextSize(TypedValue.COMPLEX_UNIT_PX, rightTvSize);
        rightTv.setText(rightTvString);
        rightTv.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (OnTextViewClickListener != null) {
                    OnTextViewClickListener.OnRightTvClick();
                }
            }
        });

        addView(rightTv);
    }

    private void initBottomLine() {
        bottomView = new View(mContext);
        LayoutParams bottomParams = new LayoutParams(LayoutParams.WRAP_CONTENT, bottomLineHeight);
        bottomParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, TRUE);
        bottomParams.setMargins(bottomLineMargin, 0, bottomLineMargin, 0);
        bottomView.setLayoutParams(bottomParams);
        bottomView.setBackgroundColor(bottomcolor);
        addView(bottomView);
    }

    //点击事件接口
    public static class OnTextViewClickListener {
        public void OnLeftImgClick() {
        }

        public void OnRightImgClick() {
        }

        public void OnTextViewClick() {
        }

        public void OnRightTvClick() {

        }

    }
}

2 效果图

SeniorUI33_自定义控件的概括

3 代码

CustomTextViewActivity

四 自定义控件onMeasure的常见“套路”

1 继承自View的子类

			只需要重写onMeasure测量好自己的宽高就可以了。
			最终调用setMeasuredDimension()保存好自己的测量宽高。
				int mode = MeasureSpec.getMode(widthMeasureSpec);
				int Size = MeasureSpec.getSize(widthMeasureSpec);
				int viewSize = 0;
				switch(mode){
					case MeasureSpec.EXACTLY:
						viewSize = size;//当前view的尺寸就为父容器的尺寸
						break;
					case MeasureSpec.AT_MOST:
						viewSize = Math.min(size, getContentSize());//当前view的尺寸就为内容尺寸和费容器尺寸当中的最小值。
						break;
					case MeasureSpec.UNSPECIFIED:
						viewSize = getContentSize();//内容有多大,久设置多大尺寸。
						break;
					default:
						break;
				}
				
				view 提供的api: public static int resolveSize(int size, int measureSpec) 

2 继承自ViewGroup的子类

不但需要重写onMeasure测量自己,还要测量子控件的规格大小。
				可以直接使用ViewGroup的工具方法来测量里面的子控件,也可以自己来实现这一套子控件的测量(比如:RelativeLayout)
					
				//1.测量自己的尺寸
						ViewGroup.onMeasure();
				//1.1 为每一个child计算测量规格信息(MeasureSpec)
						ViewGroup.getChildMeasureSpec();
				//1.2 将上面测量后的结果,传给每一个子View,子view测量自己的尺寸
						child.measure();

				//1.3 子View测量完,ViewGroup就可以拿到这个子View的测量后的尺寸了
					child.getChildMeasuredSize();//child.getMeasuredWidth()和child.getMeasuredHeight()
				//1.4ViewGroup自己就可以根据自身的情况(Padding等等),来计算自己的尺寸
						ViewGroup.calculateSelfSize();
				//2.保存自己的尺寸
				ViewGroup.setMeasuredDimension(size);
				  ViewGroup中提供的Measure相关的api:
					measureChild
					measureChildren(所有)
					measureChildWithMargins
				    getChildMeasureSpec