美文网首页Android开发
自定义view代替点9图

自定义view代替点9图

作者: 43d60efa37c7 | 来源:发表于2018-10-30 16:50 被阅读7次

项目中有一些弹窗和聊天的文字背景框,点9图有点难用,用代码绘制这种有一个尖角的圆角矩形。可以设置三角的位置,整体颜色,圆角大小。


黑色透明框和白色框.jpg

记录一下,还有一些情况没有处理,现在在布局中设置padding,是矩形的内边距,不用考虑尖角的长宽,但是获取padding时会加上,还需要完善

/**
 * 有一个尖角的圆角矩形
 */
//TODO 处理padding,以获取更一致的符合预期的padding值
//TODO 处理设置不合理数值的情况,比如offset过大过小等等
public class ChatLinearLayout extends LinearLayout {

    
    int chatBackgroundColor = Color.parseColor("#000000");
    // 尖角的位置
    int triangleGravity = 0;
    private static final int LEFT = 0;
    private static final int RIGHT = 1;
    private static final int TOP = 2;
    private static final int BOTTOM = 3;

    // 尖角基准位置,配合offset
    // BASE_START 当triangleGravity为LEFT,RIGHT时候,offset就是尖角和ChatLinearLayout的top的距离,BASE_END是到bottom的距离
    // 当triangleGravity为TOP、BOTTOM的时候,offset是尖角和ChatLinearLayout的left的距离,BASE_END是到right的距离
    // 为CENTER,就是在中间
    int base = 2;
    private static final int BASE_START = 0;
    private static final int BASE_END = 1;
    private static final int CENTER = 2;

    // 圆角半径
    private float cornerRadius = 0;
    Paint mPaint = new Paint();
    RectF rectF = new RectF();
    Path mPath = new Path();
    // 尖角宽(x轴上的长度)
    private float triangleWidth = 0f;
    // 尖角高(y轴上的长度)
    private float triangleHeight = 0f;
    // 偏移位置,xml中给定的
    private float offset;
    // 尖角距离左边或者上边的距离
    private float triangleOffset = 0f;
    private int paddingLeft;
    private int paddingRight;
    private int paddingTop;
    private int paddingBottom;


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

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

