国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統(tǒng) > Android > 正文

Android 自定義View之邊緣凹凸的優(yōu)惠券效果的開發(fā)過程

2019-10-22 18:14:06
字體:
供稿:網(wǎng)友

本篇文章講的是自定義View之邊緣凹凸的優(yōu)惠券效果,之前有見過很多優(yōu)惠券的效果都是使用了邊緣凹凸的樣式。和往常一樣,主要總結(jié)一下在自定義View的開發(fā)過程中需要注意的一些地方。

按照慣例,我們先來看看效果圖

android,自定義,優(yōu)惠券,凹凸優(yōu)惠券

一、寫代碼之前,我們先弄清楚view的啟動過程:

之所以想要弄清楚這個問題是因為代碼里面用到了onSizeChanged()方法,一開始我有點猶豫onSizeChanged是在什么時候啟動的呢,所以看看View的啟動流程吧

package per.lijuan.coupondisplayviewdome;import android.content.Context;import android.graphics.Canvas;import android.util.AttributeSet;import android.util.Log;import android.widget.LinearLayout;/** * 自定義邊緣凹凸的優(yōu)惠券效果view * Created by lijuan on 2016/9/26. */public class CouponDisplayView extends LinearLayout {  public CouponDisplayView(Context context) {    this(context, null);    Log.d("mDebug", "CouponDisplayView:context");  }  public CouponDisplayView(Context context, AttributeSet attrs) {    this(context, attrs, 0);    Log.d("mDebug", "CouponDisplayView:context,attrs");  }  public CouponDisplayView(Context context, AttributeSet attrs, int defStyleAttr) {    super(context, attrs, defStyleAttr);    Log.d("mDebug", "CouponDisplayView:context,attrs,defStyleAttr");  }  @Override  protected void onSizeChanged(int w, int h, int oldw, int oldh) {    super.onSizeChanged(w, h, oldw, oldh);    Log.d("mDebug", "onSizeChanged:w=" + w + ",h=" + h + ",oldw=" + oldw + ",oldh=" + oldh);  }  @Override  protected void onDraw(Canvas canvas) {    super.onDraw(canvas);    Log.d("mDebug", "onDraw");  }}

輸出如下:

09-27 15:29:31.957 8210-8210/per.lijuan.coupondisplayviewdome D/mDebug: CouponDisplayView:context,attrs,defStyleAttr09-27 15:29:31.957 8210-8210/per.lijuan.coupondisplayviewdome D/mDebug: CouponDisplayView:context,attrs09-27 15:29:32.050 8210-8210/per.lijuan.coupondisplayviewdome D/mDebug: onSizeChanged:w=984,h=361,oldw=0,oldh=009-27 15:29:32.083 8210-8210/per.lijuan.coupondisplayviewdome D/mDebug: onDraw

在這里可以看到,onSizeChanged()方法的啟動是在onDraw之前

二、view的幾個常用觸發(fā)方法

1. onFinishInflate():當View中所有的子控件均被映射成xml后觸發(fā)
2. onMeasure(int widthMeasureSpec, int heightMeasureSpec):確定所有子元素的大小
3. onLayout(boolean changed, int l, int t, int r, int b):當View分配所有的子元素的大小和位置時觸發(fā)
4. onSizeChanged(int w, int h, int oldw, int oldh):當view的大小發(fā)生變化時觸發(fā)
5. onDraw(Canvas canvas):負責將View繪制在屏幕上

三、View 的幾個構(gòu)造函數(shù)

1、public CouponDisplayView(Context context)
—>Java代碼直接new一個CouponDisplayView實例的時候,會調(diào)用這個只有一個參數(shù)的構(gòu)造函數(shù);

2、public CouponDisplayView(Context context, AttributeSet attrs)
—>在默認的XML布局文件中創(chuàng)建的時候調(diào)用這個有兩個參數(shù)的構(gòu)造函數(shù)。AttributeSet類型的參數(shù)負責把XML布局文件中所自定義的屬性通過AttributeSet帶入到View內(nèi);

3、public CouponDisplayView(Context context, AttributeSet attrs, int defStyleAttr)
—>構(gòu)造函數(shù)中第三個參數(shù)是默認的Style,這里的默認的Style是指它在當前Application或者Activity所用的Theme中的默認Style,且只有在明確調(diào)用的時候才會調(diào)用

4、public CouponDisplayView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)
—>該構(gòu)造函數(shù)是在API21的時候才添加上的

自定義View中,我們需要重寫了3個構(gòu)造方法,在上面的構(gòu)造方法中說過默認的布局文件調(diào)用的是兩個參數(shù)的構(gòu)造方法,所以記得讓所有的構(gòu)造方法調(diào)用三個參數(shù)的構(gòu)造方法,然后在三個參數(shù)的構(gòu)造方法中獲得自定義屬性。
一開始一個參數(shù)的構(gòu)造方法和兩個參數(shù)的構(gòu)造方法是這樣的:

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

我們需要注意的是super應(yīng)該改成this,然后讓一個參數(shù)的構(gòu)造方法引用兩個參數(shù)的構(gòu)造方法,兩個參數(shù)的構(gòu)造方法引用三個參數(shù)的構(gòu)造方法,代碼如下:

public CouponDisplayView(Context context) {    this(context, null);  }  public CouponDisplayView(Context context, AttributeSet attrs) {    this(context, attrs, 0);  }

四、分析具體的實現(xiàn)思路:

從上面的效果圖來看,這個自定義View和普通的Linearlayout,RelativeLayout一樣,只是上下兩邊多了類似于半圓鋸齒的形狀,我們需要在上下兩條線上畫一個個白色的小圓來實現(xiàn)這種效果。

假如我們上下線的半圓以及半圓與半圓之間的間距是固定的,那么不同尺寸的屏幕肯定會畫出不同數(shù)量的半圓,那么我們只需要根據(jù)控件的寬度來獲取能畫的半圓數(shù)。

我們觀察效果圖會發(fā)現(xiàn),圓的數(shù)量總是圓間距數(shù)量-1,也就是說,假設(shè)圓的數(shù)量是circleNum,那么圓間距就是circleNum+1,所以我們可以根據(jù)這個計算出circleNum:

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

這里gap就是圓間距,radius是圓半徑,w是view的寬。

五、下面我們就開始來看看代碼啦

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

<?xml version="1.0" encoding="utf-8"?><resources>  <!--圓間距-->  <attr name="radius" format="dimension" />  <!--半徑-->  <attr name="gap" format="dimension" />  <declare-styleable name="CouponDisplayView">    <attr name="radius" />    <attr name="gap" />  </declare-styleable></resources>

我們定義了圓間距和半徑2個屬性,format是值該屬性的取值類型,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"  android:layout_margin="16dp">  <per.lijuan.coupondisplayviewdome.CouponDisplayView    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:background="#FBB039"    android:orientation="horizontal"    android:padding="16dp"    custom:gap="8dp"    custom:radius="5dp">    <ImageView      android:layout_width="90dp"      android:layout_height="match_parent"      android:scaleType="centerCrop"      android:src="@mipmap/ic_launcher" />    <LinearLayout      android:layout_width="match_parent"      android:layout_height="wrap_content"      android:layout_marginLeft="5dp"      android:orientation="vertical">      <TextView        android:id="@+id/name"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:text="電影新客代金劵"        android:textSize="18dp" />      <TextView        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:paddingTop="5dp"        android:text="編號:525451122312431"        android:textSize="12dp" />      <TextView        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:paddingTop="5dp"        android:text="滿200元可用、限最新版本客戶端使用"        android:textSize="12dp" />      <TextView        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:paddingTop="5dp"        android:text="截止日期:2016-11-07"        android:textSize="12dp" />    </LinearLayout>  </per.lijuan.coupondisplayviewdome.CouponDisplayView></LinearLayout>

一定要引入xmlns:custom=”http://schemas.android.com/apk/res-auto”,Android Studio中我們可以使用res-atuo命名空間,就不用添加自定義View全類名。

3、在View的構(gòu)造方法中,獲得我們的xml布局文件中定義的圓的半徑和圓間距

private Paint mPaint;  /**   * 半徑   */  private float radius=10;  /**   * 圓間距   */  private float gap=8;  /**   * 圓數(shù)量   */  private int circleNum;  private float remain;  public CouponDisplayView(Context context) {    this(context, null);    Log.d("mDebug", "CouponDisplayView context");  }  public CouponDisplayView(Context context, AttributeSet attrs) {    this(context, attrs, 0);    Log.d("mDebug", "CouponDisplayView context, attrs");  }  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_radius:          radius = a.getDimensionPixelSize(R.styleable.CouponDisplayView_radius, 10);          break;        case R.styleable.CouponDisplayView_gap:          gap = a.getDimensionPixelSize(R.styleable.CouponDisplayView_radius, 8);          break;      }    }    a.recycle();    mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);    mPaint.setDither(true);    mPaint.setColor(Color.WHITE);    mPaint.setStyle(Paint.Style.FILL);  }

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

@Override  protected void onSizeChanged(int w, int h, int oldw, int oldh) {    super.onSizeChanged(w, h, oldw, oldh);    Log.d("mDebug", "onSizeChanged,w=" + w + ",h=" + h + ",oldw=" + oldw + ",oldh=" + oldh);    if (remain == 0) {      //計算不整除的剩余部分      remain = (int) (w - gap) % (2 * radius + gap);    }    circleNum = (int) ((w - gap) / (2 * radius + gap));  }

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

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

這里remain/2是因為避免有一些情況:當計算出來的圓的數(shù)量不是整除時,這樣就會出現(xiàn)右邊最后一個間距會比其它的間距都要寬,所以我們在繪制第一個的時候加上了余下的間距的一半,即使是不整除的情況,至少也能保證第一個和最后一個間距寬度一致。

總結(jié)

以上所述是小編給大家介紹的Android 自定義View之邊緣凹凸的優(yōu)惠券效果的開發(fā)過程,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對VEVB武林網(wǎng)網(wǎng)站的支持!


注:相關(guān)教程知識閱讀請移步到Android開發(fā)頻道。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 九江市| 若尔盖县| 青川县| 韩城市| 定州市| 天祝| 汾西县| 阿荣旗| 抚州市| 石渠县| 武宣县| 金寨县| 苏尼特右旗| 辉县市| 宾阳县| 广宗县| 孟村| 大足县| 长宁区| 社会| 孟津县| 恭城| 横峰县| 六枝特区| 侯马市| 正定县| 绍兴县| 绥宁县| 晋宁县| 扶沟县| 义马市| 昌邑市| 登封市| 上蔡县| 尼勒克县| 沙坪坝区| 绵竹市| 日土县| 卢氏县| 珠海市| 古丈县|