亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Android App中自定義View視圖的實例教程

 更新時間:2016年04月26日 14:54:06   作者:鴻洋_  
這篇文章主要介紹了Android App中自定義View視圖的實例教程,詳細(xì)講解了如何在創(chuàng)建View中定義各種鎖需要的樣式屬性,需要的朋友可以參考下

一、基礎(chǔ)
很多的Android入門程序猿來說對于Android自定義View,可能都是比較恐懼的,但是這又是高手進(jìn)階的必經(jīng)之路,所有準(zhǔn)備在自定義View上面花一些功夫,多寫一些文章。先總結(jié)下自定義View的步驟:
1、自定義View的屬性
2、在View的構(gòu)造方法中獲得我們自定義的屬性
3、重寫onMesure
4、重寫onDraw
我把3用[]標(biāo)出了,所以說3不一定是必須的,當(dāng)然了大部分情況下還是需要重寫的。

1、自定義View的屬性,首先在res/values/  下建立一個attrs.xml , 在里面定義我們的屬性和聲明我們的整個樣式。
 

<?xml version="1.0" encoding="utf-8"?> 
<resources> 
 
  <attr name="titleText" format="string" /> 
  <attr name="titleTextColor" format="color" /> 
  <attr name="titleTextSize" format="dimension" /> 
 
  <declare-styleable name="CustomTitleView"> 
    <attr name="titleText" /> 
    <attr name="titleTextColor" /> 
    <attr name="titleTextSize" /> 
  </declare-styleable> 
 
</resources> 


我們定義了字體,字體顏色,字體大小3個屬性,format是值該屬性的取值類型:
一共有:string,color,demension,integer,enum,reference,float,boolean,fraction,flag;不清楚的可以google一把。
然后在布局中聲明我們的自定義View

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
  xmlns:tools="http://schemas.android.com/tools" 
  xmlns:custom="http://schemas.android.com/apk/res/com.example.customview01" 
  android:layout_width="match_parent" 
  android:layout_height="match_parent" > 
 
  <com.example.customview01.view.CustomTitleView 
    android:layout_width="200dp" 
    android:layout_height="100dp" 
    custom:titleText="3712" 
    custom:titleTextColor="#ff0000" 
    custom:titleTextSize="40sp" /> 
 
</RelativeLayout> 

一定要引入 xmlns:custom="http://schemas.android.com/apk/res/com.example.customview01"我們的命名空間,后面的包路徑指的是項目的package

2、在View的構(gòu)造方法中,獲得我們的自定義的樣式 

/** 
   * 文本 
   */ 
  private String mTitleText; 
  /** 
   * 文本的顏色 
   */ 
  private int mTitleTextColor; 
  /** 
   * 文本的大小 
   */ 
  private int mTitleTextSize; 
 
  /** 
   * 繪制時控制文本繪制的范圍 
   */ 
  private Rect mBound; 
  private Paint mPaint; 
 
  public CustomTitleView(Context context, AttributeSet attrs) 
  { 
    this(context, attrs, 0); 
  } 
 
  public CustomTitleView(Context context) 
  { 
    this(context, null); 
  } 
 
  /** 
   * 獲得我自定義的樣式屬性 
   * 
   * @param context 
   * @param attrs 
   * @param defStyle 
   */ 
  public CustomTitleView(Context context, AttributeSet attrs, int defStyle) 
  { 
    super(context, attrs, defStyle); 
    /** 
     * 獲得我們所定義的自定義樣式屬性 
     */ 
    TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomTitleView, defStyle, 0); 
    int n = a.getIndexCount(); 
    for (int i = 0; i < n; i++) 
    { 
      int attr = a.getIndex(i); 
      switch (attr) 
      { 
      case R.styleable.CustomTitleView_titleText: 
        mTitleText = a.getString(attr); 
        break; 
      case R.styleable.CustomTitleView_titleTextColor: 
        // 默認(rèn)顏色設(shè)置為黑色 
        mTitleTextColor = a.getColor(attr, Color.BLACK); 
        break; 
      case R.styleable.CustomTitleView_titleTextSize: 
        // 默認(rèn)設(shè)置為16sp,TypeValue也可以把sp轉(zhuǎn)化為px 
        mTitleTextSize = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension( 
            TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics())); 
        break; 
 
      } 
 
    } 
    a.recycle(); 
 
    /** 
     * 獲得繪制文本的寬和高 
     */ 
    mPaint = new Paint(); 
    mPaint.setTextSize(mTitleTextSize); 
    // mPaint.setColor(mTitleTextColor); 
    mBound = new Rect(); 
    mPaint.getTextBounds(mTitleText, 0, mTitleText.length(), mBound); 
 
  } 

