Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android自定義UI陷阱:LayoutInflater.from().inflate()一定不能工作在父類或虛類裡

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

編輯:關於Android編程

問題背景:有一些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 stub
		mContext = context;
		mGuideViewCallback = callback;
		setOnClickListener(this);
		mOrientation = OrientationUtil.getOrientation();
		
	}


	@Override
	public void setOrientation(int orientation, boolean animation) {
		// TODO Auto-generated method stub
		mOrientation = orientation;
		requestLayout();
	}

	protected abstract void initView();

	@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {
		// TODO Auto-generated method stub
		return true; //super.onInterceptTouchEvent(ev)
	}

	@Override
	public void onClick(View v) {
		// TODO Auto-generated method stub
		mGuideViewCallback.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 stub
		initView();
	}

	@Override
	protected void initView() {
		// TODO Auto-generated method stub
		Log.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:



<frameLayout 
    android:id="@+id/guide_nan_layout"
    android:layout_width="200dip"
    android:layout_height="150dip"
    android:background="@drawable/nan1">
    
    
</frameLayout>    


在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 0x00000000

07-06 15:17:58.258 D/AndroidRuntime( 8375): Shutting down VM

07-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自行加載並初始化是最好的。

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





  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved