Android自定義布局實現(xiàn)優(yōu)惠券效果

最近需要實現(xiàn)一個凹凸效果的擬物化優(yōu)惠券效果,我一看沛鸵,本來想用.9圖片做背景實現(xiàn)的括勺,雖說圖片做背景實現(xiàn)省事兒方便缆八,但是能用代碼實現(xiàn)最好不過了,最終我還是選擇了用代碼來實現(xiàn)疾捍,于是有了下文奈辰。

最終效果圖

demo下載地址

1.完整代碼

先看完整的代碼,后面我們再對代碼逐一的解釋

public class CouponDisplayView extends RelativeLayout {

    private Paint mPaint;
    private Paint mPaint2;
// 圓間距
    private float gap = 0;
// 半徑
    private float radius = 20;
// 圓數(shù)量
    private int circleNum;
    private float remain;
    private int color;

    public CouponDisplayView(Context context) {
        super(context);
    }
    public CouponDisplayView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setDither(true);
        mPaint.setColor(color);
        mPaint.setStyle(Paint.Style.FILL);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        if (remain == 0) {
            remain = (int) (w - gap) % (2 * radius + gap);
        }
        circleNum = (int) ((w - gap) / (2 * radius + gap));

    }
    public CouponDisplayView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        for (int i = 0; i < circleNum; i++) {
            float x = gap + radius + remain / 2 + ((gap + radius * 2) * i);
            canvas.drawCircle(x, 0, radius, mPaint);
        }
        mPaint2 = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint2.setDither(true);
        mPaint2.setColor(getResources().getColor(R.color.divider_color_car));
        mPaint2.setStyle(Paint.Style.FILL);

        Paint paint = new Paint();
        paint.setStyle(Paint.Style.STROKE);
        paint.setColor(Color.DKGRAY);
        Path path = new Path();
        path.moveTo(0, getHeight() / 2 + 60);
        path.lineTo(getWidth(), getHeight() / 2 + 60);
        PathEffect effects = new DashPathEffect(new float[]{15, 15, 15, 15}, 2);
        paint.setPathEffect(effects);
        canvas.drawPath(path, paint);
        canvas.drawCircle(0, getHeight() / 2 + 60, radius, mPaint2);
        canvas.drawCircle(getWidth(), getHeight() / 2 + 60, radius, mPaint2);
    }
    public void setColor(int color) {
        this.color = color;
    }
}

2.方法解釋

1乱豆、CouponDisplayView繼承自RelativeLayout奖恰,通過打印日志測試已知View的執(zhí)行順序如下:

CouponDisplayView(context,attrs,defStyleAttr)
CouponDisplayView(context,attrs)
onSizeChanged()
onDraw()

onSizeChanged(int w, int h, int oldw, int oldh)
當view的大小發(fā)生變化時觸發(fā)
onDraw(Canvas canvas)
負責將View繪制在屏幕上
public CouponDisplayView(Context context)
Java代碼直接new一個CouponDisplayView實例的時候,會調(diào)用這個只有一個參數(shù)的構(gòu)造函數(shù)
public CouponDisplayView(Context context, AttributeSet attrs)
在默認的XML布局文件中創(chuàng)建的時候調(diào)用這個有兩個參數(shù)的構(gòu)造函數(shù)宛裕。AttributeSet類型的參數(shù)負責把XML布局文件中所自定義的屬性通過AttributeSet帶入到View內(nèi)瑟啃;
public CouponDisplayView(Context context,AttributeSet attrs, int defStyleAttr)
構(gòu)造函數(shù)中第三個參數(shù)是默認的Style,這里的默認的Style是指它在當前Application或者Activity所用的Theme中的默認Style揩尸,且只有在明確調(diào)用的時候才會調(diào)用

3.代碼實現(xiàn)思路

從上面的效果圖來看蛹屿,這個自定義View和普通的Linearlayout,RelativeLayout一樣岩榆,只是上下兩邊多了類似于半圓鋸齒的形狀错负,我們需要在上下兩條線上畫一個個白色的小圓來實現(xiàn)這種效果。
假如我們上下線的半圓以及半圓與半圓之間的間距是固定的勇边,那么不同尺寸的屏幕肯定會畫出不同數(shù)量的半圓犹撒,那么我們只需要根據(jù)控件的寬度來獲取能畫的半圓數(shù)。
我們觀察效果圖會發(fā)現(xiàn)粥诫,圓的數(shù)量總是圓間距數(shù)量-1油航,

也就是說,假設(shè)圓的數(shù)量是circleNum,那么圓間距就是circleNum+1怀浆,所以我們可以根據(jù)這個計算出circleNum: 這里gap就是圓間距谊囚,radius是圓半徑,w是view的寬

circleNum = (int) ((w-gap)/(2*radius+gap));

1 执赡、重寫onSizeChanged()方法镰踏,根據(jù)上面的圓的半徑和圓間距來計算需要畫的圓數(shù)量circleNum

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        if (remain == 0) {
            remain = (int) (w - gap) % (2 * radius + gap);
        }
        circleNum = (int) ((w - gap) / (2 * radius + gap));
    }