我們重寫了3個構(gòu)造方法,默認(rèn)的布局文件調(diào)用的是兩個參數(shù)的構(gòu)造方法,所以記得讓所有的構(gòu)造調(diào)用我們的三個參數(shù)的構(gòu)造,我們在三個參數(shù)的構(gòu)造中獲得自定義屬性。
3、我們重寫onDraw,onMesure調(diào)用系統(tǒng)提供的: 

@Override 
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) 
  { 
    super.onMeasure(widthMeasureSpec, heightMeasureSpec); 
  } 
 
  @Override 
  protected void onDraw(Canvas canvas) 
  { 
    mPaint.setColor(Color.YELLOW); 
    canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint); 
 
    mPaint.setColor(mTitleTextColor); 
    canvas.drawText(mTitleText, getWidth() / 2 - mBound.width() / 2, getHeight() / 2 + mBound.height() / 2, mPaint); 
  } 

此時的效果是:

2016426144707639.jpg (443×404)

是不是覺得還不錯,基本已經(jīng)實現(xiàn)了自定義View。但是此時如果我們把布局文件的寬和高寫成wrap_content,會發(fā)現(xiàn)效果并不是我們的預(yù)期:

2016426144731947.jpg (437×663)

系統(tǒng)幫我們測量的高度和寬度都是MATCH_PARNET,當(dāng)我們設(shè)置明確的寬度和高度時,系統(tǒng)幫我們測量的結(jié)果就是我們設(shè)置的結(jié)果,當(dāng)我們設(shè)置為WRAP_CONTENT,或者M(jìn)ATCH_PARENT系統(tǒng)幫我們測量的結(jié)果就是MATCH_PARENT的長度。
所以,當(dāng)設(shè)置了WRAP_CONTENT時,我們需要自己進(jìn)行測量,即重寫onMesure方法”:
重寫之前先了解MeasureSpec的specMode,一共三種類型:
EXACTLY:一般是設(shè)置了明確的值或者是MATCH_PARENT
AT_MOST:表示子布局限制在一個最大值內(nèi),一般為WARP_CONTENT
UNSPECIFIED:表示子布局想要多大就多大,很少使用
下面是我們重寫onMeasure代碼:

@Override 
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) 
{ 
  int widthMode = MeasureSpec.getMode(widthMeasureSpec); 
  int widthSize = MeasureSpec.getSize(widthMeasureSpec); 
  int heightMode = MeasureSpec.getMode(heightMeasureSpec); 
  int heightSize = MeasureSpec.getSize(heightMeasureSpec); 
  int width; 
  int height ; 
  if (widthMode == MeasureSpec.EXACTLY) 
  { 
    width = widthSize; 
  } else 
  { 
    mPaint.setTextSize(mTitleTextSize); 
    mPaint.getTextBounds(mTitle, 0, mTitle.length(), mBounds); 
    float textWidth = mBounds.width(); 
    int desired = (int) (getPaddingLeft() + textWidth + getPaddingRight()); 
    width = desired; 
  } 
 
  if (heightMode == MeasureSpec.EXACTLY) 
  { 
    height = heightSize; 
  } else 
  { 
    mPaint.setTextSize(mTitleTextSize); 
    mPaint.getTextBounds(mTitle, 0, mTitle.length(), mBounds); 
    float textHeight = mBounds.height(); 
    int desired = (int) (getPaddingTop() + textHeight + getPaddingBottom()); 
    height = desired; 
  } 
   
   
 
  setMeasuredDimension(width, height); 
} 

現(xiàn)在我們修改下布局文件:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
  xmlns:tools="http://schemas.android.com/tools" 
  xmlns:custom="http://schemas.android.com/apk/res/com.example.customview01" 
  android:layout_width="match_parent" 
  android:layout_height="match_parent" > 
 
  <com.example.customview01.view.CustomTitleView 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    custom:titleText="3712" 
    android:padding="10dp" 
    custom:titleTextColor="#ff0000" 
    android:layout_centerInParent="true" 
    custom:titleTextSize="40sp" /> 
 
</RelativeLayout> 

現(xiàn)在的效果是:

2016426144806075.jpg (436×678)

完全復(fù)合我們的預(yù)期,現(xiàn)在我們可以對高度、寬度進(jìn)行隨便的設(shè)置了,基本可以滿足我們的需求。
當(dāng)然了,這樣下來我們這個自定義View與TextView相比豈不是沒什么優(yōu)勢,所有我們覺得給自定義View添加一個事件:
在構(gòu)造中添加:

this.setOnClickListener(new OnClickListener() 
    { 
 
      @Override 
      public void onClick(View v) 
      { 
        mTitleText = randomText(); 
        postInvalidate(); 
      } 
 
    }); 

 
private String randomText() 
  { 
    Random random = new Random(); 
    Set<Integer> set = new HashSet<Integer>(); 
    while (set.size() < 4) 
    { 
      int randomInt = random.nextInt(10); 
      set.add(randomInt); 
    } 
    StringBuffer sb = new StringBuffer(); 
    for (Integer i : set) 
    { 
      sb.append("" + i); 
    } 
 
    return sb.toString(); 
  } 

下面再來運行:

2016426144834673.gif (429×638)

我們添加了一個點擊事件,每次讓它隨機(jī)生成一個4位的隨機(jī)數(shù),有興趣的可以在onDraw中添加一點噪點,然后改寫為驗證碼,是不是感覺很不錯。

進(jìn)階

前面已經(jīng)介紹過一個自定義View的基礎(chǔ)的例子,下面給大家?guī)硪粋€稍微復(fù)雜點的例子。
自定義View顯示一張圖片,下面包含圖片的文本介紹,類似相片介紹什么的,不過不重要,主要是學(xué)習(xí)自定義View的用法么。
直接切入正題:
1、在res/values/attr.xml
 

<?xml version="1.0" encoding="utf-8"?> 
<resources> 
 
  <attr name="titleText" format="string" /> 
  <attr name="titleTextSize" format="dimension" /> 
  <attr name="titleTextColor" format="color" /> 
  <attr name="image" format="reference" /> 
  <attr name="imageScaleType"> 
    <enum name="fillXY" value="0" /> 
    <enum name="center" value="1" /> 
  </attr> 
 
  <declare-styleable name="CustomImageView"> 
    <attr name="titleText" /> 
    <attr name="titleTextSize" /> 
    <attr name="titleTextColor" /> 
    <attr name="image" /> 
    <attr name="imageScaleType" /> 
  </declare-styleable> 
 
</resources> 

2、在構(gòu)造中獲得我們的自定義屬性:

/** 
   * 初始化所特有自定義類型 
   * 
   * @param context 
   * @param attrs 
   * @param defStyle 
   */ 
  public CustomImageView(Context context, AttributeSet attrs, int defStyle) 
  { 
    super(context, attrs, defStyle); 
 
    TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomImageView, defStyle, 0); 
 
    int n = a.getIndexCount(); 
 
    for (int i = 0; i < n; i++) 
    { 
      int attr = a.getIndex(i); 
 
      switch (attr) 
      { 
      case R.styleable.CustomImageView_image: 
        mImage = BitmapFactory.decodeResource(getResources(), a.getResourceId(attr, 0)); 
        break; 
      case R.styleable.CustomImageView_imageScaleType: 
        mImageScale = a.getInt(attr, 0); 
        break; 
      case R.styleable.CustomImageView_titleText: 
        mTitle = a.getString(attr); 
        break; 
      case R.styleable.CustomImageView_titleTextColor: 
        mTextColor = a.getColor(attr, Color.BLACK); 
        break; 
      case R.styleable.CustomImageView_titleTextSize: 
        mTextSize = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 
            16, getResources().getDisplayMetrics())); 
        break; 
 
      } 
    } 
    a.recycle(); 
    rect = new Rect(); 
    mPaint = new Paint(); 
    mTextBound = new Rect(); 
    mPaint.setTextSize(mTextSize); 
    // 計算了描繪字體需要的范圍 
    mPaint.getTextBounds(mTitle, 0, mTitle.length(), mTextBound); 
 
  } 

3、重寫onMeasure

