自定义邮票锯齿背景效果

来源:互联网 发布:全国计算机考试软件 编辑:程序博客网 时间:2024/05/20 14:44

简介

最近项目中有一个需求,需要做一个类似于邮票那样的背景效果,它主要是由半圆锯齿和虚线边框结合而成。

效果图:

效果图

我用到的效果是上面图中的第一种,四周边缘是半圆锯齿,内部是虚线边框。当然,具体效果可以根据自定义属性自己定制。

使用

1、在attr.xml中定义属性

<declare-styleable name="StampView">    <!-- 半圆之间间距 -->    <attr name="sv_semicircle_gap" format="dimension|reference" />    <!-- 半圆半径 -->    <attr name="sv_semicircle_radius" format="dimension|reference" />    <!-- 半圆颜色 -->    <attr name="sv_semicircle_color" format="color|reference" />    <!-- 半圆覆盖线宽 -->    <attr name="sv_semicircle_cover_stroke_width" format="dimension|reference" />    <!-- 半圆覆盖颜色 -->    <attr name="sv_semicircle_cover_color" format="color|reference" />    <!-- 开启顶部半圆曲线 -->    <attr name="sv_semicircle_top" format="boolean|reference" />    <!-- 开启底部半圆曲线 -->    <attr name="sv_semicircle_bottom" format="boolean|reference" />    <!-- 开启左边半圆曲线 -->    <attr name="sv_semicircle_left" format="boolean|reference" />    <!-- 开启右边半圆曲线 -->    <attr name="sv_semicircle_right" format="boolean|reference" />    <!-- 虚线的长度 -->    <attr name="sv_dash_line_length" format="dimension|reference" />    <!-- 虚线的间距 -->    <attr name="sv_dash_line_gap" format="dimension|reference" />    <!-- 虚线的高度 -->    <attr name="sv_dash_line_height" format="dimension|reference" />    <!-- 虚线的颜色 -->    <attr name="sv_dash_line_color" format="color|reference" />    <!-- 顶部虚线距离View顶部的距离 -->    <attr name="sv_dash_line_top" format="boolean|reference" />    <!-- 底部虚线距离View底部的距离 -->    <attr name="sv_dash_line_bottom" format="boolean|reference" />    <!-- 左侧虚线距离View左侧的距离 -->    <attr name="sv_dash_line_left" format="boolean|reference" />    <!-- 右侧虚线距离View右侧的距离 -->    <attr name="sv_dash_line_right" format="boolean|reference" />    <!-- 开启顶部虚线 -->    <attr name="sv_dash_line_margin_top" format="dimension|reference" />    <!-- 开启底部虚线 -->    <attr name="sv_dash_line_margin_bottom" format="dimension|reference" />    <!-- 开启左边虚线 -->    <attr name="sv_dash_line_margin_left" format="dimension|reference" />    <!-- 开启左边虚线 -->    <attr name="sv_dash_line_margin_right" format="dimension|reference" /></declare-styleable>

2、布局文件

<com.wiggins.stampview.widget.StampViewLinearLayout    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:layout_margin="@dimen/margin_normal"    android:background="@drawable/stamp_view_bg"    android:orientation="vertical"    app:sv_semicircle_bottom="true"    app:sv_semicircle_color="@color/theme_bg"    app:sv_semicircle_cover_color="@color/red"    app:sv_semicircle_cover_stroke_width="1dp"    app:sv_semicircle_gap="5dp"    app:sv_semicircle_left="true"    app:sv_semicircle_radius="2.5dp"    app:sv_semicircle_right="true"    app:sv_semicircle_top="true">    <LinearLayout        android:layout_width="match_parent"        android:layout_height="80dp"        android:orientation="vertical">    </LinearLayout></com.wiggins.stampview.widget.StampViewLinearLayout>

3、自定义StampView

获取自定义属性值

