Android群英传知识点回顾——第四章:ListView常用优化技巧


知识点目录

  • 4.1 ListView常用优化技巧

    • 4.1.1 使用ViewHolder模式提高效率
    • 4.1.2 设置项目间分割线
    • 4.1.3 隐藏ListView的滚动条
    • 4.1.4 取消ListView的Item点击效果
    • 4.1.5 设置ListView需要显示在第几项
    • 4.1.6 动态修改ListView
    • 4.1.7 遍历ListView中的所有Item
    • 4.1.8 处理空ListView
    • 4.1.9 ListView滑动监听
  • 4.2 ListView常用拓展
    • 4.2.1 具有弹性的ListView
    • 4.2.2 自动显示、隐藏布局的ListView
    • 4.2.3 聊天ListView
    • 4.2.4 动态改变ListView布局

知识点回顾

4.1 ListView常用优化技巧

无知识点

4.1.1 使用ViewHolder模式提高效率

ViewHolder模式充分利用了ListView的视图缓存机制,避免了每次在调用getView()的时候都去通过findViewById()实例化控件。据测试,使用ViewHolder将提高50%以上的效率

public class ViewHolderAdapter extends BaseAdapter{private List<String> mData;private LayoutInflater mInflater;public ViewHolderAdapter(Context context, List<String> mData) {this.mData = mData;mInflater = LayoutInflater.from(context);}@Overridepublic int getCount() {return mData.size();}@Overridepublic Object getItem(int position) {return mData.get(position);}@Overridepublic long getItemId(int position) {return position;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {ViewHolder holder = null;//判断是否有缓存if (convertView == null) {holder = new ViewHolder();//通过LayoutInflater实例化布局convertView = mInflater.inflate(R.layout.viewholder_item, null);holder.img = (ImageView) convertView.findViewById(R.id.imageView);holder.title = (TextView) convertView.findViewById(R.id.textView);convertView.setTag(holder);} else {//通过tag找到缓存的布局holder = (ViewHolder) convertView.getTag();}//设置布局中控件要显示的视图holder.img.setBackgroundResource(R.mipmap.ic_launcher);holder.title.setText(mData.get(position));return convertView;}public final class ViewHolder {public ImageView img;public TextView title;}
}

4.1.2 设置项目间分割线

设置有颜色和有厚度的分割线

android:dividerHeight="10dp"
android:divider="@android:color/darker_gray"

设置无分割线

android:divider="@null"

4.1.3 隐藏ListView滚动条

android:scrollbars="none"

4.1.4 取消ListView的Item点击效果

android:listSelector="@android:color/transparent"

4.1.5 设置ListView需要显示在第几项

自然的滑动到第几项

listview.setSelection(N);

瞬间的滑动到第几项

listview.smoothScrollBy(distance,duration);
listview.smoothScrollByOffset(offset);
listview.smoothScrollToPosition(index);

4.1.6 动态修改ListView

当数据发生变化时,可以使用notifyDataSetChanged()来刷新ListView,但是必须保证使用这个方法传进Adapter的数据List是同一个List而不能是其他对象

mData.add("new");
mAdapter.notifyDataSetChanged();

4.1.7 遍历ListView中的所有Item

for (int i = 0; i < mListview.getChildCount();i++){View view = mListview.getChildAt(i);
}

4.1.8 处理空ListView

在开发中,会遇到ListView为空的时候,比如:购物车在没有添加物品时,需要显示该购物车没有任何物品的View,这个时候也就是ListView数据为空的时候,ListView为我们提供好了方法

在存在ListView的FrameLayout中,添加一个ImageView,作为空ListView时显示:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"><ListView
        android:id="@+id/listview"android:layout_width="match_parent"android:layout_height="match_parent" /><ImageView
        android:id="@+id/empty_view"android:layout_width="match_parent"android:layout_height="match_parent" /></FrameLayout>

在Activity中实现ListView空数据时显示布局

ListView listView = (ListView)findViewById(R.id.listview);
listview.setEmptyView(findViewById(R.id.tv_null));

4.1.9 ListView滑动监听

onTouchListener:

  • MotionEvent.ACTION_DOWN:触摸时操作
  • MotionEvent.ACTION_MOVE:移动时操作
  • MotionEvent.ACTION_UP:离开时操作
mListview.setOnTouchListener(new View.OnTouchListener() {@Overridepublic boolean onTouch(View view, MotionEvent motionEvent) {switch (motionEvent.getAction()) {case MotionEvent.ACTION_DOWN://触摸时操作break;case MotionEvent.ACTION_MOVE://移动时操作break;case MotionEvent.ACTION_UP://离开时操作break;}return false;}
});

onScrollListener和onScroll:

  • OnScrollListener.SCROLL_STATE_IDLE:滑动停止时
  • OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:正在滚动
  • OnScrollListener.SCROLL_STATE_FLING:手指抛动时
mListview.setOnScrollListener(new OnScrollListener() {@Overridepublic void onScrollStateChanged(AbsListView view, int scrollState) {switch (scrollState) {case OnScrollListener.SCROLL_STATE_IDLE://滚动停止break;case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL://正在滚动break;case OnScrollListener.SCROLL_STATE_FLING://手指抛动时break;}}@Overridepublic void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {//滚动的时候一直在调用}
});

onScroll参数:

  • firstVisibleItem:当前能看见的第一个Item的ID
  • visibleItemCount:当前能看见的Item总数
  • totalItemCount:整个ListView的Item总数

利用onScroll方法的参数可以判断滚动到最后一行:

if(firstVisibleItem + visibleItemCount == totalItemCount && totalItemCount>0){//滚动到最后一行
}

判断上滑和下滑:

if(firstVisibleItem > LastVisibleItemPosition){//上滑
}else if(firstVisibleItem < LastVisibleItemPosition){//下滑
}
LastVisibleItemPosition = firstVisibleItem;

ListView也给我们提供封装好的方法获得当前可视的Item位置等信息:

//获取可视区域内最后一个item的id
mListview.getLastVisiblePosition();
//获取可视区域内第一个item的id
mListview.getFirstVisiblePosition();

4.2 ListView常用拓展

4.2.1 具有弹性的ListView

  • 弹性的ListView……见经典代码回顾案例一

4.2.2 自动显示、隐藏布局的ListView

  • 自动显示、隐藏布局的ListView……见经典代码回顾案例二

4.2.3 聊天ListView

  • 聊天ListView……见经典代码回顾案例三

4.2.4 动态改变ListView布局

  • 动态改变ListView布局……见经典代码回顾案例四

经典代码回顾

案例一:弹性的ListView

这个案例测试了好久,跟书本源码一样效果还是没出来,具体原因还不清楚

public class TanXingListView extends ListView {private int mMaxOverDistance;public TanXingListView(Context context, AttributeSet attrs) {super(context, attrs);DisplayMetrics metrics = context.getResources().getDisplayMetrics();float density = metrics.density;mMaxOverDistance = (int) (density * mMaxOverDistance);}@Overrideprotected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, mMaxOverDistance, maxOverScrollY, isTouchEvent);}
}

案例二:自动显示、隐藏布局的ListView

由于书本上的案例比较模糊,实现了很久才做出效果,可能与作者的实现方法大同小异,不过条条道路通罗马

public class ShowAndHideListViewActivity extends AppCompatActivity {private int mTouchSlop;private ObjectAnimator mAnimator;private Toolbar mToolBar;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_show_and_hide_list_view);//添加头部mToolBar = (Toolbar) findViewById(R.id.toolbar);setSupportActionBar(mToolBar);//填充布局ListView mListView = (ListView) findViewById(R.id.lv);String[] str = new String[]{"1", "2", "3", "4", "5", "6", "7", "8", "9"};mListView.setAdapter(new ArrayAdapter<String>(this, R.layout.list_item, R.id.tv, str));//添加头布局,防止第一条数据被遮盖View header = new View(this);header.setLayoutParams(new AbsListView.LayoutParams(AbsListView.LayoutParams.MATCH_PARENT,(int) getResources().getDimension(android.support.v7.appcompat.R.dimen.abc_action_bar_default_height_material)));mListView.addHeaderView(header);//获得TouchSlopmTouchSlop = ViewConfiguration.get(this).getScaledTouchSlop();//设置监听mListView.setOnTouchListener(myTouchListener);}View.OnTouchListener myTouchListener = new View.OnTouchListener() {public boolean mShow;public int direction;public float mCurrentY;public float mFirstY;@Overridepublic boolean onTouch(View v, MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:mFirstY = event.getY();break;case MotionEvent.ACTION_MOVE:mCurrentY = event.getY();if (mCurrentY - mFirstY > mTouchSlop) {direction = 0;//down} else if (mFirstY - mCurrentY > mTouchSlop) {direction = 1;//up}if (direction == 1) {if (mShow) {toolBarAnim(0);//hidemShow = !mShow;}} else if (direction == 0) {if (!mShow) {toolBarAnim(1);//upmShow = !mShow;}}break;case MotionEvent.ACTION_UP:break;}return false;}};private void toolBarAnim(int flag) {if (mAnimator != null && mAnimator.isRunning()) {mAnimator.cancel();}if (flag == 0) {//up:hidemAnimator = ObjectAnimator.ofFloat(mToolBar, "translationY", -mToolBar.getHeight());} else {//down:showmAnimator = ObjectAnimator.ofFloat(mToolBar, "translationY", -mToolBar.getHeight(),0);}mAnimator.start();}}

布局文件的编写,记得将theme设置为NoActionBar

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"><android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"android:layout_width="match_parent"android:layout_height="?attr/actionBarSize"android:background="?attr/colorPrimary"/><ListView
        android:id="@+id/lv"android:layout_width="match_parent"android:layout_height="match_parent" /></RelativeLayout>

效果图


案例三:聊天ListView

实现这个效果比较重要的步骤就是左右布局的填充

左布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="horizontal"><ImageView
        android:id="@+id/left_icon"android:layout_width="50dp"android:layout_height="50dp" /><TextView
        android:id="@+id/tv_left"android:layout_width="match_parent"android:layout_height="wrap_content"android:padding="30dp" /></LinearLayout>

右布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="horizontal"><TextView
        android:id="@+id/tv_right"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_weight="1"android:padding="30dp" /><ImageView
        android:id="@+id/right_icon"android:layout_width="50dp"android:layout_height="50dp" />
</LinearLayout>

聊天的实体类

public class ChatItemListViewBean {private int type;private String text;private Bitmap icon;public int getType() {return type;}public void setType(int type) {this.type = type;}public String getText() {return text;}public void setText(String text) {this.text = text;}public Bitmap getIcon() {return icon;}public void setIcon(Bitmap icon) {this.icon = icon;}
}

比较关键的就是Adapter的getItemViewType()方法和getViewTypeCount()方法

public class ChatListViewAdapter extends BaseAdapter {private List<ChatItemListViewBean> mData;private LayoutInflater mInflater;public ChatListViewAdapter(Context context, List<ChatItemListViewBean> mData) {this.mData = mData;mInflater = LayoutInflater.from(context);}@Overridepublic int getCount() {return mData.size();}@Overridepublic Object getItem(int position) {return mData.get(position);}@Overridepublic long getItemId(int position) {return position;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {ViewHolder viewHolder;if (convertView == null) {if (getItemViewType(position) == 0) {viewHolder = new ViewHolder();convertView = mInflater.inflate(R.layout.left_item, null);viewHolder.icon = (ImageView) convertView.findViewById(R.id.left_icon);viewHolder.text = (TextView) convertView.findViewById(R.id.tv_left);} else {viewHolder = new ViewHolder();convertView = mInflater.inflate(R.layout.right_item, null);viewHolder.icon = (ImageView) convertView.findViewById(R.id.right_icon);viewHolder.text = (TextView) convertView.findViewById(R.id.tv_right);}convertView.setTag(viewHolder);} else {viewHolder = (ViewHolder) convertView.getTag();}viewHolder.icon.setImageBitmap(mData.get(position).getIcon());viewHolder.text.setText(mData.get(position).getText());return convertView;}@Overridepublic int getItemViewType(int position) {ChatItemListViewBean bean = mData.get(position);return bean.getType();}@Overridepublic int getViewTypeCount() {return 2;}public final class ViewHolder {public ImageView icon;public TextView text;}
}

在主Activity中实现我们的效果

public class ChatListViewActivity extends AppCompatActivity {private ListView mListView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_chat_list_view);mListView = (ListView) findViewById(R.id.lv_chat);ChatItemListViewBean bean1 = new ChatItemListViewBean();bean1.setType(0);bean1.setIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher));bean1.setText("hello how are you?");ChatItemListViewBean bean2 = new ChatItemListViewBean();bean2.setType(1);bean2.setIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher));bean2.setText("find thank you ,and you?");List<ChatItemListViewBean> data = new ArrayList<>();data.add(bean1);data.add(bean2);ChatListViewAdapter adapter = new ChatListViewAdapter(this, data);mListView.setAdapter(adapter);}
}

