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


近期也是比較迷茫。可是有一点点还是要坚持的,就是学习了。近期离职了,今天也是继续温习第四章ListView,也拖了事实上也挺久的了,listview可谓是老牌大将了,非常多的应用场景都要使用它,他也是我们用得最多的控件之中的一个了,尽管如今出来了一个RecyclerView,可是ListView的地位一时半会儿还是撼动不了的。这就促使我们更加应该去把他掌握了

一.Listview经常使用优化技巧

我们一步步来把ListView学习好

1.使用ViewHolder模式提高效率

ViewHolder模式是提高ListView效率的一个非常重要的方法,他充分利用了ListView的视图缓存机制,避免每次调用getView()的时候去通过findViewById()实例化控件,有人測试结果效率要高百分之五十。我们仅仅须要在自己定义的Adapter里面定义一个内部类ViewHolder即可,代码例如以下:

    public final class ViewHolder{public ImageView img;public TextView tv;}

然后我们在getView的时候复用即可了,我们来看一下完整的Adapter

package com.lgl.listviewdemo;import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;import java.util.List;/*** 自己定义Adapter* Created by LGL on 2016/3/10.*/
public class MyAdapter extends BaseAdapter {private List<String> mData;private LayoutInflater mInflater;//构造方法public MyAdapter(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 viewHolder = null;//推断是否有缓存if (convertView == null) {viewHolder = new ViewHolder();//通过LayoutInflater去实例化布局convertView = mInflater.inflate(R.layout.item, null);viewHolder.img = (ImageView) convertView.findViewById(R.id.img);viewHolder.tv = (TextView) convertView.findViewById(R.id.tv);convertView.setTag(viewHolder);} else {//通过TAG找到缓存的布局viewHolder = (ViewHolder) convertView.getTag();}//设置布局中要显示的东西‘viewHolder.tv.setText(mData.get(position));return convertView;}public final class ViewHolder {public ImageView img;public TextView tv;}
}

假设我们要使用的话。我们就能够直接使用adapter了

package com.lgl.listviewdemo;import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ListView;import java.util.ArrayList;
import java.util.List;public class MainActivity extends AppCompatActivity {private ListView listview;private MyAdapter myAdapter;private List<String> list = new ArrayList<String>();@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);listview = (ListView) findViewById(R.id.listview);for (int i = 0; i < 20; i++) {list.add("第" + i + "张");}myAdapter = new MyAdapter(this, list);listview.setAdapter(myAdapter);}
}

我们执行一下

OK我们继续

2.设置项目间切割栏、

ListView在各个项目之中,能够通过切割线进行区分的,系统也提供了两个属性来设置item间的颜色和高度

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

我们来执行一下

可是假设你是须要去掉这个切割线的话,事实上也好办

 android:divider="@null"

看图

3.隐藏listview的滚动栏

这个看需求吧,尽管说实话,我是非常不喜欢这个滚动栏的,可是不可否认他还是须要用来显示运行进度的。去掉的方法也非常easy,加一条属性就能够了

 android:scrollbars="none"

4.取消ListView的item点击效果

先来看一下点击的效果。是有一点点灰色的点击效果,我们把他给去掉,加一个点击反馈颜色透明的属性就能够了

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

这里;你也能够直接填#00000000

5.设置ListView须要显示在第几项

ListView默认是从上到下的,我们能够觉得的去设置他要显示的item

listview.setSelection(15);

这个就有点相似于平滑的效果了

listview.smoothScrollBy(1,15);
listview.smoothScrollByOffset(15);
listview.smoothScrollToPosition(15);

6.动态改动ListView

这个就非经常常使用了,我们在某一个场景的时候须要对listview添加数据,我们应该怎么样做尼?我们在xml里新添加一个button

<?

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="vertical"> <ListView android:id="@+id/listview" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" /> <Button android:id="@+id/add_data" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="加入数据" /> </LinearLayout>

