Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android自定義View——自由定制優惠券背景

Android自定義View——自由定制優惠券背景

編輯:關於Android編程

1、功能介紹

現在購物類的APP真的是數不甚數啊,經常可以在這些APP中看到優惠券的影子,今天我們就來實現一下優惠券的背景效果。實際開發中,如果我們想偷懶,直接用一張背景圖作為優惠劵背景就OK了,今天我們手動來實現一下,其實實現起來還是比較簡單的。效果圖如下:

\

邊緣的樣式可以自由定制,有兩種邊緣類型:半圓形和三角形。上面圖中第一張左右兩邊邊緣為三角形、上下邊緣為半圓形,第二張左右兩本是半圓形、上下兩邊是三角形,第三張上下、左右兩邊都是半圓形。邊緣的設置都是通過在xml布局中自定義屬性指定,因此可根據需要自由定制,也可以設置為none,表示不繪制邊緣,默認類型就是none。

 

2、實現思路

要實現這個自定義View,我們需要考慮的問題有三個:

(1)是繼承View還是ViewGroup?

(2)邊緣怎麼來處理?

(3)繪制的時機?

對於第一個問題,我們簡單想一下就可以得出答案,因為我們在這個自定義View中需要放入一些其他的控件,如上圖中的TextView和ImageView,如果繼承View那裡面就不能再放入其他控件了,因此我們得選擇繼承ViewGroup,但是如果我們直接是繼承ViewGroup的話,那裡面的控件擺放邏輯即onLayout還得我們自己來實現,此時就會比較復雜了,為了簡單起見,我們直接繼承自LinearLayout即可,不用去考慮onMeasure和onLayout的實現,只需關注我們這一次的業務核心即繪制不同的邊緣。

 

對於第二個問題,我們觀察一下上圖,只需要在控件的邊緣做文章即可,拿半圓形邊緣來說,我們只需要在一條邊上循環進行半圓的繪制即可,這裡重要的是要計算出這一條邊上有多少個半圓型,因為每個人可能設置的控件長度不一樣,我們可以指定一下圓形半徑以及半圓形與半圓形直接間距,有了這兩個參數就可以計算出這一條邊上有多少個半圓型了,如下計算方法:

 

/**
 * 計算垂直方向需要畫圓或三角形的數量和初始偏移量
 * @param gapSize 每個圓形或三角形之間的間距
 */
private void calculateVerticalCount(float gapSize){
    mVerticalCount = (int) ((mHeight - gapSize) / (2 * mRadius + gapSize));
    mVerticalInitSize = (int) ((mHeight - (2 * mRadius * mVerticalCount + (mVerticalCount + 1) * gapSize)) / 2);
}

/**
 * 計算水平方向上圓或三角形的數量和初始偏移量
 * @param gapSize 每個圓形或三角形之間的間距
 */
private void calculateHorizontalCount(float gapSize) {
    mHorizontalCount = (int) ((mWidth - gapSize) / (2 * mRadius + gapSize));
    mHorizontalInitSize = (int) ((mWidth - (2 * mRadius * mHorizontalCount + (mHorizontalCount + 1) * gapSize)) / 2);
}
上面這個計算方式畫個圖就出來了,假設有n個半圓,那就會有n+1個圓間距,因此控件寬度mWidth = n * 2 * radius + (n-1) * gapSize,由此可以求出半圓的個數,由於邊的寬度或高度在這個半徑radius和圓間距gapsize下不一定能夠完整平分,為了讓兩邊留出的距離相等,我們計算了一個初始偏移值。

 

 

在計算出了邊上的半圓數量之後,就可以開始准備繪制操作了。那繪制的時機是在哪裡?根據View的繪制過程:先繪制背景、在繪制自己(即onDraw)、下面繪制子布局、最後再繪制一些裝飾之類的,其實我們在onDraw或dispatchDraw中繪制都可以,只不過onDraw一般是對於View來說的,對於ViewGroup我們一般用它來擺放布局,當我們在ViewGroup的onDraw中繪制時,最好要給這個ViewGroup設置background或setWillNotDraw(false);進行設置,才能保證每次都會進入onDraw方法,這裡我選擇在dispatchDraw中進行繪制,先讓它的子View全部繪制完畢,然後再繪制邊緣,以避免我們的邊緣被裡面的內容給覆蓋掉。

 

在繪制的時候不斷循環繪制,不斷更改坐標即可。具體實現如下:

 

@Override
protected void dispatchDraw(Canvas canvas) {
    super.dispatchDraw(canvas);
    if(vertical_style == 1){//如果垂直方向是半圓形
        drawVerticalCircle(canvas);
    }else if(vertical_style == 2){//垂直方向是三角形
        drawVerticalTriangle(canvas);
    }
    if(horizontal_style == 1){//如果水平方向是半圓形
        drawHorizontalCircle(canvas);
    }else if(horizontal_style == 2){//如果水平方向是三角形
        drawHorizontalTriangle(canvas);
    }
}

/**
 * 在水平方向上繪制三角形
 * @param canvas
 */
