編輯:關於android開發
最近在寫一個關於音樂播放的應用,寫到播放界面UI時,就想自己實現的一個播放界面。那麼如何實現自定義View呢?通過查看他人博客和Android官方開發文檔,初步了解了一些淺顯的內容。在此記錄,已供需要的朋友參考。
自定義視圖的官方參考文檔:http://developer.android.com/training/custom-views/create-view.html
當我們使用XML布局文件進行UI編寫時,通過增加xml tag我們可以加入自己想要的任何view組件,例如下面的布局文件(只是個例子,刪除了其他不重要布局元素):
1 <?xml version="1.0" encoding="utf-8"?> 2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent"> 5 <TextView 6 android:layout_width="match_parent" 7 android:layout_height="match_parent" /> 8 </RelativeLayout>
用過<RelativeLayout 引入RelativeLayout,通過<TextView引入TextView。然後在對應便簽了加入了各種屬性(如:android:layout_width、android:layout_heignt),編譯程序在編譯時會解析xml文件,把對應的tag生成相應的view對象。
那麼自己定義的view如何通過上面那種方式使用呢?這就要說到xmlns(XML namespace)了。了解XML的朋友都知道,XML為了傳輸數據設計的可拓展標記語言,它不同於HTML有預定義的各種便簽,它的便簽是用戶自定義的。在哪定義呢?xmlns!
不知道你注意到沒,我們的布局文件中總是用這樣一行代碼:
xmlns:android="http://schemas.android.com/apk/res/android"
這就是引入命名空間。更過關於XML知識,請查看:XML介紹。簡單來說通過在頂級tag中引入命名空間,整個個xml都可以用命名空間中定義的內容了,如android:id等。那麼怎麼為我們的自己寫的view添加命名空間呢?
下面我們來創建自己的命名空間文件:首先在res->values目錄下新建attrs資源文件,如下圖:
在attrs中定義裡需要表述的屬性:
1 <?xml version="1.0" encoding="utf-8"?> 2 <resources> 3 <declare-styleable name="Circle"> 4 <attr name="radius" format="dimension"/> 5 <attr name="background_color" format="color"/> 6 </declare-styleable> 7 </resources>
其中declare-styeable節點的name屬性值一般是你寫的view的名字,如這裡我自己寫的view叫Cirecle。接下來定義可以在xml中定義的組件屬性,這裡可以指定兩個,radius和background。其中format屬性指定可接受值的類型,多個類型用“|”分隔。
更多關於怎麼寫attrs可以參考Android sdk目錄下的platforms\android-xxx\data\res\values\attrs.xml文件,哪裡為自帶的所有空間聲明了命名空間。
寫好的命名空間如何使用呢?下面給出布局文件:
1 <?xml version="1.0" encoding="utf-8"?> 2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 xmlns:custom="http://schemas.android.com/apk/res-auto" 4 xmlns:tools="http://schemas.android.com/tools" 5 android:layout_width="match_parent" 6 android:layout_height="match_parent" 7 android:paddingBottom="@dimen/activity_vertical_margin" 8 android:paddingLeft="@dimen/activity_horizontal_margin" 9 android:paddingRight="@dimen/activity_horizontal_margin" 10 android:paddingTop="@dimen/activity_vertical_margin" 11 tools:context="com.github.fallblank.myapplication.MainActivity"> 12 <!--引入自定義View,並設置屬性--> 13 <com.github.fallblank.myapplication.Circle 14 android:id="@+id/circle" 15 android:layout_width="wrap_content" 16 android:layout_height="wrap_content" 17 custom:background_color="#ff0000" 18 custom:radius="100dp" /> 19 <!--下面兩個按鈕是為了改變View使其重繪--> 20 <Button 21 android:id="@+id/btn_larger" 22 android:layout_width="wrap_content" 23 android:layout_height="wrap_content" 24 android:layout_alignParentBottom="true" 25 android:text="Larger" /> 26 27 <Button 28 android:id="@+id/btn_smaller" 29 android:layout_width="wrap_content" 30 android:layout_height="wrap_content" 31 android:layout_toRightOf="@id/btn_larger" 32 android:layout_alignParentBottom="true" 33 android:text="Smaller" /> 34 </RelativeLayout>
注意這行代碼:
xmlns:custom="http://schemas.android.com/apk/res-auto"
這裡就是引入自定義的命名空間,有了這行代碼後面就可以使用我們之前定義的內容custom:radius和custom:backgroud_color了。需要注意的是這裡引入的方式適合於gradle編譯,對應ant編譯,xmlns定義如下:
xmlns:custom="http://schemas.android.com/apk/res/自定義view的包名
接下來就是如何獲取在xml指定屬性的值了,下面給出自定義view的代碼:
1 package com.github.fallblank.myapplication; 2 3 import android.content.Context; 4 import android.content.res.TypedArray; 5 import android.graphics.Canvas; 6 import android.graphics.Paint; 7 import android.util.AttributeSet; 8 import android.view.View; 9 import android.widget.Toast; 10 11 /** 12 * Created by fallb on 2015/11/24. 13 */ 14 public class Circle extends View { 15 16 private int mColor; 17 private Context mContext; 18 private float mRadius; 19 20 public Circle(Context context, AttributeSet attrs) { 21 super(context, attrs); 22 mContext = context; 23 TypedArray a = context.getTheme().obtainStyledAttributes(attrs,R.styleable.Circle,0,0); 24 try { 25 // 26 mColor = a.getColor(R.styleable.Circle_line_color,0x000000); 27 mRadius = a.getDimension(R.styleable.Circle_side,16); 28 }finally { 29 a.recycle(); 30 } 31 } 32 33 public void addSide() { 34 mRadius+=5.0; 35 invalidate(); 36 requestLayout(); 37 } 38 39 public void subSide(){ 40 if (mRadius>=5.0){ 41 mRadius-=5.0; 42 invalidate(); 43 requestLayout(); 44 }else { 45 Toast.makeText(mContext,"smaller enough!",Toast.LENGTH_LONG).show(); 46 } 47 } 48 49 @Override 50 protected void onDraw(Canvas canvas) { 51 super.onDraw(canvas); 52 Paint paint = new Paint(); 53 paint.setColor(mColor); 54 canvas.drawCircle(0,0,mRadius,paint); 55 } 56 }
上面標紅的代碼就是獲取定義在xml中的屬性的方法(為什麼不用AttributeSet直接獲取屬性?官方文檔有介紹,需要了解的朋友可以去看看)
獲取到屬性後就是實現自己的繪圖方法,重載onDraw()實現繪制。對應怎麼使用Pait、canvas,我會在後面介紹。
說了這麼多,來總結一下。
為了不空放嘴炮,最後給出效果圖和代碼:
樣例代碼:https://github.com/fallblank/CustomView
現在遇到一個疑問:我定義的View在xml中的默認大小是充滿這個父控件,指定寬度為wrap_content也沒用。應該是哪裡沒設置,知道的朋友請告之!小弟大榭!
僅此拋磚引玉!
【騰訊Bugly干貨分享】深入源碼探索 ReactNative 通信機制,buglyreactnativeBugly 技術干貨系列內容主要涉及移動開發方向,是由 Bugl
Android4.4.2KK豎屏強制更改為橫屏的初步簡略方案 解決方案: 當前是根據當前問題場景即豎屏強制更改為橫屏的需求而做的改動,基本是hardcode定義的狀態,總
自定義View(二)ViewPage廣告輪播,viewviewpage自定義View的第二個學習案例,使用ViewPage實現廣告輪播,通過組合現有的View實現效果如下
Android實戰--電話撥號器,android電話撥號器今天跟著黑馬視頻建立一個android app--電話撥號器 首先新建一個android項目 activity