重寫setContentView實現多個Activity部分UI布局相同
安卓應用中不同的activity一般都具有相同的地方,最典型的是標題欄(titlebar),我們只需在每個activity中調用setTitle就可以得到一個除了標題文字不同,其他完全相同的標題欄。
系統已經為我們引進了titlebar這樣的功能,但是如果我們還需要一個類似titlebar這樣容易copy外形的bottombar呢?
當然是否需要一個bottombar是個問題,我要說的其實是如果我們想讓activity共享一部分UI的情況下該怎么做。
很直觀的我們會寫一個activity的子類,然后將公共部分的UI在這個子類activity中實現,命名為BaseActivity,最后所有要共享此部分UI的activity都繼承這個BaseActivity。
思路是這樣,但是究竟該如何寫這個BaseActivity呢,注意上面藍色那句話,公共部分的UI如果是通過setContentView來渲染的話那該如果處理BaseActivity子類中其獨有的UI呢,合理的情況是在BaseActivity子類中調用setContentView來顯示自己獨有的界面,但是兩次調用setContentView總有一次是會被覆蓋的。
現在的情況是,我們想得到公共的UI,但沒辦法把公共部分和獨有部分的UI分開來處理。解決問題的辦法是了解activity的布局到底是如何組成的,setContentView做了些什么。
一、DecorView為整個Window界面的最頂層View。
二、DecorView只有一個子元素為LinearLayout。代表整個Window界面,包含通知欄,標題欄,內容顯示欄三塊區域。
三、LinearLayout里有兩個FrameLayout子元素。
(20)為標題欄顯示界面。只有一個TextView顯示應用的名稱。也可以自定義標題欄,載入后的自定義標題欄View將加入FrameLayout中。
(21)為內容欄顯示界面。就是setContentView()方法載入的布局界面,加入其中。
所以要實現activity具有公共部分的UI,重寫setContentView()方法:
import android.app.Activity; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.View.OnClickListener; import android.view.ViewGroup.LayoutParams; import android.widget.LinearLayout; import android.widget.TextView; public class BaseActivity extends Activity { private TextView mTitleTx; private View mBack; private LinearLayout contentLayout;@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); initContentView(); initTitleBar(); } public void initTitleBar(){ mTitleTx = (TextView)findViewById(R.id.titlebar_title); mBack = findViewById(R.id.titlebar_left); mBack.setOnClickListener(new OnClickListener(){ @Override public void onClick(View view){ finish(); } }); } private void initContentView() { ViewGroup content = (ViewGroup) findViewById(android.R.id.content); content.removeAllViews(); contentLayout=new LinearLayout(this); contentLayout.setOrientation(LinearLayout.VERTICAL); content.addView(contentLayout); LayoutInflater.from(this).inflate(R.layout.common_title_bar, contentLayout, true); } @Override public void setContentView(int layoutResID) { //View customContentView = LayoutInflater.from(this).inflate(layoutResID,null); /*this is the same result with View customContentView = LayoutInflater.from(this).inflate(layoutResID,contentLayout, false); */ //contentLayout.addView(customContentView,LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT); LayoutInflater.from(this).inflate(layoutResID, contentLayout, true); } @Override public void setContentView(View customContentView) { contentLayout.addView(customContentView); } @Override public void setTitle(CharSequence title) { mTitleTx.setText(title); }
}</pre>
(ViewGroup) findViewById(android.R.id.content)
可以獲得掛在一個activity內容部分LinearLayout。在這個LinearLayout中添加一個LinearLayoutcontentLayout=new LinearLayout(this);contentLayout.setOrientation(LinearLayout.VERTICAL); content.addView(contentLayout);作為新的內容區域。
接下來將公共部分的UI添加進新的內容區域。
LayoutInflater.from(this).inflate(R.layout.common_title_bar, contentLayout, true);我這里是自定義了一個標題欄作為公共部分,其實如果是標題欄可以不如此麻煩直接用原生的titlebar就行了。
然后重寫setContentView,將子類的內容區域從原本該直接掛在到
android.R.id.content
上面改為掛在到這個新的內容區域。代碼如下:@Override public void setContentView(int layoutResID) {LayoutInflater.from(this).inflate(layoutResID, contentLayout, true);
}</pre>