private void drawHorizontalTriangle(Canvas canvas) {
    //先計算出水平方向上的數量
    calculateHorizontalCount(0);
    Path path = new Path();
    float x = 0;
    //繪制上面部分
    for(int i = 0; i < mHorizontalCount; i++){
        path.reset();
        x = mHorizontalInitSize + i * 2 * mRadius;
        path.moveTo(x, 0);
        x += mRadius;
        path.lineTo(x, mRadius);
        x += mRadius;
        path.lineTo(x, 0);
        path.close();
        canvas.drawPath(path, mPaint);
    }
    //繪制下面部分
    x = 0;
    for(int i = 0; i < mHorizontalCount; i++){
        path.reset();
        x = mHorizontalInitSize + i * 2 * mRadius;
        path.moveTo(x, mHeight);
        x += mRadius;
        path.lineTo(x, mHeight - mRadius);
        x += mRadius;
        path.lineTo(x, mHeight);
        path.close();
        canvas.drawPath(path, mPaint);
    }
}

/**
 * 在水平方向上繪制圓形
 * @param canvas
 */
private void drawHorizontalCircle(Canvas canvas) {
    //先計算出水平方向上的數量
    calculateHorizontalCount(mGapSize);
    float x = mHorizontalInitSize + mGapSize + mRadius;
    //先繪制上面部分
    for(int i = 0; i < mHorizontalCount; i++){
        canvas.drawCircle(x, 0, mRadius, mPaint);
        x += 2 * mRadius + mGapSize;
    }
    //再繪制下面部分
    x = mHorizontalInitSize + mGapSize + mRadius;
    for(int i = 0; i < mHorizontalCount; i++){
        canvas.drawCircle(x, mHeight, mRadius, mPaint);
        x += 2 * mRadius + mGapSize;
    }
}

/**
 * 在垂直方向繪制三角形
 * @param canvas
 */
private void drawVerticalTriangle(Canvas canvas) {
    //計算一下三角形的數量和初始距離
    calculateVerticalCount(0);
    Path path = new Path();
    float y = 0;
    //先畫左邊
    for(int i = 0; i < mVerticalCount; i++){
        path.reset();
        y = mVerticalInitSize + i * 2 * mRadius;
        path.moveTo(0, y);
        y += mRadius;
        path.lineTo(mRadius, y);
        y += mRadius;
        path.lineTo(0, y);
        path.close();
        canvas.drawPath(path, mPaint);
    }
    //再畫右邊
    y = 0;
    for(int i = 0; i < mVerticalCount; i++){
        path.reset();
        y = mVerticalInitSize + i * 2 * mRadius;
        path.moveTo(mWidth, y);
        y += mRadius;
        path.lineTo(mWidth - mRadius, y);
        y += mRadius;
        path.lineTo(mWidth, y);
        path.close();
        canvas.drawPath(path, mPaint);
    }
}

/**
 * 在垂直方向繪制半圓形
 * @param canvas
 */
private void drawVerticalCircle(Canvas canvas) {
    //計算一下圓形的數量和初始偏移距離
    calculateVerticalCount(mGapSize);
    //這次使用畫弧來繪制出圓形
    RectF rectF = new RectF();
    //先畫左邊
    for(int i = 0; i < mVerticalCount; i++){
        rectF.left = -mRadius;
        rectF.top = mVerticalInitSize + mGapSize * (i + 1) + i * 2 * mRadius;
        rectF.right =  mRadius;
        rectF.bottom = rectF.top + 2 * mRadius;
        canvas.drawArc(rectF, -90, 180, false, mPaint);
    }
    //再畫右邊
    for(int i = 0; i < mVerticalCount; i++){
        rectF.left = mWidth - mRadius;
        rectF.top = mVerticalInitSize + mGapSize * (i + 1) + i * 2 * mRadius;
        rectF.right = rectF.left + 2 * mRadius;
        rectF.bottom = rectF.top + 2 * mRadius;
        canvas.drawArc(rectF, 90, 180, false, mPaint);
    }
}

 

 

 

3、使用方法

 

因為這個自定義View是繼承自LinearLayout,在布局中直接把它當做LinearLayout來使用,通過我們自定義的屬性來指定邊緣類型。

 


    
        
        
        
    
    
        
        
        
    
那在xml布局中就可以自己自由指定了,如下:

 

 

    android:layout_width="match_parent"
    android:layout_height="200dp"
    android:layout_marginLeft="20dp"
    android:layout_marginRight="20dp"
    android:orientation="horizontal"
    android:background="#47BDBD"
    android:gravity="center_vertical"
    coupon:horizontal_style="circle" 
    coupon:vertical_style="triangle">
            android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="match_parent"
        android:padding="30dp"
        android:orientation="vertical">
                    android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="@color/white"
            android:textSize="18sp"
            android:text="順旺基優惠券"/>
                    android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="#FC4A36"
            android:layout_marginTop="15dp"
            android:textSize="16sp"
            android:text="全場五折優惠"/>
                    android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="@color/white"
            android:layout_marginTop="15dp"
            android:textSize="15sp"
            android:text="券編號:2016070920160720"/>
                    android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="@color/white"
            android:layout_marginTop="15dp"
            android:textSize="15sp"
            android:text="有效期:2016-07-09至2016-07-20"/>
    
            android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginRight="20dp"
        android:src="@mipmap/iv_coupon"
        android:layout_gravity="center"/>

 

 

點擊下載

使用起來是不是很簡單呢?

在翻看購物類APP時,看到了很多APP在添加購物車時有很多添加動畫,那麼下一篇就實現一下購物車添加動畫玩玩。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved