Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android自定義控件

Android自定義控件

編輯:關於Android編程

我們在開發的過程中,有時會遇到一些Android系統自帶的控件解決不了我們的需求,比如說我們在開發項目時顯示的圖片輪播,當我們展示的時候不希望圖片變形,還要保證圖片能夠完整的顯示出來,我們如何做呢?如果只是一個簡單的ImageView控件恐怕很難實現吧!有人會說ImageView的ScaleType屬性就能夠解決圖片填充不滿的問題,但是那樣的話圖片很容易失真,達不到產品原先的需求。首先我們來認識一下ImageView的ScaleType屬性的一些值。當我們查看ImageView的ScaleType的源碼時會發現ScaleType的一些枚舉值,也就是我們所用的屬性值

public static enum ScaleType {
        CENTER,
        CENTER_CROP,
        CENTER_INSIDE,
        FIT_CENTER,
        FIT_END,
        FIT_START,
        FIT_XY,
        MATRIX;
        private ScaleType() {
        }
    }

那麼我們就按照枚舉值的順序來認識一下這些值如何使用。
android:scaleType=”center”
center就是居中,按圖片的原來大小居中顯示,當圖片長/寬超過View的長/寬,則截取圖片的居中部分顯示,目的是讓圖片居中。
android:scaleType=”centerCrop”
這個就是縮放圖片的一種,它的作用就是讓圖片等比例縮放,但是唯一美中不足的就是這個圖片的縮放會對圖片造成一定的裁剪(當設置的View的寬高和圖片的寬高比例不同的時候)。圖片依舊是居中顯示
android:scaleType=”centerInside”
將圖片的內容完整居中顯示,通過按比例縮小或原來的大小使得圖片長/寬等於或小於View的長/寬
android:scaleType=”fitCenter”
把圖片按比例擴大/縮小到View的寬度,居中顯示
android:scaleType=”fitEnd”
把圖片按比例擴大/縮小到View的寬度,顯示在View的下部分位置
android:scaleType=”fitStart”
把圖片按比例擴大/縮小到View的寬度,顯示在View的上部分位置
android:scaleType=”fitXY”
把圖片不按比例擴大/縮小到跟View的大小一致,這一種也是最容易產生圖片失真的
android:scaleType=”matrix”
用矩陣來繪制,動態縮小放大圖片來顯示
以上效果圖如下
這裡寫圖片描述vcbky/zK1rv6xOPE3Mi3saPSstK70fnC8KO/v9bFwrK70NCwyaOhxMfDtM7Sw8fI57rOveK+9sTYo7/O0sPHyOe5+8/r0qrN6sPAtcTP1Mq+1NrL+dPQtcTK1rv6yc/D5r7N0OjSqtfUtqjS5dK7uPa/2Lz+wcuhozxiciAvPg0KQW5kcm9pZNfUtqjS5b/YvP7Q6NKq0rvQqdfUtqjS5bXEyvTQ1KOsztLDx9Do0qrU2mFwcFxzcmNcbWFpblxyZXNcdmFsdWVzz8LQwr2o0ru49nhtbM7EvP7D+9fWzqphdHRyc9Kyvs3Kx8r00NTOxLz+o6zU2s7EvP7A78PmztLDx9KqyrnTw2RlY2xhcmUtc3R5bGVhYmxlwLTJ+cP30ru49s7Sw8fX1Ly6tcS48cq9tcTSu9CpyvTQ1DwvcD4NCjxwcmUgY2xhc3M9"brush:java;">

其中declare-styleable name=”CustomLayout”裡面的name值最好跟我們自定義控件名相同,name=”test” format=”string”,name是根據自己的習慣來定但是要做到見名知意,就像layout_width讓人一看就知道就布局的寬一樣。format就是數據的格式,它有string 、float、boolean、color、dimension、enum、flag、fraction、integer、reference這10種格式,本次只用到float這種格式。因為要實現圖片等比例縮放需要用到一個比例內容如下



    
        
    

自定義控件的時候需要重寫onMeasure方法,onMeasure是用來計算控件的寬高的,當我們知道控件的寬度或高度想要根據比例設置高度或寬度的時候,就需要在此方法中進行測量計算。在onMeasure方法中,我們會看到兩個參數onMeasure(int widthMeasureSpec, int heightMeasureSpec),onMeasure傳入的兩個參數是由上一層控件傳入的大小,有多種情況,重寫該方法時需要對計算控件的實際大小,然後調用setMeasuredDimension(int, int)設置實際大小。widthMeasureSpec其實就是width的寬度值與寬度的模式,說到模式大家都應該很熟悉的,有三種模式分別是:MeasureSpec.AT_MOST、MeasureSpec.EXACTLY、MeasureSpec.UNSPECIFIED。當模式為MeasureSpec.AT_MOST時則意味著控件大小一般隨著控件的子空間或內容進行變化,此時控件尺寸只要不超過父控件允許的最大尺寸即可,我們經常使用的wrap_content就是這種模式。當模式為MeasureSpec.EXACTLY時,說明控件的大小為精確值,是我們已知的大小的時候可以設置此模式,我們經常使用的match_parent就是這種模式。當模式為MeasureSpec.UNSPECIFIED時,說明控件的大小不確定,控件的大小是可以隨便變化的,我們通常使用的父控件為Adapter的就是通過傳入的大小來確定的就是這種模式。那麼widthMeasureSpec裡面的值又是什麼情況呢,下面是我打印的一個當控件的寬度為match_parent也就是模式為MeasureSpec.EXACTLY時的widthMeasureSpec的值

10-28 12:55:50.785 5350-5350/custom.lyxrobert.com.customcontrols I/System.out: widthMeasureSpec------>1073742904

那麼1073742904是什麼意思呢?
這裡寫圖片描述

其中的10000111000?轉換成10進制就是1080也就是我的手機的屏寬,那麼?01000000000000000000010000111000?前面的又是什麼情況呢?

    public static final int AT_MOST = -2147483648;
    public static final int EXACTLY = 1073741824;
    public static final int UNSPECIFIED = 0;

1073741824的二進制則為?01000000000000000000000000000000?看到這裡相比大家也就知道怎麼回事了吧。
那麼我們就可以根據widthMeasureSpec來獲取我們想要的寬度方法則是MeasureSpec.getSize(widthMeasureSpec),高度也是如此不過傳入的參數就是heightMeasureSpec。
如果我們知道寬度和高度也是不行的,如果用戶想要給圖片設置一定的padding值怎麼辦?比如說padding為10,那麼圖片的內邊距都會為10,圖片以前的比例就很難保持。所以我們為防止這種情況的發生還是通過獲取相應的padding值來進行處理。圖片的寬度則為int img_width=width - getPaddingLeft() - getPaddingRight();通過寬度/計算出的圖片的寬高比得到圖片的高度int img_height = (int) (imageWidth / ratio + 0.5f);但是這樣還是不行,因為圖片寬度左右各減少10,而高度雖然也等比例縮小了,但是顯示出來的效果恐怕只有圖片的左右的間距與上下的會有不同的效果

圖片沒有設置padding時
圖片沒有設置padding時
圖片設置padding為20dp時
圖片設置padding為20dp時
我們發現圖片的上下的邊距並不是我們所設置的,那麼如果達到這種效果呢,就是需要根據我們獲取的img_height 的值再加上得到top和bottom的padding值height = img_height + getPaddingTop() + getPaddingBottom();設置之後的圖片顯示為
這裡寫圖片描述

package custom.lyxrobert.com.customcontrols;

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.widget.FrameLayout;

/**
 * Created by ytx on 2016/10/28.
 */
public class CustomLayout extends FrameLayout {
    private float ratio;
    public CustomLayout(Context context) {
        super(context);
    }

    public CustomLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.CustomLayout);
        ratio = ta.getFloat(R.styleable.CustomLayout_rario, -1);
        ta.recycle();

    }

    public CustomLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int width = MeasureSpec.getSize(widthMeasureSpec);// 獲取寬度值
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);// 獲取寬度模式
        int height;
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);// 獲取高度模式
        if (widthMode == MeasureSpec.EXACTLY
                && heightMode != MeasureSpec.EXACTLY && ratio > 0) {
            int img_width  = width - getPaddingLeft() - getPaddingRight();
            int img_height  = (int) (img_width / ratio + 0.5f);
            height = img_height  + getPaddingTop() + getPaddingBottom();
            heightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
                    MeasureSpec.EXACTLY);
        }
        // 按照最新的高度測量控件
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }
}

布局文件為,如果想給給圖片添加邊距請在custom.lyxrobert.com.customcontrols.CustomLayout裡面添加,不要在ImageView裡面設置,否則將不會起作用,因為我們的計算是在CustomLayout裡面的onMeasure方法裡面實現的。lyxrobert:rario=”1.7”裡面的1.7是圖片的寬和高的像素比



    
    


 

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