@Override 
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) 
{ 
  // super.onMeasure(widthMeasureSpec, heightMeasureSpec); 
 
  /** 
   * 設(shè)置寬度 
   */ 
  int specMode = MeasureSpec.getMode(widthMeasureSpec); 
  int specSize = MeasureSpec.getSize(widthMeasureSpec); 
 
  if (specMode == MeasureSpec.EXACTLY)// match_parent , accurate 
  { 
    Log.e("xxx", "EXACTLY"); 
    mWidth = specSize; 
  } else 
  { 
    // 由圖片決定的寬 
    int desireByImg = getPaddingLeft() + getPaddingRight() + mImage.getWidth(); 
    // 由字體決定的寬 
    int desireByTitle = getPaddingLeft() + getPaddingRight() + mTextBound.width(); 
 
    if (specMode == MeasureSpec.AT_MOST)// wrap_content 
    { 
      int desire = Math.max(desireByImg, desireByTitle); 
      mWidth = Math.min(desire, specSize); 
      Log.e("xxx", "AT_MOST"); 
    } 
  } 
 
  /*** 
   * 設(shè)置高度 
   */ 
 
  specMode = MeasureSpec.getMode(heightMeasureSpec); 
  specSize = MeasureSpec.getSize(heightMeasureSpec); 
  if (specMode == MeasureSpec.EXACTLY)// match_parent , accurate 
  { 
    mHeight = specSize; 
  } else 
  { 
    int desire = getPaddingTop() + getPaddingBottom() + mImage.getHeight() + mTextBound.height(); 
    if (specMode == MeasureSpec.AT_MOST)// wrap_content 
    { 
      mHeight = Math.min(desire, specSize); 
    } 
  } 
  setMeasuredDimension(mWidth, mHeight); 
 
} 

4、重寫onDraw

@Override 
  protected void onDraw(Canvas canvas) 
  { 
    // super.onDraw(canvas); 
    /** 
     * 邊框 
     */ 
    mPaint.setStrokeWidth(4); 
    mPaint.setStyle(Paint.Style.STROKE); 
    mPaint.setColor(Color.CYAN); 
    canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint); 
 
    rect.left = getPaddingLeft(); 
    rect.right = mWidth - getPaddingRight(); 
    rect.top = getPaddingTop(); 
    rect.bottom = mHeight - getPaddingBottom(); 
 
    mPaint.setColor(mTextColor); 
    mPaint.setStyle(Style.FILL); 
    /** 
     * 當(dāng)前設(shè)置的寬度小于字體需要的寬度,將字體改為xxx... 
     */ 
    if (mTextBound.width() > mWidth) 
    { 
      TextPaint paint = new TextPaint(mPaint); 
      String msg = TextUtils.ellipsize(mTitle, paint, (float) mWidth - getPaddingLeft() - getPaddingRight(), 
          TextUtils.TruncateAt.END).toString(); 
      canvas.drawText(msg, getPaddingLeft(), mHeight - getPaddingBottom(), mPaint); 
 
    } else 
    { 
      //正常情況,將字體居中 
      canvas.drawText(mTitle, mWidth / 2 - mTextBound.width() * 1.0f / 2, mHeight - getPaddingBottom(), mPaint); 
    } 
 
    //取消使用掉的快 
    rect.bottom -= mTextBound.height(); 
 
    if (mImageScale == IMAGE_SCALE_FITXY) 
    { 
      canvas.drawBitmap(mImage, null, rect, mPaint); 
    } else 
    { 
      //計算居中的矩形范圍 
      rect.left = mWidth / 2 - mImage.getWidth() / 2; 
      rect.right = mWidth / 2 + mImage.getWidth() / 2; 
      rect.top = (mHeight - mTextBound.height()) / 2 - mImage.getHeight() / 2; 
      rect.bottom = (mHeight - mTextBound.height()) / 2 + mImage.getHeight() / 2; 
 
      canvas.drawBitmap(mImage, null, rect, mPaint); 
    } 
 
  } 

