Android自訂UI陷阱:LayoutInflater.from().inflate()一定不能工作在父類或虛類裡

來源:互聯網
上載者:User

Android自訂UI陷阱:LayoutInflater.from().inflate()一定不能工作在父類或虛類裡

問題背景:有一些UI具有共性,比如常見的app第一次運行時出現的各種指示框,告訴你往哪搓是調音量的,往哪點是調螢幕亮度的,當點擊這些VIew,則其自動消失。或者一動時間後,自動消失。另外一個問題是,不同的方向下載入出來的指示View內容是不一樣的。

為此需要將這些特點的View抽象出來,寫個父類或者說是基類,為啥一定要這樣搞,這樣寫好處很多。優點如下:

1、可以讓代碼變得更簡潔。每個子View裡的共同的方法都由父類來做,每個子View實現自己的邏輯就ok了。

2、因為這些View只工作一次,所以寫死在主UI的xml裡顯得不合時宜,動態添加是最好的。因為牽涉到旋轉方向問題,就必須要提前給出這些View的執行個體化變數名稱。如果互相之間是完全是獨立的,則需要定義View1 view1, View2 view2...很多個View,然後方向發生變化時挨個通知。如果有個BaseView, View1和View2...都是繼承自BaseView,則只需定義BaseView baseView,需要顯示時用BaseView執行個體化具體的是View1 還是View2.如: baseView = new View1(...).然後方向變化時判斷baseView是否為空白,然後把方向告訴它就ok了。

先來看上面提到的BaseView,這裡命名為BaseGuideView:

package org.yanzi.ui;import org.yanzi.util.OrientationUtil;import android.content.Context;import android.view.MotionEvent;import android.view.View;import android.widget.RelativeLayout;import android.widget.TextView;public abstract  class BaseGuideView extends RelativeLayout implements Rotatable, View.OnClickListener {protected int mOrientation = 0;protected Context mContext;private GuideViewCallback mGuideViewCallback;public interface GuideViewCallback{public void onGuideViewClick();}public BaseGuideView(Context context, GuideViewCallback callback) {super(context);// TODO Auto-generated constructor stubmContext = context;mGuideViewCallback = callback;setOnClickListener(this);mOrientation = OrientationUtil.getOrientation();}@Overridepublic void setOrientation(int orientation, boolean animation) {// TODO Auto-generated method stubmOrientation = orientation;requestLayout();}protected abstract void initView();@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {// TODO Auto-generated method stubreturn true; //super.onInterceptTouchEvent(ev)}@Overridepublic void onClick(View v) {// TODO Auto-generated method stubmGuideViewCallback.onGuideViewClick();}}

最重要一點是我再onInterceptTouchEvent裡把點擊事件給消費了,這樣布局裡的孩子就接收不到點擊了。然後寫了一個GuideViewCallback,當被點擊時,會觸發onGuideViewClick,這個介面的實現在另一個地方,如集中管理Ui的地方。將這個彈框再消失。另外,就是每次方向發生改變都會執行requestLayout,重新執行view的onMeasure和onLayout.

再定義個NanShiGuide.java繼承自上面的類:

package org.yanzi.ui;import com.example.test1.R;import android.content.Context;import android.util.Log;import android.view.LayoutInflater;import android.view.View;import android.widget.TextView;public class NanShiGuide extends BaseGuideView {int LAYOUT_ID = R.layout.c_nanshi_guide;View guideNanLayout;TextView guideNanText;public NanShiGuide(Context context, GuideViewCallback callback) {super(context, callback);// TODO Auto-generated constructor stubinitView();}@Overrideprotected void initView() {// TODO Auto-generated method stubLog.i("YanZi", "NanShiGuide initView enter...");View v = LayoutInflater.from(mContext).inflate(LAYOUT_ID, this, true);guideNanLayout = v.findViewById(R.id.guide_nan_layout);guideNanText = (TextView) v.findViewById(R.id.guide_nan_text);Log.i("YanZi", "NanShiGuide initView exit...");}}

在這個子類裡就可以將資源載入進來了。對應的布局c_nanshi_guide.xml:

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent" ><FrameLayout     android:id="@+id/guide_nan_layout"    android:layout_width="200dip"    android:layout_height="150dip"    android:background="@drawable/nan1">    <TextView         android:id="@+id/guide_nan_text"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:gravity="center"        android:layout_gravity="bottom|center_horizontal"        android:textColor="@android:color/white"        android:textSize="20sp"        android:text="南公懷瑾."/>    </FrameLayout>    </RelativeLayout>
在initView函數裡將xml載入進來並獲得各個控制項的執行個體,我所遇到的問題是,如果這個initView()寫在基類(也是個虛類)BaseGuideView的建構函式裡,是不能夠正常啟動並執行。雖然initView()函數執行了,但是會報錯:

07-06 15:17:58.258 I/YanZi   ( 8375): NanShiGuide initView enter...07-06 15:17:58.258 W/ResourceType( 8375): No package identifier when getting value for resource number 0x0000000007-06 15:17:58.258 D/AndroidRuntime( 8375): Shutting down VM07-06 15:17:58.258 W/dalvikvm( 8375): threadid=1: thread exiting with uncaught exception (group=0x410899a8)

找不到package的指標。按理說從java的文法上是完全可以這麼用的,虛類調一個虛方法,虛方法由各個子類具體實現,但這裡報錯了。原因是因為:

View v = LayoutInflater.from(mContext).inflate(LAYOUT_ID, this, true);

這裡有個this指標的問題,當initVIew()讓虛類調用時,這個this指向誰?是虛類自己還是子類?正因此才掛了,另外這個inflate本身就有一定特殊性,是不能隨便亂用this的。我嘗試過把BaseGuideView裡的initView不寫成虛的,而是一個空的函數,依舊是報錯。所以遇到這種情況,載入布局一定由各個子View自行載入並初始化是最好的。

效果如下,左上方的圖片就是特意顯示的,同時將背景變暗:





聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.