要實現分組列表這樣的效果:點擊ListView中的分組名稱,即展開此分組顯示其包含的項目。使用ExpandableList可以實現展開這樣的效果,如果對於列表中的每個可點擊的標題View需要更多的定製,而不是簡單的展開——例如點擊全選等,那麼可使用ListView嵌套GridView組合實現,Lis
2016-03-13
Android零散
ListView中嵌套GridView
要實現分組列表
這樣的效果:點擊ListView中的分組名稱,即展開此分組顯示其包含的項目。
使用ExpandableList可以實現展開這樣的效果,如果對於列表中的每個可點擊的標題View需要更多的定製,而不是簡單的展開——例如點擊全選等,那麼可使用ListView嵌套GridView組合實現,ListView中嵌套的GridView應該是完全展開的——內外層都滑動的交互體驗很彆扭,而且實現起來麻煩。而對應的GridView可以使用setVisibility為GONE、VISIBLE這樣的方式進行暫時的隱藏和打開。
為了使GridView在ListView中完全展開,那麼它的height應該是個具體的數值,這裡讓GridView始終保持其內容的高度即可:
public class UnfoldGridView extends GridView {
public UnfoldGridView(Context context) {
super(context);
}
public UnfoldGridView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public UnfoldGridView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int expandSpec = View.MeasureSpec.makeMeasureSpec(900000, View.MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
}
}
makeMeasureSpec中給一個很大的size,然後使用AtMost使其保持夠大即可。
setAdapter和addHeaderView、addFooterView
可以使用addHeaderView和addFooterView來為ListView添加首尾的個性視圖。兩者都可以多次調用來添加多個header和footer。
這兩個方法需要註意和setAdapter的調用順序:
When first introduced, this method could only be called before setting the adapter with setAdapter(ListAdapter). Starting with KITKAT, this method may be called at any time. If the ListView's adapter does not extend HeaderViewListAdapter, it will be wrapped with a supporting instance of WrapperListAdapter.
所以,為了保持相容性,無論是在API 19之前或之後,保持addHeaderView和addFooterView在setAdapter之前執行。addHeaderView如果在setAdapter之後執行,那麼在API 19之前的版本直接回報錯。而addFooterView在setAdapter之後執行的話,雖然不引起運行時錯誤——但是更迷惑的是——添加的視圖是看不到了。
這個是和API Level相關的一個問題,算是谷歌的坑吧。
ListView的getItemViewType
一個頁面中當要連續顯示多個不同的列表時,或者間隔性地顯示多種不同的View時,需要用到ListView的兩個方法:
@Override
public int getItemViewType(int position) {
return super.getItemViewType(position);
}
@Override
public int getViewTypeCount() {
return super.getViewTypeCount();
}
getItemViewType方法需要註意的是,其定義的ITEM_XX這樣的整數常量,其取值範圍需要在0~getViewTypeCount()-1
之間,下麵是getItemViewType返回值的描述:
An integer representing the type of View. Two views should share the same type if one can be converted to the other in getView. Note: Integers must be in the range 0 to getViewTypeCount - 1. IGNORE_ITEM_VIEW_TYPE can also be returned.
在區間外的viewType值,會引起運行時的indexoutofboundexception錯誤,這個是ListView自身的限制。
startActivityForResult和活動的launchMode
Activity_A啟動Activity_B後,需要Activity_B在完成操作後返回的一些數據:
//Activity_A中
private final int REQUEST_CODE_EDIT_ITEM = 2;
public void startPageBForEdit() {
Intent start = new Intent(this, EditActivity.class);
startActivityForResult(start, REQUEST_CODE_EDIT_ITEM);
}
//Activity_B中
public void setResult() {
Intent data = new Intent();
data.putExtra("itemDelete", true);
setResult(RESULT_OK, data);
}
在Activity_A中接收數據:
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_EDIT_ITEM && resultCode == RESULT_OK) {
//成功返回結果了
}
}
上面是典型的代碼片段,需要註意的是:對於對應的目標Activity啟動模式(在manifest中)指定為singleTask和singleInstance的Activity,使用startActivityForResult後,當前Activity的onActivityResult會立即執行,其resultCode為RESULT_CANCEL,並且data為null.
這個從啟動模式的設計上就可以理解,假設依次打開了A、B兩個Activity,其中A指定為singleTask,那麼在B中使用startActivityForResult打開A顯然是沒有意義的,因為B會從活動棧出棧,直接被destroy了。
所以,只有standard和singleTop這樣的啟動模式的Activity,使用startActivityForResult打開它們才可以有效的返回數據給上一個Activity,如果遇到這樣的需求,需要設計好多個Activity之間的跳轉關係。傳遞數據的方式是很多的。
Service的onStartCommand的返回值
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
onStartCommand中的flags和其返回值都和Service的啟動緊密相關。Service的定位就像是沒有View的Activity,應用長期後臺的情況下Service可能會暫時性被殺死(隨著進程被殺死)——之後又會再次被系統啟動。
每次調用startService來執行一些動作時,onStartCommand被執行,其intent參數代表分發過來的意圖描述數據(intnt就是一個攜帶有關“要做什麼”的信息對象)。
使用startService來啟動一個已經運行中的,正在啟動中的,重新啟動中的Service時,系統會在這些不同的Service狀態下對onStartCommand的調用產生一些差異。
//待續。。。