效果图


案例四:动态改变ListView布局

public class DongTaiListViewActivity extends AppCompatActivity {private DongTaiListViewAdapter adapter;private List<String> list;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_dong_tai_list_view);ListView listView = (ListView) findViewById(R.id.lv_dongtai);list = new ArrayList<>();list.add("item1");list.add("item2");list.add("item3");list.add("item4");adapter = new DongTaiListViewAdapter(this, list);listView.setAdapter(adapter);listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> parent, View view, int position, long id) {adapter.setCurrentItem(position);adapter.notifyDataSetChanged();}});}
}
public class DongTaiListViewAdapter extends BaseAdapter {private List<String> list;private Context mContext;private int mCurrentItem=0;public DongTaiListViewAdapter(Context context, List<String> list) {this.list = list;this.mContext = context;}@Overridepublic int getCount() {return list.size();}@Overridepublic Object getItem(int position) {return list.get(position);}@Overridepublic long getItemId(int position) {return position;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {LinearLayout layout = new LinearLayout(mContext);layout.setOrientation(LinearLayout.VERTICAL);if (mCurrentItem == position) {layout.addView(addFocusView(position));} else {layout.addView(addNormalView(position));}return layout;}private View addFocusView(int i) {ImageView iv = new ImageView(mContext);iv.setImageResource(R.mipmap.ic_launcher);return iv;}private View addNormalView(int i) {LinearLayout layout = new LinearLayout(mContext);layout.setOrientation(LinearLayout.HORIZONTAL);ImageView iv = new ImageView(mContext);iv.setImageResource(R.mipmap.ic_launcher);layout.addView(iv, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT));TextView tv = new TextView(mContext);tv.setText(list.get(i));layout.addView(tv, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT));layout.setGravity(Gravity.CENTER);return layout;}public void setCurrentItem(int position) {mCurrentItem = position;}
}

效果图

经典回顾源码下载

github:https://github.com/CSDNHensen/QunYingZhuang

Android群英传知识点回顾——第四章:ListView常用优化技巧相关推荐

  1. Android群英传知识点回顾——第十章:Android性能优化

    Android群英传知识点回顾--第十章:Android性能优化 知识点目录 10.1 布局优化 10.1.1 Android UI渲染机制 10.1.2 避免Overdraw 10.1.3 优化布局 ...

  2. Android群英传笔记——第十二章:Android5.X 新特性详解,Material Design UI的新体验

    Android群英传笔记--第十二章:Android5.X 新特性详解,Material Design UI的新体验 第十一章为什么不写,因为我很早之前就已经写过了,有需要的可以去看 Android高 ...

  3. Android群英传神兵利器读书笔记——第一章:程序员小窝——搭建高效的开发环境

    Android群英传神兵利器读书笔记--第一章:程序员小窝--搭建高效的开发环境 目录 1.1 搭建高效的开发环境之操作系统 1.2 搭建开发环境之高效配置 基本环境配置 基本开发工具 1.3 搭建程 ...

  4. Android群英传帝落篇——程序人生,路漫漫其修远兮,吾将上下而求索!

    Android群英传帝落篇--程序人生,路漫漫其修远兮,吾将上下而求索! 当写这篇博客的时候,自2016-02-22到现在5.2号,一晃眼,也㓟两个多月就过去了,我才将这本书看完,虽然写笔记花了很大的 ...

  5. Android群英传笔记——第四章:ListView使用技巧

    Android群英传笔记--第四章:ListView使用技巧 近期也是比較迷茫.可是有一点点还是要坚持的,就是学习了.近期离职了,今天也是继续温习第四章ListView,也拖了事实上也挺久的了,lis ...

  6. Android群英传笔记——第三章:Android控件架构与自定义控件讲解

    Android群英传笔记--第三章:Android控件架构与自定义控件讲解 真的很久没有更新博客了,三四天了吧,搬家干嘛的,心累,事件又很紧,抽时间把第三章大致的看完了,当然,我还是有一点View的基 ...

  7. Android群英传笔记——第九章:Android系统信息和安全机制

    Android群英传笔记--第九章:Android系统信息和安全机制 本书也正式的进入尾声了,在android的世界了,不同的软件,硬件信息就像一个国家的经济水平,军事水平,不同的配置参数,代表着一个 ...

  8. Android群英传神兵利器读书笔记——第三章:Android Studio奇技淫巧

    Android群英传神兵利器读书笔记--第三章:Android Studio奇技淫巧 这篇文章篇幅较长,可以使用版权声明下面的目录,找到感兴趣的进行阅读 目录 3.1 Android Studio使用 ...

  9. Android群英传笔记——第二章:Android开发工具新接触

    Android群英传笔记--第二章:Android开发工具新接触 其实这一章并没什么可讲的,前面的安装Android studio的我们可以直接跳过,如果有兴趣的,可以去看看Google主推-Andr ...