然后我们的点击事件就能够这样写了

 @Overridepublic void onClick(View view) {switch (view.getId()) {case R.id.add_data:list.add("我是新添加的数据");//通知刷新myAdapter.notifyDataSetChanged();break;}}

来看看效果吧

7.遍历全部的item

ListView作为一个ViewGroup,他提供了非常多操纵子View的方法。最经常使用的就是getChilaAt()来获取View了

for (int j = 0; j < listview.getChildCount();j++){View v = listview.getChildAt(12);}

8.处理空ListView

有时候我们获取一条数据的时候,他须要显示列表,有的可能是空,这种话,我们就得处理一下了。我们在布局中新加一个textview

 <TextViewandroid:id="@+id/tv_null"android:text="没有数据"android:layout_width="match_parent"android:layout_height="wrap_content" />

仅仅要在代码中设置假设是空数据的话就载入这个布局就能够

 listview.setEmptyView(findViewById(R.id.tv_null));

这种话,假设ListView为空数据的时候就会设置这句话了

9.ListView滑动监听

ListView的滑动监听可是ListView的非常重要的一个技巧,非常多应用场景须要重写ListView的事实上都要在滑动监听上下非常大的功夫,通过推断滑动事件来处理不同的逻辑这是非常有必要的,开发人员通常还须要GestureDetector手势识别。VelocityTracker滑动速度检測来辅助监听,这里介绍两种监听方法,一种是OnTouchListener,还有一中是OnScrollListener

-1. OnTouchListener

OnTouchListener是View的监听事件。包含ACTION_DOWN,UP,MOVE等,通过坐标的改变老发生不同的逻辑

listview.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 true;}});

-2 OnScrollListener

