Android應用程式使用View和ViewGroup來構建使用者介面,它們都是繼承自View類(或其子類)例如:Button、TextView、EditText等。各類View搭配上Style和Animation可以編織出非常豐富的UI,足以應付絕大部分的需求。但有時候我們也需要一些特別的View
,以帶給使用者與眾不同的體驗。
在此我打算寫一個大長篇都是關於android
View的,主要內容為:SDK上部分文章翻譯(英文水平有限盡請拍磚);自訂的View、android原始碼分析、開源View程式碼分析;各類App應用的介面模仿;以理論+程式碼範例+實踐
的方式指導本系列博文的撰寫。
——因為本人水平有限,而且寫系列經常虎頭蛇尾,所以這個系列就不寫總目錄了。如果哪天您發現本系列不在更新,而我又開始了另一個“大長篇”,那麼請扔雞蛋吧。(但是我們不退票!)
——出於前車之鑒,本系列中的源碼將不提供打包服務。
言歸正傳,在我們編寫android程式時一般是自訂以一個類繼承自Activity
並且重寫onCreate方法:
@Override
public void onCreate(Bundle
savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
setContentView()方法包含多個重載其中一個便是“setContentView(View
view)”,也就是說可以直接通過一個View的執行個體來構建內容。我們嘗試放入一個TextView,上面的代碼變成了這樣:
@Override
public void onCreate(Bundle
savedInstanceState) {
super.onCreate(savedInstanceState);
//
setContentView(R.layout.main);
TextView sayHello = new
TextView(this);
sayHello.setText("Hello world! I'm a
TextView.");
setContentView(sayHello);
}
運行這段代碼,在模擬器上你應該可以看到以下結果:
如此簡單不是嗎?好吧讓我們再讓它豐富點:
@Override
public void onCreate(Bundle
savedInstanceState) {
super.onCreate(savedInstanceState);
//
setContentView(R.layout.main);
// TextView sayHello = new
TextView(this);
// sayHello.setText("Hello world! I'm a
TextView.");
setContentView(new SayHello(this));
}
class SayHello extends View{
public SayHello(Context context)
{
super(context);
}
@Override
protected void onDraw(Canvas
canvas) {
super.onDraw(canvas);
Paint mPaint=new Paint()
;
mPaint.setTextSize(22f);
mPaint.setColor(Color.RED);
canvas.drawText("Hello
world! I'm a TextView.", 0, 100, mPaint);
}
}
這次我們自訂了一個局部類SayHello 繼承自View並且重寫了 onDraw
方法(需要注意的是由於View沒有無參建構函式所以我們為其指定實現哪一個建構函式)。在onDraw
方法中我們定義了一個Paint,現在你只需要理解它有繪畫的功能即可,那麼它要在哪裡繪畫呢?答案就是在Canvas上,可以把Canvas理解成畫布。
現在我們設定mPaint的字型大小為22F 顏色為紅色,然後在畫布上寫出“Hello
world。。。”這幾個紅色的字,並且把onCreate裡的setContentView 為setContentView(new
SayHello(this));
最後在模擬器上你應該看到的是:
so cool! 不是嗎?
不!不對,我們在Android的開發View不是這樣的,它應該是通過
Xml.......@##¥%
好吧 讓我們再把例子修改一下。
首先我們將SayHello
類提取出來,並且將它放入一個單獨的類檔案中,接下來就是重點:我們需要添加另外的一些建構函式以便給View傳遞參數,最好你看到的SayHello
類應該是這樣的:
public class SayHello extends View
{
public SayHello(Context
context)
{
super(context);
}
public SayHello(Context context, AttributeSet
attrs) {
this(context, attrs,0);
}
public SayHello(Context
context, AttributeSet attrs,int defStyle)
{
super(context, attrs,
defStyle);
}
@Override
protected void onDraw(Canvas
canvas) {
super.onDraw(canvas);
Paint mPaint=new Paint()
;
mPaint.setTextSize(22f);
mPaint.setColor(Color.RED);
canvas.drawText("Hello
world! I'm a TextView.", 0, 100, mPaint);
}
}
這裡簡單講解一下新增的建構函式的作用,在新的建構函式中為View的建構函式傳遞了AttributeSet
attrs,int defStyle兩個參數,這代表著該View可以通過XML
來建立並且接受Style來設定樣式。等到相關博文時會再具體講解。
接下來,我們恢複Activity類裡的onCreate方法讓它看起來像這個樣子:
@Override
public void onCreate(Bundle
savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
和一開始沒啥兩樣對吧。
最後我們需要去修改布局檔案main 在檔案裡加入以下 xml標籤:
<com.××××.customview.SayHello
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
</com.××××.customview.SayHello>
(注意××××,代表SayHello類所在的包,這裡需要的是全名)。
然後再次運行程式,你應該看到以下結果:
是不是和我們平常定義View時很像了?
你感覺得還不夠,還缺乏些什嗎?
好吧,你很聰明,我們的Text應該是在XML上通過某個屬性配置而成的,而不是寫在代碼裡!
為了將SayHello的屬性暴露到XMl上首先我們需要在res/value
檔案夾下建立一個XMl檔案,命名為:atts。
在裡面添加如下代碼:
<?xml version="1.0"
encoding="utf-8"?>
<resources>
<declare-styleable
name="SayHello">
<attr name="content"
format="string"></attr>
<attr name="text_color"
format="color"></attr>
</declare-styleable>
</resources>
需要注意的是這裡是沒有智能提示的
然後我們需要修改SayHello類,還記得那個AttributeSet嗎?我們將通過它來擷取XML配置上的屬性值。修改後的SayHello類代碼是這樣的:
private int mColor;
private String
mContent;
public SayHello(Context context, AttributeSet
attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray
typeArray =
context.obtainStyledAttributes(attrs,
R.styleable.SayHello);
mColor=typeArray.getColor(R.styleable.SayHello_text_color,
0XFF00FF00);
mContent=typeArray.getString(R.styleable.SayHello_content);
}
@Override
protected void onDraw(Canvas
canvas) {
super.onDraw(canvas);
Paint mPaint = new
Paint();
mPaint.setTextSize(22f);
mPaint.setColor(mColor);
canvas.drawText(mContent,
0, 100, mPaint);
}
現在可以去XML上為哥哥屬性添加值了,不過先別著急我們的得將命名空間告訴它。
在布局檔案的根源是上(通常是Layout)添加: xmlns:SayHello="http://schemas.android.com/apk/res/com.XXXX.customview"
SayHello
可以為您任意想要定義的名字,它將作為屬性的首碼使用就像android:Layout 一樣而我們的為:SayHello:content,後半段http://schemas.android.com/apk/res/ 為固定值,緊接著的是你整個APP的包命名,你不知道自己包名稱?趕去去
AndroidManifest.xml檔案中看看吧(注意該包名需要保持和manifest中的 package
保持一致,否則會提示無法找到XML屬性)。
最後我們終於可以在XML上定義自己想要的字型顏色的內容了:
<com.XXXX.customview.SayHello
android:layout_width="fill_parent"
android:layout_height="wrap_content"
SayHello:text_color="#1212f0"
SayHello:content="this is a xml attr
view">
</com.XXXX.customview.SayHello>
運行程式您應該會看到以下結果:
這就是我們View 一般的定義方式和過程。
——啟航。
//本筆記從 麥庫中複製過來, 圖片連不上,請見諒