public StampView(View view, Context context, AttributeSet attrs, int defStyle) {    this.context = context;    this.view = view;    TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.StampView, defStyle, 0);    semicircleRadius = a.getDimensionPixelSize(R.styleable.StampView_sv_semicircle_radius, dp2Px(DEFAULT_SEMICIRCLE_RADIUS));    semicircleGap = a.getDimensionPixelSize(R.styleable.StampView_sv_semicircle_gap, dp2Px(DEFAULT_SEMICIRCLE_GAP));    semicircleCoverStrokeWidth = a.getDimensionPixelSize(R.styleable.StampView_sv_semicircle_cover_stroke_width, dp2Px(DEFAULT_SEMICIRCLE_COVER_STROKE_WIDTH));    semicircleColor = a.getColor(R.styleable.StampView_sv_semicircle_color, DEFAULT_SEMICIRCLE_COLOR);    semicircleCoverColor = a.getColor(R.styleable.StampView_sv_semicircle_cover_color, DEFAULT_SEMICIRCLE_COLOR);    isSemicircleTop = a.getBoolean(R.styleable.StampView_sv_semicircle_top, isSemicircleTop);    isSemicircleBottom = a.getBoolean(R.styleable.StampView_sv_semicircle_bottom, isSemicircleBottom);    isSemicircleLeft = a.getBoolean(R.styleable.StampView_sv_semicircle_left, isSemicircleLeft);    isSemicircleRight = a.getBoolean(R.styleable.StampView_sv_semicircle_right, isSemicircleRight);    dashLineLength = a.getDimensionPixelSize(R.styleable.StampView_sv_dash_line_length, dp2Px(DEFAULT_DASH_LINE_LENGTH));    dashLineHeight = a.getDimensionPixelSize(R.styleable.StampView_sv_dash_line_height, dp2Px(DEFAULT_DASH_LINE_HEIGHT));    dashLineGap = a.getDimensionPixelSize(R.styleable.StampView_sv_dash_line_gap, dp2Px(DEFAULT_DASH_LINE_GAP));    dashLineColor = a.getColor(R.styleable.StampView_sv_dash_line_color, DEFAULT_DASH_LINE_COLOR);    isDashLineTop = a.getBoolean(R.styleable.StampView_sv_dash_line_top, isDashLineTop);    isDashLineBottom = a.getBoolean(R.styleable.StampView_sv_dash_line_bottom, isDashLineBottom);    isDashLineLeft = a.getBoolean(R.styleable.StampView_sv_dash_line_left, isDashLineLeft);    isDashLineRight = a.getBoolean(R.styleable.StampView_sv_dash_line_right, isDashLineRight);    dashLineMarginTop = a.getDimensionPixelSize(R.styleable.StampView_sv_dash_line_margin_top, dp2Px(DEFAULT_DASH_LINE_MARGIN));    dashLineMarginBottom = a.getDimensionPixelSize(R.styleable.StampView_sv_dash_line_margin_bottom, dp2Px(DEFAULT_DASH_LINE_MARGIN));    dashLineMarginLeft = a.getDimensionPixelSize(R.styleable.StampView_sv_dash_line_margin_left, dp2Px(DEFAULT_DASH_LINE_MARGIN));    dashLineMarginRight = a.getDimensionPixelSize(R.styleable.StampView_sv_dash_line_margin_right, dp2Px(DEFAULT_DASH_LINE_MARGIN));    a.recycle();    init();}

初始化画笔

private void init() {    semicirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);    semicirclePaint.setDither(true);    semicirclePaint.setColor(semicircleColor);    semicirclePaint.setStyle(Paint.Style.FILL);    semicirclePaintCover = new Paint(Paint.ANTI_ALIAS_FLAG);    semicirclePaintCover.setDither(true);    semicirclePaintCover.setColor(semicircleCoverColor);    semicirclePaintCover.setStyle(Paint.Style.STROKE);    semicirclePaintCover.setStrokeWidth(semicircleCoverStrokeWidth);    dashLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);    dashLinePaint.setDither(true);    dashLinePaint.setColor(dashLineColor);    dashLinePaint.setStyle(Paint.Style.FILL);}

获取View宽高

public void onSizeChanged(int w, int h) {    viewWidth = w;    viewHeight = h;    calculate();}

计算半圆锯齿和虚线边框数量和剩余距离

private void calculate() {    if (isSemicircleTop || isSemicircleBottom) {        remindSemicircleX = (int) ((viewWidth - semicircleGap) % (2 * semicircleRadius + semicircleGap));        semicircleNumX = (int) ((viewWidth - semicircleGap) / (2 * semicircleRadius + semicircleGap));    }    if (isSemicircleLeft || isSemicircleRight) {        remindSemicircleY = (int) ((viewHeight - semicircleGap) % (2 * semicircleRadius + semicircleGap));        semicircleNumY = (int) ((viewHeight - semicircleGap) / (2 * semicircleRadius + semicircleGap));    }    if (isDashLineTop || isDashLineBottom) {        remindDashLineX = (int) ((viewWidth + dashLineGap - dashLineMarginLeft - dashLineMarginRight) % (dashLineLength + dashLineGap));        dashLineNumX = (int) ((viewWidth + dashLineGap - dashLineMarginLeft - dashLineMarginRight) / (dashLineLength + dashLineGap));    }    if (isDashLineLeft || isDashLineRight) {        remindDashLineY = (int) ((viewHeight + dashLineGap - dashLineMarginTop - dashLineMarginBottom) % (dashLineLength + dashLineGap));        dashLineNumY = (int) ((viewHeight + dashLineGap - dashLineMarginTop - dashLineMarginBottom) / (dashLineLength + dashLineGap));    }}