OnScrollListener是AbsListView的监听事件,他封装了非常多ListView的相关信息,所以用起来非常灵活

 listview.setOnScrollListener(new AbsListView.OnScrollListener() {@Overridepublic void onScrollStateChanged(AbsListView absListView, int i) {switch (i) {case AbsListView.OnScrollListener.SCROLL_STATE_IDLE://滚动停止break;case AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL://正在滚动break;case AbsListView.OnScrollListener.SCROLL_STATE_FLING://手指抛动时,即手指用力滑动的时候break;}}@Overridepublic void onScroll(AbsListView absListView, int i, int i1, int i2) {//滚动的时候一直在调用}});

OnScrollListener中有两个回调方法onScrollStateChanged()和onScroll。我们先来看看onScrollStateChanged吧,这种方法的參数i来决定其回调的次数,有三种模式

  • OnScrollListener.SCROLL_STATE_IDLE://滚动停止
  • OnScrollListener.SCROLL_STATE_TOUCH_SCROLL://正在滚动
  • OnScrollListener.SCROLL_STATE_FLING://手指抛动时,即手指用力滑动的时候

当用户没有做手指抛动的动作时,这种方法仅仅会调用2次。否则就调用三次,区别就在于手指抛动的这个状态。通常情况下,我们会在这种方法中通过不同的状态来标注一些FLAG,我们来看下onScrill()这种方法

                /*** firstVisibleItem:表示在现时屏幕第一个ListItem(部分显示的ListItem也算)在整个ListView的位置(下标从0開始)* visibleItemCount:表示在现时屏幕能够见到的ListItem(部分显示的ListItem也算)总数* totalItemCount:表示ListView的ListItem总数* listView.getFirstVisiblePosition()表示在现时屏幕第一个ListItem(第一个ListItem部分显示也算)在整个ListView的位置(下标从0開始)* listView.getLastVisiblePosition()表示在现时屏幕最后一个ListItem(最后ListItem要全然显示出来才算)在整个ListView的位置(下标从0開始)*/

这里有一点要注意的是。当前能看到的item数也包含没有显示全然的。这样我们就又能Get到一些技巧了

 if(i+i1 == i2 &&i2>0){//滚动到最后一行}

再比方监听滑动放心

 int i3 = i;if(i>i3){//上滑}else if(i<i3){//下滑}

通过一个成员变量来记住上一个可视item就知道滑动的方法了,当然。ListView还提供了非常多获取位置信息的方法

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

二.ListView经常使用扩展

尽管ListView应用非常广泛,可是毕竟是一个显示的东西。扩展性肯定要的,我们接下来说几种常见的扩展

1.具有弹性的ListView

Android默认滑动到顶部或者底部仅仅会有一个阴影,而在5.X之后改变成了半圆的阴影

而在IOS上,列表是具有弹性的,即滚动到顶部或者底部,会再滚动一段距离,这种设计感觉还是挺友好的,我们也来模仿一下

我们在查看ListView的源代码的时候会发现一个控制滑动到边缘的处理方法

@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, maxOverScrollX, maxOverScrollY, isTouchEvent);}

我們能够看到这样一个參数maxOverScrollY。就是他负责控制滑动的个数的,默认是0,我们重写ListView

package com.lgl.listviewdemo;import android.content.Context;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.widget.ListView;/*** 弹性ListView* Created by lgl on 16/3/20.*/
public class ListViewScroll extends ListView {private int mMaxOverdistance ;public ListViewScroll(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);}
}

2.自己主动显示,隐藏布局的ListView

相信看过Google最新的应用,或者使用了MD风格的应用都知道,列表滑动的时候actionbar能够依据状态显示或者隐藏,

这一段作者写的非常乱

这要是讲一下大概,须要使用ToolsBar,然后一个listview

<android.support.v7.widget.Toolbarandroid:id="@+id/toolbar"android:layout_width="match_parent"android:layout_height="?attr/actionBarSize"android:background="?attr/colorPrimary" />

不具体记了。在我讲MD风格的时候会具体介绍的

3.聊天ListView

相信大家都看过聊天的ListView吧,这个主要是adapter做手脚,事实上设计者早就想到了这种方法,所以在继承BaseAdapter的时候还须要重写两个方法

 @Overridepublic int getItemViewType(int position) {return super.getItemViewType(position);}@Overridepublic int getViewTypeCount() {return super.getViewTypeCount();}

我们这里大致的了解一个思路。我们能够设置一个tag来识别不同的方向。先写两个item,各自是左边的和右边的布局,然后,我们再来写个实体类Bean

Bean

package com.lgl.listviewdemo;import android.graphics.Bitmap;/*** 实体类* Created by lgl on 16/3/20.*/
public class Bean {private int type;private String text;private Bitmap icon;public Bean() {}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了

SpeakAdapter

package com.lgl.listviewdemo;import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;import java.util.List;/*** Created by lgl on 16/3/20.*/
public class SpeakAdapter extends BaseAdapter{private List<Bean>mData;private LayoutInflater mInflater;//构造方法public SpeakAdapter(Context context,List<Bean>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) {Bean bean = mData.get(position);return bean.getType();}@Overridepublic int getViewTypeCount() {return 2;}public final class  ViewHolder{public ImageView icon;public TextView text;}
}

这里大致的思路也就是在getview中区分。如今我们的SpeakListViewActivity中就能够这样写

package com.lgl.listviewdemo;import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.PersistableBundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.ListView;import java.util.ArrayList;
import java.util.List;/*** 聊天ListView* Created by lgl on 16/3/20.*/
public class SpeakListViewActivity extends AppCompatActivity {private ListView mListview;@Overridepublic void onCreate(Bundle savedInstanceState, PersistableBundle persistentState) {super.onCreate(savedInstanceState, persistentState);setContentView(R.layout.activity_speak);mListview = (ListView) findViewById(R.id.listview);Bean bean1 = new Bean();bean1.setType(0);bean1.setIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher));bean1.setText("我是左边");Bean bean2 = new Bean();bean2.setType(1);bean2.setIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher));bean2.setText("我是右边");List<Bean>data = new ArrayList<Bean>();data.add(bean1);data.add(bean2);SpeakAdapter adapter = new SpeakAdapter(this,data);mListview.setAdapter(adapter);}
}

把数据装载好了即可,这里仅仅是演示

4.动态改变ListView的布局

都是什么鬼,写的不是非常具体呀

通常情况下,假设要动态的改变点击item的布局来达到Focus的效果,一般有两种方法。一是将两个布局写在一起。通过布局的显示隐藏来达到切换布局的效果,第二种则是在getView的时候,通过推断来选择不同的载入不同的布局。两种方法都有利弊,关键还是要看看应用场景,所以我们还是得在Adapter下手脚

 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;}

在这两个方法中就能够依据item的不同位置显示不同的信息了。以下我们回到adapter中

@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 convertView;} 