2.接下來只需要重寫onDraw()方法,簡單的根據(jù)circleNum的數(shù)量將一個一個的圓繪制在屏幕上

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
       for (int i = 0; i < circleNum; i++) {
            float x = gap + radius + remain / 2 + ((gap + radius * 2) * i);
            canvas.drawCircle(x, 0, radius, mPaint);
        }
}

3.畫中間的黑色虛線

  Paint paint = new Paint();
        paint.setStyle(Paint.Style.STROKE);
        paint.setColor(Color.DKGRAY);
        Path path = new Path();
        path.moveTo(0, getHeight() / 2 + 60);
        path.lineTo(getWidth(), getHeight() / 2 + 60);
        PathEffect effects = new DashPathEffect(new float[]{15, 15, 15, 15}, 2);
        paint.setPathEffect(effects);
        canvas.drawPath(path, paint);

4.畫兩邊居中的半圓

    mPaint2 = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint2.setDither(true);
        mPaint2.setColor(getResources().getColor(R.color.divider_color_car));
        mPaint2.setStyle(Paint.Style.FILL);
      canvas.drawCircle(0, getHeight() / 2 + 60, radius, mPaint2);
        canvas.drawCircle(getWidth(), getHeight() / 2 + 60, radius, mPaint2);

代碼分析完畢

3.設(shè)置自定義樣式屬性

考慮到復(fù)用地方不是很多沙合,所以上面的代碼沒有寫自定義樣式屬性奠伪,而是用了public void setColor(int color) {this.color = color;}有需要設(shè)置自定義屬性的我在這里寫一下哈,嘻嘻

1首懈、在res/values/ 下建立一個attr.xml 绊率, 在里面定義我們的需要用到的屬性以及聲明相對應(yīng)屬性的取值類型

<?xml version="1.0" encoding="utf-8"?>
<resources>
    //半圓顏色
    <attr name="radiusColor" format="color" />
    <declare-styleable name="CouponDisplayView">
        <attr name="radiusColor" />
    </declare-styleable>

</resources>

上面定義的半圓顏色的屬性,format屬性的取值類型總共有10種,包括:string究履,color滤否,demensioninteger最仑,enum藐俺,reference炊甲,floatboolean欲芹,fraction卿啡,flag

2菱父、然后在XML布局中聲明我們的自定義View

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:custom="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
<--注意:一定要引入xmlns:custom="http://schemas.android.com/apk/res-auto"
custom名字可以自定義-->
    <com.xxx.xxx.CouponDisplayView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#FBB039"
        android:orientation="horizontal"
        android:padding="16dp"
        custom:radiusColor="@Color/red">
............
    </com.xxx.xxx.CouponDisplayView>
</LinearLayout>

3颈娜、在View的構(gòu)造方法中,獲得我們的xml布局文件中定義的顏色

public CouponDisplayView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        Log.d("mDebug", "CouponDisplayView context,attrs,defStyleAttr");
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CouponDisplayView, defStyleAttr, 0);
        for (int i = 0; i < a.getIndexCount(); i++) {
            int attr = a.getIndex(i);
            switch (attr) {
                case R.styleable.CouponDisplayView_radiusColor:
                    radius = a.getDimensionPixelSize(R.styleable.CouponDisplayView_radiusColor, 10);
                    break;
            }
        }
        a.recycle();
}

OK滞伟,設(shè)置自定義樣式屬性到此就寫完了揭鳞。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市梆奈,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌称开,老刑警劉巖亩钟,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異鳖轰,居然都是意外死亡清酥,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進店門蕴侣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來焰轻,“玉大人,你說我怎么就攤上這事昆雀∪柚荆” “怎么了?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵狞膘,是天一觀的道長揩懒。 經(jīng)常有香客問我,道長挽封,這世上最難降的妖魔是什么已球? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮辅愿,結(jié)果婚禮上智亮,老公的妹妹穿的比我還像新娘。我一直安慰自己点待,他們只是感情好阔蛉,可當我...
    茶點故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著亦鳞,像睡著了一般馍忽。 火紅的嫁衣襯著肌膚如雪棒坏。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天遭笋,我揣著相機與錄音坝冕,去河邊找鬼。 笑死瓦呼,一個胖子當著我的面吹牛喂窟,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播央串,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼磨澡,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了质和?” 一聲冷哼從身側(cè)響起稳摄,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎饲宿,沒想到半個月后厦酬,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡瘫想,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年仗阅,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片国夜。...
    茶點故事閱讀 39,902評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡减噪,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出车吹,到底是詐尸還是另有隱情筹裕,我是刑警寧澤,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布礼搁,位于F島的核電站饶碘,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏馒吴。R本人自食惡果不足惜扎运,卻給世界環(huán)境...
    茶點故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望饮戳。 院中可真熱鬧豪治,春花似錦、人聲如沸扯罐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽歹河。三九已至掩浙,卻和暖如春花吟,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背厨姚。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工衅澈, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人谬墙。 一個月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓今布,卻偏偏與公主長得像,于是被迫代替她去往敵國和親拭抬。 傳聞我的和親對象是個殘疾皇子部默,可洞房花燭夜當晚...
    茶點故事閱讀 44,843評論 2 354

推薦閱讀更多精彩內(nèi)容