摘要:方法根據子項所處的位置判斷具體類型并返回。調用方法解除子項與之間的關聯。自定義適配器適配器繼承自,并將泛型指定為內部類。使用支持多種布局方式借助能夠靈活地將列表控件放入不同的容器。
ListView 和 RecyclerView
最常用和最難用的控件
由于手機屏幕空間有限,無法顯示全部內容。當有大量數據需要展示的時候,借助列表控件。通過手指上下滑動,使得屏幕內外的數據不斷進出。
最基本的列表工作模式需要列表控件、數據源,列表控件能夠進行交互和展示數據。但是列表控件不與數據源直接打交道,Adapter 接口充當橋梁,關聯數據源與列表控件,增強可擴展性,適配不同數據類型數據源。例如:ArrayAdapter 數組、CursorAdapter 游標。
數據源可能來自:
靜態數據
網絡數據
數據庫
ListViewListView extends AdapterView extends ViewGroup.
Adapter 管理數據源
AdapterView 展示數據并處理交互
數據無法直接傳遞給 ListView,需要借助 setAdapter() 適配器來完成。例如 ArrayAdapter<> 泛型指定要適配的數據類型。
ListView listView = (ListView) findViewById(R.id.listview); listView.setAdapter(adapter);自定義適配器
適配數據源并重寫一組父類方法:
構造函數:例如 ArrayAdapter 依次傳入當前上下文、ListView 子項布局 id、數據源。
ArrayAdapter(Context context, int resource, int textViewResourceId, Listobjects)
getView() 方法:用于每個子項(單行)進入屏幕可視區域時候調用,根據數據源繪制子項布局。
程序示例:
public class MySimpleArrayAdapter extends ArrayAdapter{ private final Context context; private final String[] values; public MySimpleArrayAdapter(Context context, String[] values) { super(context, R.layout.rowlayout, values); this.context = context; this.values = values; } @Override public View getView(int position, View convertView, ViewGroup parent) { LayoutInflater inflater = (LayoutInflater) context .getSystemService(Context.LAYOUT_INFLATER_SERVICE); View rowView = inflater.inflate(R.layout.rowlayout, parent, false); TextView textView = (TextView) rowView.findViewById(R.id.label); ImageView imageView = (ImageView) rowView.findViewById(R.id.icon); textView.setText(values[position]); // Change the icon for Windows and iPhone String s = values[position]; if (s.startsWith("Windows7") || s.startsWith("iPhone") || s.startsWith("Solaris")) { imageView.setImageResource(R.drawable.no); } else { imageView.setImageResource(R.drawable.ok); } return rowView; } }
其他常用方法:
getCount() 方法
返回適配器表示的數據源中一共有多少項數據。
notifyDataSetChanged() 方法
數據源的數據發生變化,通知 ListView 更新數據重新繪制視圖。
提升 ListView 運行效率避免在 Adapter 的 getView() 方法中重新加載布局(子項布局)
public abstract View getView(int position, View convertView, ViewGroup parent)
convertView 用于將加載好的布局進行緩存,根據 convertView 是否為空,判斷能否重用布局,減少 LayoutInflater.inflate() 調用次數從而提升性能。
減少 findViewById() 方法獲取控件實例的調用次數
通過內部類 ViewHolder 對控件實例進行緩存,調用 View 的 setTag() 方法,將 ViewHolder 對象存儲在 View 中。
程序示例:
public class MyPerformanceArrayAdapter extends ArrayAdapter存在多種類型的子項布局的場景{ private final Activity context; private final String[] names; static class ViewHolder { public TextView text; public ImageView image; } public MyPerformanceArrayAdapter(Activity context, String[] names) { super(context, R.layout.rowlayout, names); this.context = context; this.names = names; } @Override public View getView(int position, View convertView, ViewGroup parent) { View rowView = convertView; // reuse views if (rowView == null) { LayoutInflater inflater = context.getLayoutInflater(); rowView = inflater.inflate(R.layout.rowlayout, null); // configure view holder ViewHolder viewHolder = new ViewHolder(); viewHolder.text = (TextView) rowView.findViewById(R.id.TextView01); viewHolder.image = (ImageView) rowView .findViewById(R.id.ImageView01); rowView.setTag(viewHolder); } // fill data ViewHolder holder = (ViewHolder) rowView.getTag(); String s = names[position]; holder.text.setText(s); if (s.startsWith("Windows7") || s.startsWith("iPhone") || s.startsWith("Solaris")) { holder.image.setImageResource(R.drawable.no); } else { holder.image.setImageResource(R.drawable.ok); } return rowView; } }
基本實現方式:
定義視圖類型常量
重寫 getViewTypeCount() 方法和 getItemViewType(int position) 方法
重寫 getView() 方法
getViewTypeCount() 方法
返回一共有多少個不同的視圖類型(布局),這些視圖將由 getView() 方法創建。
getItemViewType(int position) 方法
根據子項所處的位置判斷具體類型并返回。
程序示例:
@Override public int getViewTypeCount() { return 2; } @Override public int getItemViewType(int position) { return (contactList.get(position).getContactType() == ContactType.CONTACT_WITH_IMAGE) ? 0 : 1; } @Override public View getView(int position, View convertView, ViewGroup parent) { View v = convertView; int type = getItemViewType(position); if (v == null) { // Inflate the layout according to the view type LayoutInflater inflater = (LayoutInflater) ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE); if (type == 0) { // Inflate the layout with image v = inflater.inflate(R.layout.image_contact_layout, parent, false); } else { v = inflater.inflate(R.layout.simple_contact_layout, parent, false); } } // fill data Contact c = contactList.get(position); TextView surname = (TextView) v.findViewById(R.id.surname); TextView name = (TextView) v.findViewById(R.id.name); TextView email = (TextView) v.findViewById(R.id.email); if (type == 0) { ImageView img = (ImageView) v.findViewById(R.id.img); img.setImageResource(c.imageId); } surname.setText(c.surname); name.setText(c.name); email.setText(c.email); return v; }ListView 的 RecycleBin 機制
ListView 即使加載成百上千條數據,依然不會發生 OOM 的原因——RecycleBin 機制。
RecycleBin 類中存在兩個重要的數組:
mActiveViews 屏幕上可見的 View
mScrapViews 屏幕外不可見的 View
當 ListView 子項 View 進入屏幕可視區域時候,從 RecycleBin 的 mScrapViews 獲取 View 作為 convertView 參數傳遞給 Adapter 的 getView() 方法。
ListView 有如 View 一般執行視圖繪制流程 onMeasure()、onLayout()、onDraw()。在 onLayout() 方法中會調用一個關鍵方法 layoutChildren(),該方法由 ListView 具體實現進行子元素的布局,同時完成 ListView 對子項 View 的添加和刪除操作。
layoutChildren() 方法主要邏輯:
若 Adapter 中的數據集發生變化,則將 ListView 中的所有子項 View 放到 RecycleBin 中的 mScrapViews 廢棄 View 集合。
若 Adapter 中的數據集無變化,則將 ListView 中的所有子項 View 放到 RecycleBin 中的 mActiveViews 激活 View 集合。
調用 detachAllViewsFromParent() 方法解除子項 View 與 ListView 之間的關聯。
重新將子項 View 添加到 ListView 中。根據 mLayoutMode 判斷如何進行添加,fillDown() 方法將子 View 從指定的 position 自上而下填充 ListView,fillUp() 則相反自下而上進行填充。
RecyclerView 自定義適配器適配器繼承自 RecyclerView.Adapter<>,并將泛型指定為內部類 Adapter.ViewHolder。
重寫一組父類方法:
onCreateViewHolder()
加載子項布局(LayoutInflater inflate()),創建 ViewHolder 實例。
onBindViewHolder()
用于每個子項(單行)進入屏幕可視區域時候調用,根據數據源位置繪制子項布局。
getItemCount()
返回數據源的長度
程序示例:
public class MyAdapter extends RecyclerView.AdapterRecyclerView vs ListView{ private String[] mDataset; // Provide a reference to the views for each data item // Complex data items may need more than one view per item, and // you provide access to all the views for a data item in a view holder public static class MyViewHolder extends RecyclerView.ViewHolder { // each data item is just a string in this case public TextView mTextView; public MyViewHolder(TextView v) { super(v); mTextView = v; } } // Provide a suitable constructor (depends on the kind of dataset) public MyAdapter(String[] myDataset) { mDataset = myDataset; } // Create new views (invoked by the layout manager) @Override public MyAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { // create a new view TextView v = (TextView) LayoutInflater.from(parent.getContext()) .inflate(R.layout.my_text_view, parent, false); ... MyViewHolder vh = new MyViewHolder(v); return vh; } // Replace the contents of a view (invoked by the layout manager) @Override public void onBindViewHolder(MyViewHolder holder, int position) { // - get element from your dataset at this position // - replace the contents of the view with that element holder.mTextView.setText(mDataset[position]); } // Return the size of your dataset (invoked by the layout manager) @Override public int getItemCount() { return mDataset.length; } }
固有的 ViewHolder 模式規范
RecyclerView.Adapter 默認采用 ViewHolder 模式,減少 findViewById() 方法獲取控件實例的調用次數。
使用 LayoutManager 支持多種布局方式
RecyclerView 借助 LayoutManager 能夠靈活地將列表控件放入不同的容器(LinearLayout, GridLayout)。
ListView 布局只能實現縱向排列,而 RecyclerView 將排列工作 setLayoutManager() 交給 LayoutManager 布局排列接口,因此可以定制出不同排列方式(橫向、瀑布流布局)。
通知 Adapter 的數據變化更加靈活
不僅 notifyDataSetChange() 方法,RecyclerView 可以使用 notifyItemRangeChanged() 等方法實現局部更新數據并重繪視圖。
子項視圖的動畫效果更容易實現
RecyclerView.ItemAnimator
RecyclerView.ItemDecoration
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/72020.html
摘要:四種狀態運行狀態暫停狀態停止狀態銷毀狀態運行狀態處于返回棧的棧頂位置,正在運行與用戶發生著交互,系統不愿回收此種狀態的。和都是為了解決重復創建問題,的作用域是棧頂,的作用域是整個返回棧。 Context Android 系統組件不同于普通類對象,能夠直接創建實例,需要各自的上下文環境——Context。 Context 上下文環境確保 Android 系統組件(Activity、Se...
摘要:層面中可以通過方法攔截事件傳遞,返回代表同一事件列不再向下傳遞給子,返回代表事件繼續傳遞,默認返回。同時注冊兩者事件傳遞順序,方法將會先于方法執行,并且方法可能執行多次事件。如此反復執行初始化布局繪制過程容易造成性能問題。 View 和 ViewGroup View 是 Android 中最基本的 UI 組件,在屏幕上繪制一塊矩形區域。 ViewGroup 是一種特殊的 View,它...
閱讀 2570·2021-09-06 15:02
閱讀 3199·2021-09-02 10:18
閱讀 2820·2019-08-30 15:44
閱讀 684·2019-08-30 15:43
閱讀 1947·2019-08-30 14:08
閱讀 2757·2019-08-30 13:16
閱讀 1396·2019-08-26 13:52
閱讀 930·2019-08-26 12:21