代碼,結(jié)合注釋和基礎(chǔ)部分View的使用,應(yīng)該可以看懂,不明白的留言。下面我們引入我們的自定義View:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
  xmlns:tools="http://schemas.android.com/tools" 
  xmlns:zhy="http://schemas.android.com/apk/res/com.zhy.customview02" 
  android:layout_width="match_parent" 
  android:layout_height="match_parent" 
  android:orientation="vertical" > 
 
  <com.zhy.customview02.view.CustomImageView 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:layout_margin="10dp" 
    android:padding="10dp" 
    zhy:image="@drawable/ic_launcher" 
    zhy:imageScaleType="center" 
    zhy:titleText="hello andorid ! " 
    zhy:titleTextColor="#ff0000" 
    zhy:titleTextSize="30sp" /> 
 
  <com.zhy.customview02.view.CustomImageView 
    android:layout_width="100dp" 
    android:layout_height="wrap_content" 
    android:layout_margin="10dp" 
    android:padding="10dp" 
    zhy:image="@drawable/ic_launcher" 
    zhy:imageScaleType="center" 
    zhy:titleText="helloworldwelcome" 
    zhy:titleTextColor="#00ff00" 
    zhy:titleTextSize="20sp" /> 
 
  <com.zhy.customview02.view.CustomImageView 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:layout_margin="10dp" 
    android:padding="10dp" 
    zhy:image="@drawable/lmj" 
    zhy:imageScaleType="center" 
    zhy:titleText="妹子~" 
    zhy:titleTextColor="#ff0000" 
    zhy:titleTextSize="12sp" /> 
 
</LinearLayout> 

我特意讓顯示出現(xiàn)3中情況:
1、字體的寬度大于圖片,且View寬度設(shè)置為wrap_content
2、View寬度設(shè)置為精確值,字體的長度大于此寬度
3、圖片的寬度大于字體,且View寬度設(shè)置為wrap_content
看看顯示效果:

2016426145053519.jpg (441×676)

怎么樣,對于這三種情況所展示的效果都還不錯吧。

相關(guān)文章

  • android實現(xiàn)輪播圖引導(dǎo)頁

    android實現(xiàn)輪播圖引導(dǎo)頁

    這篇文章主要為大家詳細(xì)介紹了android實現(xiàn)輪播圖引導(dǎo)頁,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-09-09
  • Android studio gradle環(huán)境變量配置教程

    Android studio gradle環(huán)境變量配置教程

    這篇文章主要為大家詳細(xì)介紹了Android studio gradle環(huán)境變量配置教程,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-05-05
  • Android狀態(tài)欄的適配匯總

    Android狀態(tài)欄的適配匯總

    這篇文章主要給大家介紹了關(guān)于Android狀態(tài)欄適配的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對各位Android開發(fā)者們具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-05-05
  • Android實現(xiàn)手繪功能

    Android實現(xiàn)手繪功能

    這篇文章主要為大家詳細(xì)介紹了Android實現(xiàn)手繪功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-05-05
  • Flutter應(yīng)用框架搭建之屏幕適配詳解

    Flutter應(yīng)用框架搭建之屏幕適配詳解

    因移動設(shè)備的多樣性,特別是 Android 的碎片化嚴(yán)重,存在各種各樣的分辨率,而 Flutter 跨平臺開發(fā)又需同時支持 Android 和 iOS ,為盡可能的還原設(shè)計圖效果提升用戶體驗,屏幕適配就勢在必行了。本文將詳細(xì)講解Flutter屏幕適配的方法,需要的可以參考一下
    2022-03-03
  • android實現(xiàn)主動連接和被動連接的藍(lán)牙聊天功能

    android實現(xiàn)主動連接和被動連接的藍(lán)牙聊天功能

    這篇文章主要為大家詳細(xì)介紹了android實現(xiàn)主動連接和被動連接的藍(lán)牙聊天功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-06-06
  • Android Studio用genymotion運行后小圖標(biāo)無法顯示問題

    Android Studio用genymotion運行后小圖標(biāo)無法顯示問題

    這篇文章主要介紹了Android Studio用genymotion運行后小圖標(biāo)無法顯示的問題,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-04-04
  • Android應(yīng)用App更新實例詳解

    Android應(yīng)用App更新實例詳解

    現(xiàn)在一般的Android軟件都是需要不斷更新的,當(dāng)你打開某個app的時候,如果有新的版本,它會提示你有新版本需要更新。該項目實現(xiàn)的就是這個功能。下面跟著小編一起來看下吧
    2017-03-03
  • Android仿今日頭條APP實現(xiàn)下拉導(dǎo)航選擇菜單效果

    Android仿今日頭條APP實現(xiàn)下拉導(dǎo)航選擇菜單效果

    這篇文章主要為大家詳細(xì)介紹了Android仿今日頭條APP實現(xiàn)下拉導(dǎo)航選擇菜單效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-06-06
  • Android中的Intent Filter匹配規(guī)則簡介

    Android中的Intent Filter匹配規(guī)則簡介

    這篇文章主要為大家詳細(xì)介紹了Android中的Intent Filter匹配規(guī)則,感興趣的小伙伴們可以參考一下
    2016-04-04

最新評論