View绘制

public void onDraw(Canvas canvas) {    if (isSemicircleTop) {        for (int i = 0; i < semicircleNumX; i++) {            float x = semicircleGap + semicircleRadius + remindSemicircleX / 2 + (semicircleGap + semicircleRadius * 2) * i;            canvas.drawCircle(x, 0, semicircleRadius, semicirclePaint);            canvas.drawCircle(x, 0, semicircleRadius, semicirclePaintCover);        }    }    if (isSemicircleBottom) {        for (int i = 0; i < semicircleNumX; i++) {            float x = semicircleGap + semicircleRadius + remindSemicircleX / 2 + (semicircleGap + semicircleRadius * 2) * i;            canvas.drawCircle(x, viewHeight, semicircleRadius, semicirclePaint);            canvas.drawCircle(x, viewHeight, semicircleRadius, semicirclePaintCover);        }    }    if (isSemicircleLeft) {        for (int i = 0; i < semicircleNumY; i++) {            float y = semicircleGap + semicircleRadius + remindSemicircleY / 2 + (semicircleGap + semicircleRadius * 2) * i;            canvas.drawCircle(0, y, semicircleRadius, semicirclePaint);            canvas.drawCircle(0, y, semicircleRadius, semicirclePaintCover);        }    }    if (isSemicircleRight) {        for (int i = 0; i < semicircleNumY; i++) {            float y = semicircleGap + semicircleRadius + remindSemicircleY / 2 + (semicircleGap + semicircleRadius * 2) * i;            canvas.drawCircle(viewWidth, y, semicircleRadius, semicirclePaint);            canvas.drawCircle(viewWidth, y, semicircleRadius, semicirclePaintCover);        }    }    if (isDashLineTop) {        for (int i = 0; i < dashLineNumX; i++) {            float x = dashLineMarginLeft + remindDashLineX / 2 + (dashLineGap + dashLineLength) * i;            canvas.drawRect(x, dashLineMarginTop, x + dashLineLength, dashLineMarginTop + dashLineHeight, dashLinePaint);        }    }    if (isDashLineBottom) {        for (int i = 0; i < dashLineNumX; i++) {            float x = dashLineMarginLeft + remindDashLineX / 2 + (dashLineGap + dashLineLength) * i;            canvas.drawRect(x, viewHeight - dashLineHeight - dashLineMarginBottom, x + dashLineLength, viewHeight - dashLineMarginBottom, dashLinePaint);        }    }    if (isDashLineLeft) {        for (int i = 0; i < dashLineNumY; i++) {            float y = dashLineMarginTop + remindDashLineY / 2 + (dashLineGap + dashLineLength) * i;            canvas.drawRect(dashLineMarginLeft, y, dashLineMarginLeft + dashLineHeight, y + dashLineLength, dashLinePaint);        }    }    if (isDashLineRight) {        for (int i = 0; i < dashLineNumY; i++) {            float y = dashLineMarginTop + remindDashLineY / 2 + (dashLineGap + dashLineLength) * i;            canvas.drawRect(viewWidth - dashLineMarginRight - dashLineHeight, y, viewWidth - dashLineMarginRight, y + dashLineLength, dashLinePaint);        }    }}

4、定制自己的StampViewLinearLayout

StampViewLinearLayout继承于LinearLayout,除了边缘半圆锯齿和虚线边框之外,它和普通的LinearLayout没有任何区别。可以通过StampView这个代理类来给其他View(比如LinearLayoutFrameLayoutImageViewTextView等常用View)添加锯齿边框背景。

public class StampViewLinearLayout extends LinearLayout {    private StampView helper;    public StampViewLinearLayout(Context context) {        this(context, null);    }    public StampViewLinearLayout(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public StampViewLinearLayout(Context context, AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);        helper = new StampView(this, context, attrs, defStyle);    }    @Override    protected void onSizeChanged(int w, int h, int oldw, int oldh) {        super.onSizeChanged(w, h, oldw, oldh);        helper.onSizeChanged(w, h);    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        helper.onDraw(canvas);    }    public float getSemicircleGap() {        return helper.getSemicircleGap();    }    public void setSemicircleGap(float semicircleGap) {        helper.setSemicircleGap(semicircleGap);    }    public float getSemicircleRadius() {        return helper.getSemicircleRadius();    }    public void setSemicircleRadius(float semicircleRadius) {        helper.setSemicircleRadius(semicircleRadius);    }    public float getSemicircleCoverStrokeWidth() {        return helper.getSemicircleCoverStrokeWidth();    }    public void setSemicircleCoverStrokeWidth(float semicircleCoverStrokeWidth) {        helper.setSemicircleCoverStrokeWidth(semicircleCoverStrokeWidth);    }    public int getSemicircleColor() {        return helper.getSemicircleColor();    }    public void setSemicircleColor(int semicircleColor) {        helper.setSemicircleColor(semicircleColor);    }    public int getSemicircleCoverColor() {        return helper.getSemicircleCoverColor();    }    public void setSemicircleCoverColor(int semicircleCoverColor) {        helper.setSemicircleCoverColor(semicircleCoverColor);    }    public boolean isSemicircleTop() {        return helper.isSemicircleTop();    }    public void setSemicircleTop(boolean semicircleTop) {        helper.setSemicircleTop(semicircleTop);    }    public boolean isSemicircleBottom() {        return helper.isSemicircleBottom();    }    public void setSemicircleBottom(boolean semicircleBottom) {        helper.setSemicircleBottom(semicircleBottom);    }    public boolean isSemicircleLeft() {        return helper.isSemicircleLeft();    }    public void setSemicircleLeft(boolean semicircleLeft) {        helper.setSemicircleLeft(semicircleLeft);    }    public boolean isSemicircleRight() {        return helper.isSemicircleRight();    }    public void setSemicircleRight(boolean semicircleRight) {        helper.setSemicircleRight(semicircleRight);    }    public float getDashLineLength() {        return helper.getDashLineLength();    }    public void setDashLineLength(float dashLineLength) {        helper.setDashLineLength(dashLineLength);    }    public float getDashLineHeight() {        return helper.getDashLineHeight();    }    public void setDashLineHeight(float dashLineHeight) {        helper.setDashLineHeight(dashLineHeight);    }    public float getDashLineGap() {        return helper.getDashLineGap();    }    public void setDashLineGap(float dashLineGap) {        helper.setDashLineGap(dashLineGap);    }    public int getDashLineColor() {        return helper.getDashLineColor();    }    public void setDashLineColor(int dashLineColor) {        helper.setDashLineColor(dashLineColor);    }    public float getDashLineMarginTop() {        return helper.getDashLineMarginTop();    }    public void setDashLineMarginTop(float dashLineMarginTop) {        helper.setDashLineMarginTop(dashLineMarginTop);    }    public float getDashLineMarginBottom() {        return helper.getDashLineMarginBottom();    }    public void setDashLineMarginBottom(float dashLineMarginBottom) {        helper.setDashLineMarginBottom(dashLineMarginBottom);    }    public float getDashLineMarginLeft() {        return helper.getDashLineMarginLeft();    }    public void setDashLineMarginLeft(float dashLineMarginLeft) {        helper.setDashLineMarginLeft(dashLineMarginLeft);    }    public float getDashLineMarginRight() {        return helper.getDashLineMarginRight();    }    public void setDashLineMarginRight(float dashLineMarginRight) {        helper.setDashLineMarginRight(dashLineMarginRight);    }    public boolean isDashLineTop() {        return helper.isDashLineTop();    }    public void setDashLineTop(boolean dashLineTop) {        helper.setDashLineTop(dashLineTop);    }    public boolean isDashLineBottom() {        return helper.isDashLineBottom();    }    public void setDashLineBottom(boolean dashLineBottom) {        helper.setDashLineBottom(dashLineBottom);    }    public boolean isDashLineLeft() {        return helper.isDashLineLeft();    }    public void setDashLineLeft(boolean dashLineLeft) {        helper.setDashLineLeft(dashLineLeft);    }    public boolean isDashLineRight() {        return helper.isDashLineRight();    }    public void setDashLineRight(boolean dashLineRight) {        helper.setDashLineRight(dashLineRight);    }}

项目地址 ☞ 传送门

原创粉丝点击