最新文章

  1. 论文笔记之:Action-Decision Networks for Visual Tracking with Deep Reinforcement Learning
  2. PHP语言 -- 基础
  3. 一个简单的HTTP通讯的例子,使用了CInternetSession,CHttpConnection,CHttpFile三个类
  4. 版本控制入门-----搬进Github
  5. STM32 - 定时器的设定 - 基础- 02 - Capture/compare channels 和相关设置寄存器 - 和STM32缩写词条解释
  6. 数据标准化处理方法_机器学习系列-数据预处理-数据标准化(归一化)-理论
  7. SLAM GMapping(2)传感器
  8. 有人滥用 GitHub Actions在 GitHub 服务器挖掘密币,且正在蔓延
  9. @interface自定义注解
  10. dojo省份地市级联之省份封装类(一)
  11. 购买namesilo域名可以用微信支付了
  12. 教你简单制作视频滚动字幕
  13. 苹果开发者账号申请流程
  14. 武汉江夏区计算机大专,武汉江夏职业技术学校2021年招生简章
  15. 老男孩教育python全栈第九期视频
  16. 超长(超过70字)短信发送
  17. 2022081班李亚楠20220905
  18. 前端学习路线之基础篇-李南江
  19. 回溯法之递归回溯和迭代回溯
  20. 梅尔频谱图与音频相互转化

热门文章

  1. win7环境下如何关闭IIS7服务
  2. 快来智影:微电影的特征有哪些?
  3. 一个小巧好用的windows端口映射管理控制工具
  4. 基于RPGMakerMV的JavaScript基础-1
  5. 用余弦相似度破解字体反爬
  6. JS数组正数转为负数
  7. Android多线程(Handler篇)
  8. qos 流控功能_01-QoS通道限速功能典型配置举例
  9. go语言 第三方包安装方法_Adobe AE 2019 软件下载安装包教程(附下载方法)
  10. Windows下用texlive+vscode报错Recipe terminated with fatal error: spawn xelatex ENOENT