android自定义布局实现优惠券效果
最近需要實現一個凹凸效果的擬物化優惠券效果,我一看,本來想用.9圖片做背景實現的,雖說圖片做背景實現省事兒方便,但是能用代碼實現最好不過了,最終我還是選擇了用代碼來實現,于是有了下文。
最終效果圖
demo下載地址
###1.完整代碼 先看完整的代碼,后面我們再對代碼逐一的解釋
public class CouponDisplayView extends RelativeLayout {private Paint mPaint;private Paint mPaint2; // 圓間距private float gap = 0; // 半徑private float radius = 20; // 圓數量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);}@Overrideprotected 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);}@Overrideprotected 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的執行順序如下:
CouponDisplayView(context,attrs,defStyleAttr) CouponDisplayView(context,attrs) onSizeChanged() onDraw() 復制代碼onSizeChanged(int w, int h, int oldw, int oldh) 當view的大小發生變化時觸發 onDraw(Canvas canvas) 負責將View繪制在屏幕上 public CouponDisplayView(Context context) Java代碼直接new一個CouponDisplayView實例的時候,會調用這個只有一個參數的構造函數 public CouponDisplayView(Context context, AttributeSet attrs) 在默認的XML布局文件中創建的時候調用這個有兩個參數的構造函數。AttributeSet類型的參數負責把XML布局文件中所自定義的屬性通過AttributeSet帶入到View內; public CouponDisplayView(Context context,AttributeSet attrs, int defStyleAttr) 構造函數中第三個參數是默認的Style,這里的默認的Style是指它在當前Application或者Activity所用的Theme中的默認Style,且只有在明確調用的時候才會調用
###3.代碼實現思路 從上面的效果圖來看,這個自定義View和普通的Linearlayout,RelativeLayout一樣,只是上下兩邊多了類似于半圓鋸齒的形狀,我們需要在上下兩條線上畫一個個白色的小圓來實現這種效果。 假如我們上下線的半圓以及半圓與半圓之間的間距是固定的,那么不同尺寸的屏幕肯定會畫出不同數量的半圓,那么我們只需要根據控件的寬度來獲取能畫的半圓數。 我們觀察效果圖會發現,圓的數量總是圓間距數量-1,
也就是說,假設圓的數量是circleNum,那么圓間距就是circleNum+1,所以我們可以根據這個計算出circleNum: 這里gap就是圓間距,radius是圓半徑,w是view的寬
circleNum = (int) ((w-gap)/(2*radius+gap)); 復制代碼1 、重寫onSizeChanged()方法,根據上面的圓的半徑和圓間距來計算需要畫的圓數量circleNum
@Overrideprotected 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()方法,簡單的根據circleNum的數量將一個一個的圓繪制在屏幕上
@Overrideprotected 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.設置自定義樣式屬性
考慮到復用地方不是很多,所以上面的代碼沒有寫自定義樣式屬性,而是用了public void setColor(int color) {this.color = color;}有需要設置自定義屬性的我在這里寫一下哈,嘻嘻
1、在res/values/ 下建立一個attr.xml , 在里面定義我們的需要用到的屬性以及聲明相對應屬性的取值類型
<?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,demension,integer,enum,reference,float,boolean,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.CouponDisplayViewandroid: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的構造方法中,獲得我們的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,設置自定義樣式屬性到此就寫完了。
轉載于:https://juejin.im/post/5bdda7e451882516bb02e11b
總結
以上是生活随笔為你收集整理的android自定义布局实现优惠券效果的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JDBC 常用的类和接口--一学就会(欢
- 下一篇: centos7装完chrome无法使用y