首先看一個引用:
ARemoteViews object (and, consequently, an App Widget) can support thefollowing layout classes:
*FrameLayout
*LinearLayout
*RelativeLayout
Andthe following widget classes:
*AnalogClock
*Button
*Chronometer
*ImageButton
*ImageView
*ProgressBar
*TextView
Descendantsof these classes are not supported.
可見我們widget裡面可以使用的控制項只有:AnalogClock,Button,Chronometer,ImageButton,mageView,ProgressBar,TextView這7種,Listview,Editview,Scrollview等這些很常用的控制項都無法在我們的Widget中使用。而其實這所有的控制項的源碼都是放在framework/base/core/java/android/widget這個目錄下的,這7種控制項之所以可用是因為加了@RemoteView這個標籤,我們可以看一下源碼:
AnalogClock.java:39:@RemoteView
AnalogClock.java-40-publicclass AnalogClock extends View {
ImageButton.java:66:@RemoteView
ImageButton.java-67-publicclass ImageButton extends ImageView {
…..
所以我們想要在widget中使用諸如Listview這樣的控制項的話,需要自己寫一個和Listview一模一樣的類,加上@RemoteView標籤,並拷貝到framework/base/core/java/android/widget這個目錄下。
然後我們就可以在Widget中使用我們寫的這個控制項了,由於他和其他可用控制項一樣都有@RemoteView標籤,那麼他也就能被RemoteView對象所識別了。
既然原理我們已經知道了,那麼可以按下面的步驟實現(以我自訂一個AnalogClock為例):
1.首先我完完整整的拷貝了源碼中的AnalogClock.java命名為MyClock.java到framework/base/core/java/android/widget這個目錄下,然後按自己的需求修改了代碼。
2.這個MyClock.java用到的資源檔必須存放在frameworks/base/core/res/res目錄下。而且必須是這樣的方式引用:com.android.internal.R.drawable.*
不過如果這樣做的話更換資源不太方便,我們知道每個系統控制項都有個style檔案,所以我的做法是:
先看系統的AnalogClock.java的style源檔案:
frameworks/base/core/res/res/values/attrs.xml:
<declare-styleable name="AnalogClock">
<!-省去部分代碼->
<attrname="hand_minute"format="reference"/>
</declare-styleable>
private Drawable mMinuteHand;
public MyClock(Context context, AttributeSet attrs, intdefStyle) {
super(context,attrs, defStyle);
Resources r = context.getResources();
TypedArray a = context.obtainStyledAttributes(attrs,com.android.internal.R.styleable.AnalogClock,defStyle,0);
mMinuteHand = a.getDrawable(com.android.internal.R.styleable.AnalogClock_hand_minute);//這裡就是調用attrs.xml裡的參數
if(mMinuteHand== null){
mMinuteHand= r.getDrawable(com.android.internal.R.drawable.clock_hand_minute);//而這裡是調用系統frameworks/base/core/res/res目錄下的資源
}
}
我自己在widget的布局設定檔裡面定義:
<MyClock
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/rl_widget_clockView"
<!-省去部分代碼->
android:hand_minute="@drawable/minute_white"//這裡就是引用本地drawable下的資源
android:layout_width="80dp"
android:layout_height="80dp"
/>
這一塊比較繞。。我也是反覆編譯源碼測試才成功。
3.這個時候基本上工作已經完成一大半了,我們需要編譯整個SDK。但是注意,我在編譯過程中出現了各種編譯錯誤,而且提示都是unknown,十分讓人費解,最終我總結出一套成功率極高編譯方法。
先在根目錄make-j4編譯整個純淨的源碼(注意不要添加任何我們自己定義的類和資源),大約1-2小時成功編譯結束後,再把我們自訂的類和資源等拷貝到framework下,再一次在根目錄make-j4編譯。
如果要測試我們添加的代碼,需要在全部編譯成功後,執行emulator命令啟動一個新編出的模擬器,然後在上面安裝我們的APK。
基本上已經大告成功了,也許還遺漏了一些瑣碎的問題,可以和我討論。