这样就能够自由选择了
那我们如今就来监听他的点击逻辑吧

 listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> parent, View view, int position, long id) {myAdapter.setCurrentItem(position);myAdapter.notifyDataSetChanged();}});

OK。搞定。实在的说吧,这一章不止这点内容,只是本书非常多都一笔带过了。当然,的确进阶书不须要写非常具体,可是…额….我们接着看下一章吧!

笔记下载链接:http://pan.baidu.com/s/1c0U7k2W password:9v0g

Demo下载地址:http://download.csdn.net/detail/qq_26787115/9467353

转载于:https://www.cnblogs.com/wzzkaifa/p/7351293.html

Android群英传笔记——第四章:ListView使用技巧相关推荐

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

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

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

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

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

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

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

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

  5. Android群英传笔记——摘要,概述,新的出发点,温故而知新,能够为师矣!

    Android群英传笔记--摘要.概述,新的出发点,温故而知新.能够为师矣! 当工作的越久,就越感到力不从心了,基础和理解才是最重要的,所以买了两本书,医生的<Android群英传>和主席 ...

  6. Android群英传笔记——第十章:Android性能优化

    Android群英传笔记--第十章:Android性能优化 随着Android应用增多,功能越来越复杂,布局也越来越丰富了,而这些也成为了阻碍一个应用流畅运行,因此,对复杂的功能进行性能优化是创造高质 ...

  7. android 群英传笔记,Android 群英传读书笔记1

    Android中每个控件都会在界面上占据一块矩形的区域,在Android中控件被分为两种,①VIew ②ViewGroup  ViewGroup可以包含多个View 或者Viewgroup 这样在界面 ...

  8. Android群英传笔记-Android系统安全与安全机制

    Android系统安全与安全机制 系统消息 Android系统消息获取 android.os.Build SystemProperty Android apk 应用信息获取 PackageManage ...

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

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

最新文章

  1. PHPStorm+XDebug进行调试
  2. python 矩形补正方形
  3. 如何把很多照片拼成一张照片_一张25GB的照片,到底比普通照片强在哪儿?
  4. 如何找出nginx配置文件的所在位置?
  5. 【Pytorch神经网络基础理论篇】 01 从零开始介绍深度学习算法和代码实现
  6. dedeCMS版权信息、备案号的调用代码 - 代码大全
  7. Arcgis创建SDE_Geometry、SDO_Geometry的区别【转】
  8. 如何查询SID及根据SID反查对应的账户
  9. 《Excel VBA实战技巧精粹》终于登场了
  10. nginx学习:搭建静态资源服务器
  11. Excel表格中选择性粘贴如何粘贴为数值
  12. Robotframework(三)常用API介绍
  13. java扫雷初级代码_运行在Eclipse环境下的java扫雷游戏的初级代码是什么?
  14. 什么是云计算和大数据?他们之间的区别是什么?
  15. 2020 年中科院计算所“计算未来”全国大学生暑期班 网络数据科学与技术重点实验室 机试试题
  16. POI读取word里面的表格并处理数据
  17. 10个超赞的HTML5框架加快Web开发
  18. python画蜡烛图_Python量化交易-绘制蜡烛图 !这个图不像你的钱哦!
  19. linux mkdir命令用法,linux中的mkdir命令的详细解释
  20. 基于STM32L431设计的云端绿化管理系统(ESP8266+腾讯物联网云平台)

热门文章

  1. python手机版下载官方-Python
  2. python安装在什么系统下最好-python开发环境哪个好用?如何搭建?
  3. python天天学怎么样-python练习:好好学习,天天向上
  4. python 爬虫实例 电影-Python爬虫教程-17-ajax爬取实例(豆瓣电影)
  5. python使用lxml及request爬取-python用lxml解析网页为什么不完整?
  6. python pdf-有没有好一点的读取 PDF 的 Python 包?
  7. 开课吧python好吗-开课吧9.9元学Python课程适合哪些人?开课吧靠谱吗?
  8. 零基础可以学python吗-学Python需要什么基础知识?零基础可以学Python吗?
  9. python能在生活中做什么-Python能在生活中做什么
  10. python需要php吗-学python需要学linux吗