編輯:關於Android編程
·PreferenceActivity可以顯示一系列Header,每一個Header可以關聯一個Fragment或者Activity。此外,它還可以直接顯示Preference條目。
·PreferenceActivity顯示Header的時候有兩種模式:single pane和two panes;如果是Fragment,那麼在two panes模式下,也就是大屏模式下,它可以同時顯示Header和Fragment,這充分利用了屏幕的空間。而在singlepane模式下只會顯示Header,無論如何,我們都可以在Header關聯的Fragment中再顯示Preference條目。
如上描述可用示意圖標示:
在介紹它的使用方法之前,為了更好的理解PreferenceActivity,我會先對源碼做一個簡單的分析,分析結束後再介紹它的用法,包括顯示Header和顯示preference,這樣更容易理解為什麼會這麼使用。
這裡的Preference指的是顯示在PreferenceActivity中的UI構建塊,例如ListPreference,CheckBoxPreference等,他們都是Preference的子類(非直接):
這裡主要介紹分析PreferenceActivity中的Header,onBuildHeaders,加載Preference,加載Header,事件處理等內容,下圖是簡單概要:
可以看到PreferenceActivity繼承自ListActivity,而ListActivity是一個封裝了ListView的Activity,在ListActivity中給ListView設置了事件監聽器:
mList.setOnItemClickListener(mOnClickListener);
這個事件監聽器是這樣的:
private AdapterView.OnItemClickListener mOnClickListener = new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterViewparent, View v, int position, long id)
{
onListItemClick((ListView)parent, v, position, id);
}
};
可以看到在監聽器中,又簡單調用了onListItemClick方法,這個方法的定義如下:
protected void onListItemClick(ListView l, View v, int position, long id) {
}
它是一個空的方法,如果你的Activity繼承自ListActivity,想處理ListView的事件的話,只需要重寫這個方法。
ListActivity中提供了給ListView設置適配器的接口,但是適配器還得自己去寫,因此可以說ListActivity功能有限。PreferenceActivity繼承了ListActivity,那麼它當然主要是一個ListView了,那麼它會怎樣給ListView設置適配器呢?它又怎樣處理按鍵事件?
Header是PreferenceActivity一個非常重要的概念,PreferenceActivity可以顯示一系列的Header,每一個Header可以給它關聯一個fragment,這樣當你點擊這個Header時,就會打開它關聯的fragment,但是不局限於此,從源碼來看,如果沒有關聯Fragment,那麼也可以設置Intent,此時,可以通過Intent打開對應的Activity。
這個類還有兩種模式,singlepane和two panes,分別針對小屏幕設備和大屏幕設備。對小屏幕設備而言,屏幕只會顯示header,而大屏則會同時顯示它關聯的frament。
Header是一個定義在PreferenceActivity中的內部類:
public static final class Header implements Parcelable {
它實現了Parcelable接口,表明它可以被序列化。它無非就是一個容器,裡面保存了一個條目的所有相關的內容,比如這個條目的title-標題,summary-描述,fragment-關聯的fragment等等。當我們要顯示它的時候,我們只需要構造好Header,然後把它提交給PreferenceActivity就可以了,提交的方法是重寫onBuildHeaders方法,這個方法的參數是一個List
setListAdapter(new HeaderAdapter(this, mHeaders, mPreferenceHeaderItemResId,
mPreferenceHeaderRemoveEmptyIcon));
可以看到它給ListView設置的適配器是一個HeaderAdapter.那麼這個Adapter是什麼呢?
private static class HeaderAdapter extends ArrayAdapter
private static class HeaderViewHolder {
ImageView icon;
TextView title;
TextView summary;
}
private LayoutInflater mInflater;
private int mLayoutResId;
private boolean mRemoveIconIfEmpty;
public HeaderAdapter(Context context, List
boolean removeIconBehavior) {
super(context, 0, objects);
mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mLayoutResId = layoutResId;
mRemoveIconIfEmpty = removeIconBehavior;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
HeaderViewHolder holder;
View view;
if (convertView == null) {
view = mInflater.inflate(mLayoutResId, parent, false);
holder = new HeaderViewHolder();
holder.icon = (ImageView) view.findViewById(com.android.internal.R.id.icon);
holder.title = (TextView) view.findViewById(com.android.internal.R.id.title);
holder.summary = (TextView) view.findViewById(com.android.internal.R.id.summary);
view.setTag(holder);
} else {
view = convertView;
holder = (HeaderViewHolder) view.getTag();
}
// All view fields must be updated every time, because the view may be recycled
Header header = getItem(position);
if (mRemoveIconIfEmpty) {
if (header.iconRes == 0) {
holder.icon.setVisibility(View.GONE);
} else {
holder.icon.setVisibility(View.VISIBLE);
holder.icon.setImageResource(header.iconRes);
}
} else {
holder.icon.setImageResource(header.iconRes);
}
holder.title.setText(header.getTitle(getContext().getResources()));
CharSequence summary = header.getSummary(getContext().getResources());
if (!TextUtils.isEmpty(summary)) {
holder.summary.setVisibility(View.VISIBLE);
holder.summary.setText(summary);
} else {
holder.summary.setVisibility(View.GONE);
}
return view;
}
}
從定義中可以看到,HeaderAdapter是一個ArrayAdapter的子類,並且復寫了getView方法。在getView方法中,根據header中的內容,填充icon,title.summary等。
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
if (!isResumed()) {
return;
}
super.onListItemClick(l, v, position, id);
if (mAdapter != null) {
Object item = mAdapter.getItem(position);
if (item instanceof Header) onHeaderClick((Header) item, position);
}
}
可以看到它重寫了onListItemClick方法,用於處理事件,在這個方法中調用了onHeaderClick方法:
public void onHeaderClick(Header header, int position) {
if (header.fragment != null) {
if (mSinglePane) {
int titleRes = header.breadCrumbTitleRes;
int shortTitleRes = header.breadCrumbShortTitleRes;
if (titleRes == 0) {
titleRes = header.titleRes;
shortTitleRes = 0;
}
startWithFragment(header.fragment, header.fragmentArguments, null, 0,
titleRes, shortTitleRes);
} else {
switchToHeader(header);
}
} else if (header.intent != null) {
startActivity(header.intent);
}
}
這個方法中判斷header中是否設置了frament,如果設置了,又會判斷是不是處於singpane模式,如果是,就會啟動fragment,如果不是singlepane,那麼肯定就是two panes模式了,這個時候則切換到Header關聯的Fragment中顯示Fragment中的preference。如果沒有設置fragment,那麼又會判斷有沒有設置Intent,如果設置了Intent,那麼會啟動Intent所指向的Activity。
關於Header的顯示,我們可以自定義適配器,這時候需要重寫setListAdapter方法,比如:
@Override
public void setListAdapter(ListAdapter adapter) {
if (adapter == null) {
super.setListAdapter(null);
} else {
}
}
這個方法是ListActivity中提供的用於設置適配器的方法,這個方法在PreferenceActivity的onCreate方法中調用,用來給ListView設置適配器。
構造Header則需要重寫onBuildHeaders方法,比如:
@Override
public void onBuildHeaders(List
}
這個方法在PreferenceActivity的onCreate方法中調用。它的調用在setListAdapter之前,用來構造Header。
寫一個Activity,繼承PreferenceActivity,然後覆寫onBuildHeaders方法即可:
public class MainActivity extends PreferenceActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_main);
}
@Override
public void onBuildHeaders(List
for(int i=0;i<5;i++){
Header header = new Header();
header.title = "hello"+i;
header.summary = "hehe"+i;
header.extras = new Bundle();
header.fragment = MyFrament.class.getName();
target.add(header);
}
super.onBuildHeaders(target);
}
}
注意:
1.setContentView要注釋掉,因為如果重新設置ContentView,那麼ListActivity中設置的ListView就找不到了。
2.onBuildHeaders中,構造的header要添加到target列表中。
3.fragment一定要設置,不設置就不會顯示的,因此你需要自己實現一個與Header關聯的Fragment,這個Fragment會在點擊Header的時候被打開。
4.因為PreferenceActivity中已經提供了默認的適配器,所以,如果不需要自定義,則不需重寫setListAdapter方法。
這樣只是單純的可以顯示一些Header,但是點擊Header還是會報錯,我們還必須要覆寫一個方法:
@Override
protected boolean isValidFragment(String fragmentName) {
return true;
}
即明確告訴PrefercenceActivity我們准備了一個合法的Fragment。
在Fragment中可以顯示preference了,這裡暫時什麼都不顯示,這樣打開的是一個空頁面:
public class MyFrament extends PreferenceFragment {
public void onCreate(Bundle b) {
super.onCreate(b);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return null;
}
}
代碼效果如下:
XML構造Header更加簡單方便。
2.1構建xml文件:
xmlns:android="http://schemas.android.com/apk/res/android">
android:icon="@mipmap/ic_launcher"
android:title="Prefs 1"
android:summary="An example of some preferences." />
android:icon="@mipmap/ic_launcher"
android:title="Prefs 2"
android:summary="Some other preferences you can see.">
android:title="Intent"
android:summary="Launches an Intent.">
android:data="http://www.baidu.com" />
2.2加載XML文件:
public void onBuildHeaders(List
// for(int i=0;i<5;i++){
// Header header = new Header();
// header.title = "hello"+i;
// header.summary = "hehe"+i;
// header.fragment = MyFrament.class.getName();
// target.add(header);
// }
// super.onBuildHeaders(target);
loadHeadersFromResource(R.xml.preference_header, target);
}
也就是說還是要重寫onBuilderHeaders方法,只不過這次試用loadHeadersFromResource方法從xml中加載header了。
代碼效果如下:
PreferenceActivity除了可以顯示Header和它關聯的fragment之外,還可以直接顯示preference,這些prefercence可以直接從XML文件中加載。PreferenceActivity顯示preference的Api大都可以在PreferenceFragment中找到,而且更推薦使用PreferenceFragment來顯示preference,不過在很多比較舊的的代碼中,還保留著很多使用PreferenceActivity顯示preference的代碼。
使用PreferenceActivity顯示preference只需要兩步:
3.1在xml文件下創建xml配置文件:
android:icon="@drawable/ic_settings_wifi_4"
android:key="network"
android:title="@string/connectivity_network" >
android:targetClass="com.android.tv.settings.connectivity.NetworkActivity"
android:targetPackage="com.android.tv.settings" />
android:icon="@drawable/ic_settings_cast"
android:key="cast"
android:title="@string/system_cast" >
android:icon="@drawable/ic_settings_apps"
android:key="apps"
android:title="@string/device_apps" >
android:targetClass="com.android.tv.settings.device.apps.AppsActivity"
android:targetPackage="com.android.tv.settings" />
android:icon="@drawable/ic_settings_storage"
android:key="storagereset"
android:title="@string/device_storage_reset" >
android:targetClass="com.android.tv.settings.device.StorageResetActivity"
android:targetPackage="com.android.tv.settings" />
android:icon="@drawable/ic_settings_about"
android:key="about_device"
android:title="@string/about_preference">
android:targetClass="com.android.tv.settings.about.AboutActivity"
android:targetPackage="com.android.tv.settings" />
PreferenceScreen中的內容會顯示在一個新的屏幕中,PreferenceCategory標示一個分組,它會成為一組條目的頭目,而且它是不能獲取焦點的。其他的配置選項這裡就不啰嗦了。
3.2在代碼中加載XML文件
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_main);
addPreferencesFromResource(R.xml.item);
}
這樣兩步就可以構造一個設置界面了。
1.Evaluator自定義1)Evaluator介紹 上一節中的ValueAnimator的簡單實用,使用動畫的第一步都是: 調用ValueAn
Android運行環境一覽Android基於linux內核,面向移動終端的操作系統。主要包括以下幾個方面:Application Framework:這一層為應用開發者提
最近幫朋友做了一個動畫菜單,感覺有一定的實用價值,就在此給大家分享一下,先看看效果:實現思路:從圖中可以看出,這三個(或更多,需要自己再實現)菜單是圍繞著中心點旋轉的,旋
// 表示事件是否攔截, 返回false表示不攔截 @Override public boolean onInterceptTouchEvent(Motion