Android22-ListView常用优化技巧

1. 使用ViewHolder模式提高效率

  1. 定义一个内部类ViewHolder
  2. 在getView()方法中通过视图缓存机制来重用缓存即可。

设置item间的分隔线

注:这里可以把分隔线设置为一个颜色,也可以设置为一个图片资源。

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

以下代码可以把分隔线设置为透明:

android:divider="@null"

隐藏ListView的滚动条

android:scrollbars="none"

取消ListView的Item点击效果

android:listSelector="#00000000"
android:listSelector="@android:color/transarent"

动态修改ListView

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

如上代码,当修改了Adapter的映射List之后,只需要调用Adapter的notifyDatasetChanger()方法,通知ListView修改数据源即可,需注意的是在使用mAdapter.notifyDataSetChanged()方法时,必须保证传进Adapter的数据List是同一个List而不能是其他对象。

遍历ListView中的所有Item

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

处理空ListView

setEmptyView()方法可以在ListView中无数据时设置一个默认的显示布局,而当ListView有数据的时候则不会显示,代码示例如下:

ListView listView = (ListView)findViewById(R.id.listView);
listView.setEmptyView(findViewById(R.id.empty_view));

ListView滑动监听

  • 使用OnTouchListener()来实现滑动监听
mListView.setOnTouchListener(new View.OnTouchListener() {
       switch(event.getAction()) {
           case MotionEvent.ACTION_DOWN:
               //触摸时的操作
               break;
           case MotionEvent.ACTION_MOVE:
               //移动时的操作
               break;
           case MotionEvent.ACTION_UP:
               //手指离开屏幕时的操作
               break;
       }
});
  • 使用OnScrollListener()来实现滑动监听

OnScrollListener是AbsListView中的监听事件,它封装了很多与ListView相关的信息。以下是OnScrollListener的一般使用方法。

mListView.setOnScrollListener(new OnScrollListener() {
       @Override
       public void onScrollStateChanged(AbsListView view, int scrollState) {
           switch (scrollState) {
               case OnScrollListener.SCROLL_STATE_IDLE:
                   //滑动停止时
                   Log.d("Test", "SCROLL_STATE_IDLE");
                   break;
               case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
                   //正在滚动时
                   Log.d("Test", "SCROLL_STATE_TOUCH_SCROLL");
               case OnScrollListener.SCROLL_STATE_FLING:
                   //手指抛开时 
                   //在离开后,ListView由于惯性继续滑动
                   Log.d("Test", SCROLL_STATE_FLING);
                   break;
           }
       }
       /*
       * view: 当前的ListView
       * firstVisibleItem: 当前能看见的第一个Item的ID,包括显示一小半的Item
       * visibleItemCount: 当前能看见的Item总数
       * totalItemCount: 整个ListView的Item总数。
       */
       @Override
       public void onScroll(AbsListView view, 
       int firstVisibleItem,
       int visibleItemCount, 
       int totalItemCount) {
           //滚动时一直调用
           Log.d("Test", "onScroll");
       }
})
  • 判断是否滚动到最后一行
if (firstVisibleItem + visibleItemCount == totalItemCount&&totalItem-Count>0) {
       //滚动到最后一行
}
  • 判断滚动的方向
if (firstVisibleItem > lastVisibleItemPosition) {
       //上滑
} else if (firstVisibleItem < lastVisibleItemPosition){
       //下滑
}
lastVisibleItemPosition = firstVisibleItem;
  • 获取可视区域内的Item
//获取可视区域内最后一个Item的id
mListView.getLastVisiblePosition();
//获取可视区域内第一个Item的id
mListView.getFirstVisiblePosition();

ListView常用扩展

具有弹性的ListView


   //控制滑到边缘到处理方法
   @Override
   protected 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, mMaxOverDistance, isTouchEvent);
   }

根据滑动方向,自动隐藏toolbar

public class ScrollHideList extends AppCompatActivity {

   private Toolbar mToolbar;
   private ListView mListView;
   private String[] mstr = new String[20];
   private int mTouchSlop;
   private float mFirstY;
   private float mCurrentY;
   private int direction;
   private ObjectAnimator mAnimator;
   private boolean mShow = true;

   View.OnTouchListener myTouchListener = new View.OnTouchListener() {
       @Override
       public 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(1);//hide
                           mShow = !mShow;
                       }
                   } else if (direction == 0) {
                       if (!mShow) {
                           toolbarAnim(0);//show
                           mShow = !mShow;
                       }
                   }
                   break;
               case MotionEvent.ACTION_UP:
                   break;
           }
           return false;
       }
   };

   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.scroll_hide);
       mTouchSlop = ViewConfiguration.get(this).getScaledTouchSlop();
       mToolbar = (Toolbar) findViewById(R.id.toolbar);
       mListView = (ListView) findViewById(R.id.listview);
       for (int i = 0; i < mstr.length; i++) {
           mstr[i] = "Item" + i;
       }
       View header = new View(this);
       header.setLayoutParams(new AbsListView.LayoutParams(
               AbsListView.LayoutParams.MATCH_PARENT,
               (int) getResources().getDimension(
                       R.dimen.abc_action_bar_default_height_material)));
       mListView.setAdapter(new ArrayAdapter<String>(ScrollHideList.this, android.R.layout.simple_expandable_list_item_1,
               mstr));
       mListView.setOnTouchListener(myTouchListener);
   }

   private void toolbarAnim(int flag) {
       if (mAnimator != null && mAnimator.isRunning()) {
           mAnimator.cancel();
       }
       if (flag == 0){
               mAnimator = ObjectAnimator.ofFloat(mToolbar, "translationY", mToolbar.getTranslationY(),0);
       } else {
               mAnimator = ObjectAnimator.ofFloat(mToolbar, "translationY", mToolbar.getTranslationY(),-mToolbar.getHeight());
       }
       mAnimator.start();
   }
}

动态改变ListView布局

public class FocusListViewAdapter extends BaseAdapter {

   private List<String> mData;
   private Context mContext;
   private int mCurrentItem;

   public FocusListViewAdapter(Context context, List<String> data) {
       this.mContext = context;
       this.mData = data;
   }

   public int getCount() {
       return mData.size();
   }

   public Object getItem(int position) {
       return mData.get(position);
   }

   public long getItemId(int position) {
       return position;
   }

   @Override
   public 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;
   }

   public void setmCurrentItem(int currentItem) {
       this.mCurrentItem = currentItem;
   }

   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(mData.get(i));
       layout.addView(tv,new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
       layout.setGravity(Gravity.CENTER);
       return layout;
   }
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,905评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,140评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,791评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,483评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,476评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,516评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,905评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,560评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,778评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,557评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,635评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,338评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,925评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,898评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,142评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,818评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,347评论 2 342

推荐阅读更多精彩内容