書中的示例代碼:github
本章主要講了一些關(guān)于ListView的優(yōu)化
- 關(guān)于
ViewHolder
的使用:略(這個(gè)太簡單了)豺鼻。不過要注意使用ViewHolder
做緩存以后,在getView
的方法中無論這項(xiàng)的每個(gè)視圖是否需要設(shè)置屬性(比如TextView
設(shè)置的屬性可能為null
噩凹,item
的某一個(gè)按鈕的背景為透明阳欲、某一項(xiàng)的顏色為透明等)舵盈,都需要為每一項(xiàng)的所有視圖設(shè)置屬性(textview
的屬性為空也需要設(shè)置setText("")
,背景透明也需要設(shè)置)球化,否則在滑動的過程中會出現(xiàn)內(nèi)容的顯示錯亂秽晚。
2.設(shè)置項(xiàng)目間的分割線:
android:divider="@android:color/darker_gray" <!--分割線背景-->
android:dividerHeight="5dp" <!--分割線高度-->
如果不需要分割線可以如此:
android:divider="@null"
3.滾動條的隱藏:
android:scrollbars="none"
4.取消item
的點(diǎn)擊效果:
android:listSelector="#00000000" <!--設(shè)置為透明-->
5.設(shè)置ListView
顯示第幾項(xiàng):
listView.setSelection(n);//這個(gè)方法和scollTo類似,是瞬間完成移動
listView.smoothScrollBy(distance,duration);//下面三個(gè)為平滑移動
listView.smoothScrollByOffset(offset);
listView.smoothScrollToPosition(index);
6.遍歷ListView
中所有item
:
for(int i=0,i<listView.getChildCount();i++){
View view = listView.getChildAt(i);
}
7.處理空ListView
:
先是layout
的布局設(shè)置:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ListView
android:id="@+id/lv"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</ListView>
<ImageView
android:id="@+id/empty_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/ic_launcher" />
</FrameLayout>
然后是代碼中:
listView.setEmptyView(findViewById(R.id.empty_view));
//設(shè)置以后ListView會根據(jù)是否有數(shù)據(jù)來判斷是否顯示該EmptyView筒愚。
8.ListView
滑動監(jiān)聽:
-
OnTouchListener
:
listView.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// 觸摸時(shí)操作
break;
case MotionEvent.ACTION_MOVE:
// 移動時(shí)操作
break;
case MotionEvent.ACTION_UP:
// 離開時(shí)操作
break;
}
return false;
}
});
-
OnScrollListener
:
listView.setOnScrollListener(new OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
switch (scrollState) {
case OnScrollListener.SCROLL_STATE_IDLE:
//滑動停止時(shí)
break;
case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
//正在滾動時(shí)
break;
case OnScrollListener.SCROLL_STATE_FLING:
//手指快速滑動爆惧,手指離開后會因慣性繼續(xù)滑動時(shí)
break;
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
//firstVisibleItem 當(dāng)前能看到的第一個(gè)item的id,從0開始锨能,包括顯示不完整的
//visibleItemCount 當(dāng)前能看見的item總數(shù)扯再,包括顯示不完整的
//totalItemCount listview的item總數(shù)
//滾動時(shí)一直調(diào)用
if(firstVisibleItem+visibleItemCount==totalItemCount&&totalItemCount>0){
//滾動至最后一行
}
if(firstVisibleItem> lastVisibleItem){
//上滑
}else if(firstVisibleItem< lastVisibleItem){
//下滑
}
lastVisibleItem=firstVisibleItem;//自行定義一個(gè)lastVisibleItem的成員變量
listView.getFirstVisiblePosition();
listView.getLastVisiblePosition();//當(dāng)然也可以通過ListView提供的方法直接獲取
}
});
9.具有彈性的ListView
:
private int mMaxOverDistance=20;
/*
* 繼承ListView重寫overScrollBy,然后根據(jù)自己需求將maxOverScrollY設(shè)置為某個(gè)值即可址遇,也可利用代碼獲取屏幕密度與該值相乘來適配屏幕
*/
@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);
}
10.自動顯示和隱藏布局的ListView
:
public class MainActivity 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);//show
mShow = !mShow;
}
} else if (direction == 0) {
if (!mShow) {
toolbarAnim(0);//hide
mShow = !mShow;
}
}
break;
case MotionEvent.ACTION_UP:
break;
}
return false;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTouchSlop = ViewConfiguration.get(this).getScaledTouchSlop();
mToolbar = (Toolbar) findViewById(R.id.tool_bar);
mListView = (ListView) findViewById(R.id.lv);
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.addHeaderView(header);
mListView.setAdapter(new ArrayAdapter<String>(
this,
android.R.layout.simple_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();
}
}
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity" >
<android.widget.Toolbar
android:id="@+id/tool_bar"
android:layout_width="match_parent"
android:layout_height="@dimen/abc_action_bar_default_height_material"
android:background="#fff332" />
<ListView
android:id="@+id/lv"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
11.聊天ListView
熄阻,這里直接貼關(guān)鍵代碼:
這里主要重寫BaseAdapter
中的幾個(gè)方法
@Override
public int getViewTypeCount() {
return 2;
}
@Override
public int getItemViewType(int position) {
return mChatBeanList.get(position).getType();
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
ChatBean chatBean = mChatBeanList.get(position);
if (convertView == null) {
viewHolder = new ViewHolder();
if (getItemViewType(position) == 0) {// 不重寫方法直接用ChatBean里的type比較也一樣
convertView = View.inflate(getActivity(), R.layout.chat_item_in, null);
viewHolder.tv = (TextView) convertView.findViewById(R.id.tv_in_text);
} else {
convertView = View.inflate(getActivity(), R.layout.chat_item_out, null);
viewHolder.tv = (TextView) convertView.findViewById(R.id.tv_out_text);
}
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.tv.setText(chatBean.getText());
return convertView;
}
12動態(tài)改變ListView
布局:
//在BaseAdapter里增加一個(gè)currentItem屬性,通過它與position比較來判斷哪個(gè)被選中
@Override
public View getView(int position, View convertView, ViewGroup parent) {
LinearLayout layout = new LinearLayout(getActivity());
layout.setOrientation(LinearLayout.VERTICAL);
if(currentItem==position){
layout.addView(addFocusView());
}else{
layout.addView(addNormalView(position));
}
return layout;
}
//在ListView的item點(diǎn)擊事件設(shè)置點(diǎn)擊中的item并且刷新ListView數(shù)據(jù)
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
mAdapter.setCurrentItem(position);
mAdapter.notifyDataSetChanged();
}
});