    public ChatLinearLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ChatLinearLayout, defStyleAttr, 0);
        // 颜色
        chatBackgroundColor = typedArray.getColor(R.styleable.ChatLinearLayout_chatBackgroundColor, Color.parseColor("#000000"));
        // 尖角位置
        triangleGravity = typedArray.getInt(R.styleable.ChatLinearLayout_triangleGravity, LEFT);
        // 基准
        base = typedArray.getInt(R.styleable.ChatLinearLayout_base, CENTER);
        // 距离
        offset = typedArray.getDimension(R.styleable.ChatLinearLayout_offset, Utils.dp2px(getContext(), 10));
        // 圆角半径
        cornerRadius = typedArray.getDimension(R.styleable.ChatLinearLayout_cornerRadius, Utils.dp2px(getContext(), 5));
        // 尖角宽
        triangleWidth = typedArray.getDimension(R.styleable.ChatLinearLayout_triangleWidth, Utils.dp2px(getContext(), 5));
        // 尖角高
        triangleHeight = typedArray.getDimension(R.styleable.ChatLinearLayout_triangleHeight, Utils.dp2px(getContext(), 8));
        mPaint.setColor(chatBackgroundColor);
        mPaint.setAntiAlias(true);
        setWillNotDraw(false);
        typedArray.recycle();

        paddingLeft = getPaddingLeft();
        paddingRight = getPaddingRight();
        paddingTop = getPaddingTop();
        paddingBottom = getPaddingBottom();

        adjustPadding();

    }
    // 把尖角算入padding中,会调用invalidate()
    private void adjustPadding(){
        switch (triangleGravity){
            case LEFT:
                setPadding((int) (paddingLeft + triangleWidth), paddingTop, paddingRight, paddingBottom);
                break;
            case RIGHT:
                setPadding(paddingLeft, paddingTop, (int) (paddingRight +triangleWidth), paddingBottom);
                break;
            case TOP:
                setPadding(paddingLeft, (int) (paddingTop + triangleHeight), paddingRight, paddingBottom);
                break;
            case BOTTOM:
                setPadding(paddingLeft, paddingTop, paddingRight, (int) (paddingBottom + triangleHeight));
                break;
        }
    }
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        float measuredWidth = getMeasuredWidth();
        float measuredHeight = getMeasuredHeight();
        if (base == CENTER) {
            triangleOffset = -1;
        } else if (base == BASE_END) {
            // 与结束位置偏移
            if (triangleGravity == LEFT || triangleGravity == RIGHT) {
                // 尖角在左右
                triangleOffset = measuredHeight - triangleHeight - offset;
            } else {
                // 在上下
                triangleOffset = measuredWidth - triangleWidth - offset;
            }
        } else {
            // 与开始位置偏移
            triangleOffset = offset;
        }
        if (triangleOffset < 0) {
            if (triangleGravity == LEFT || triangleGravity == RIGHT) {
                triangleOffset = getMeasuredHeight() / 2 - triangleHeight / 2;
            } else {
                triangleOffset = getMeasuredWidth() / 2 - triangleWidth / 2;
            }
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        float measuredWidth = getMeasuredWidth();
        float measuredHeight = getMeasuredHeight();
        mPath.reset();
        switch (triangleGravity) {
            case LEFT:
                // 尖角在左边
                // 画矩形
                rectF.set(triangleWidth, 0f, measuredWidth, measuredHeight);
                // 画尖角
                mPath.moveTo(rectF.left, triangleOffset);//上面的点
                mPath.lineTo(0, triangleOffset + triangleHeight / 2);// 中间的点
                mPath.lineTo(rectF.left, triangleOffset + triangleHeight);// 下面的点
                break;
            case RIGHT:
                // 尖角在右边
                // 画矩形
                rectF.set(0f, 0f, measuredWidth - triangleWidth, measuredHeight);
                // 画尖角
                mPath.moveTo(rectF.right, triangleOffset);//上面的点
                mPath.lineTo(measuredWidth, triangleOffset + triangleHeight / 2);// 中间的点
                mPath.lineTo(rectF.right, triangleOffset + triangleHeight);// 下面的点
                break;
            case TOP:
                // 尖角在上边
                // 画矩形
                rectF.set(0f, triangleHeight, measuredWidth, measuredHeight);
                // 画尖角
                mPath.moveTo(triangleOffset + triangleWidth / 2, 0);//中间的点
                mPath.lineTo(triangleOffset, triangleHeight);//左边的点
                mPath.lineTo(triangleOffset + triangleWidth, triangleHeight);// 右边的点
                break;
            case BOTTOM:
                // 尖角在下边
                // 画矩形
                rectF.set(0f, 0f, measuredWidth, measuredHeight - triangleHeight);
                // 画尖角
                mPath.moveTo(triangleOffset + triangleWidth / 2, measuredHeight);//中间的点
                mPath.lineTo(triangleOffset, rectF.bottom);//左边的点
                mPath.lineTo(triangleOffset + triangleWidth, rectF.bottom);// 右边的点
                break;
        }
        canvas.drawRoundRect(rectF, cornerRadius, cornerRadius, mPaint);
        mPath.close();
        canvas.drawPath(mPath, mPaint);
    }

    public void setTriangleGravity(int gravity) {
        switch (gravity) {
            case Gravity.LEFT:
                triangleGravity = LEFT;
                break;
            case Gravity.RIGHT:
                triangleGravity = RIGHT;
                break;
            case Gravity.TOP:
                triangleGravity = TOP;
                break;
            case Gravity.BOTTOM:
                triangleGravity = BOTTOM;
                break;
            default:
                triangleGravity = LEFT;
                break;
        }
        adjustPadding();
    }
}

attrs里

<declare-styleable name="ChatLinearLayout">
        <attr name="triangleGravity">
            <enum name="left" value="0"/>
            <enum name="right" value="1"/>
            <enum name="top" value="2"/>
            <enum name="bottom" value="3"/>
        </attr>
        <attr name="chatBackgroundColor" format="color"/>
        <!-- 尖角位置基准 值为center的时候,offset不起作用-->
        <attr name="base">
            <enum name="start" value="0"/>
            <enum name="end" value="1"/>
            <enum name="center" value="2"/>
        </attr>
        <attr name="triangleWidth" format="dimension"/>
        <attr name="triangleHeight" format="dimension"/>
        <!-- 尖角位置 ,与start 或 end的距离-->
        <attr name="offset" format="dimension"/>
        <!-- 圆角矩形的圆角半径-->
        <attr name="cornerRadius" format="dimension"/>
    </declare-styleable>

使用举例

<com.zhulin.android.ejiaoyan.view.ChatLinearLayout
        android:id="@+id/root"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginRight="5dp"
        app:chatBackgroundColor="@color/main_color"
        app:base="end"
        app:triangleGravity="top"
        app:offset="20dp"
        app:triangleWidth="15dp"
        app:triangleHeight="10dp"
        app:cornerRadius="5dp"
        android:orientation="vertical" >
    </com.zhulin.android.ejiaoyan.view.ChatLinearLayout>

效果


截图有点糊.jpg

相关文章

网友评论

    本文标题:自定义view代替点9图

    本文链接:https://www.haomeiwen.com/subject/mbmgtqtx.html