Android入门(11)——ListView使用汇总

一、简介:


1.每个ListView都包含很多个列表项:




2. 数据适配器:


例如电视台是数据源,通过数据适配器显示在电视上。



3. 典型应用案例:

                                                        

                            



写在前面的话,对于每一个Adapter,它们都是要接收数据源List和每个itme的布局文件的,然后在Adapter中提供各种方法,比如说getCount、getItem、getView等等,其中的getView是把List中的某一项根据布局文件加载为一个View并返回给ListView控件的,这下懂了其中的原理了吗?

4. 使用ArrayAdapter。


布局中只需要加入一个ListView控件:

<ListView
        android:id="@+id/listView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1" >
    </ListView>

MainActivity.java源代码:

package com.example.listview;

import android.os.Bundle;
import android.app.Activity;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.SimpleAdapter;

public class MainActivity extends Activity {
	
	private ListView listView;
	private ArrayAdapter<String> arr_adapter;
	private SimpleAdapter simp_adapter;
	
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        listView = (ListView) findViewById(R.id.listView);
        /*
         * 1. 新建一个适配器。
         * 		采用数组的模式,第一个参数context是上下文,第二个参数resource当前ListView中加载的每一个列表项所对应的布局文件,这里我们采用Android自带的。
         *  	第三个参数objects是数据源。
         *  2. 适配器加载数据源。
         * */
        String[] arr_data = {"笑笑1","笑笑2","笑笑3","笑笑4"};
        arr_adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, arr_data);
        
        /*
         * 3. 视图(ListView)加载适配器。
         * */
        listView.setAdapter(arr_adapter);
    }
    
}
效果图:



5. 使用SimpleAdapter


第一步:首先需要创建一个叫item.xml的布局文件,用来设定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" >
    
    <!-- 我们在这个item的布局文件中主要是为了设计ListView中每一项的布局
    	这里要设置的是每一项包含一个图片和文字。
     -->
     <ImageView 
         android:id="@+id/pic"
         android:layout_marginLeft="15dp"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:src="@drawable/ic_launcher"
         />
     
     <TextView 
         android:id="@+id/text"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:textSize="20sp"
         android:textColor="#000000"
         android:text="demo"
         />

</LinearLayout>
第二步:
在软件布局中,也仅仅是放置了一个ListView控件:

<ListView
        android:id="@+id/listView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1" >
    </ListView>
第三步:

设置MainActivity文件:

package com.example.listview;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.os.Bundle;
import android.app.Activity;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.SimpleAdapter;

public class MainActivity extends Activity {
	
	private ListView listView;
	private ArrayAdapter<String> arr_adapter;
	private SimpleAdapter simp_adapter;
	
	// 有个问题就是,不太会用Map,有点没看懂,键值对,那么前面是键,后面是值
	private List<Map<String,Object>> datalist;
	
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        listView = (ListView) findViewById(R.id.listView);
        /*
         * 1. 新建一个适配器。
         * 	 第一个参数 context:上下文
         * 	 第二个参数data:List<? extends Map<String, ?>> data 
         * 		是一个特定泛型的集合,数据源。一个Map所组成的List集合。
         * 		每一个Map都会去对应ListView列表中的一行。每一个Map(键-值对)中的键必须去包含所有在from中所制定的键。
         * 	第三个参数resource:列表项的布局文件ID。这个布局文件可以用Android自带的,也可以自己新建一个,这里我们新建一个布局文件叫item.xml
         *  第四个参数from:Map中的键名。这里的例子中对应item中的两个控件起了两个名字。这里指的是所有可能的键,
         *  第五个参数to:绑定数据视图中的ID,与from对应,这个例子中的to指的是用户自定义的item中的图片和文字控件的ID。
         * 2. 适配器加载数据源。
         * */
        datalist = new ArrayList<Map<String,Object>>();// 为什么是这样分配的?
        /*
         * 我再来解释一下这个第四五的参数
         * 第四个参数是指在每一条item中包含的控件的键名
         * 第五个参数是指在每一条item中对应的item布局的
         * */
        simp_adapter = new SimpleAdapter(this, getData(),R.layout.item , new String[]{"PIC","TEXT"}, new int[]{R.id.pic,R.id.text});
        /*
         * 3. 视图(ListView)加载适配器。
         * */
        listView.setAdapter(simp_adapter);
    }
    
    private List<Map<String,Object>> getData(){
    	for(int i=0; i<20; i++){
    		Map<String,Object> map = new HashMap<String, Object>();
    		map.put("PIC", R.drawable.ic_launcher);			// 前面是键,后面是值。
    		map.put("TEXT", "笑笑"+i);						// 前面是键,后面是值。
    		datalist.add(map);
    	}
    	return datalist;
    }
    
}

第四步:效果图:



6. 监听器:




7. 监听ListView列表项点击事件:


用接口的方式来实现。

package com.example.listview;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.os.Bundle;
import android.app.Activity;
import android.view.View;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.Toast;

public class MainActivity extends Activity implements OnItemClickListener,OnScrollListener{
	
	private ListView listView;
	private ArrayAdapter<String> arr_adapter;
	private SimpleAdapter simp_adapter;
	
	private List<Map<String,Object>> datalist;
	
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        listView = (ListView) findViewById(R.id.listView);
        datalist = new ArrayList<Map<String,Object>>();
        simp_adapter = new SimpleAdapter(this, getData(),R.layout.item , new String[]{"PIC","TEXT"}, new int[]{R.id.pic,R.id.text});

        listView.setAdapter(simp_adapter);
        listView.setOnItemClickListener(this);

    }
    
    private List<Map<String,Object>> getData(){
    	for(int i=0; i<20; i++){
    		Map<String,Object> map = new HashMap<String, Object>();
    		map.put("PIC", R.drawable.ic_launcher);
    		map.put("TEXT", "笑笑"+i);
    		datalist.add(map);
    	}
    	return datalist;
    }

	@Override
	public void onItemClick(AdapterView<?> arg0, View arg1, int position, long arg3) {
		// position传递当前点击列表项目所传过来的对应位置。
		String text = listView.getItemAtPosition(position)+" ";
		// 第三个参数duration表示的是显示时长,
		Toast.makeText(this, "position = "+ position+"text = "+text, Toast.LENGTH_SHORT).show();
	}

}
效果图:



8. 监听ListView滚动事件:


在上面的基础上,这样实现onScrollStateChanged函数:

mListView.setOnTouchListener(new View.OnTouchListener(){
<span style="white-space:pre">	</span>@Override
<span style="white-space:pre">	</span>public void onScrollStateChanged(AbsListView arg0, int scrollState) {
<span style="white-space:pre">		</span>// TODO Auto-generated method stub
<span style="white-space:pre">		</span>switch(scrollState){
<span style="white-space:pre">		</span>case SCROLL_STATE_FLING:
<span style="white-space:pre">			</span>Log.i("Main","用户在手指离开屏幕前,由于用力的滑了以下,视图可以依靠惯性继续滑");
<span style="white-space:pre">			</span>break;
<span style="white-space:pre">		</span>case SCROLL_STATE_IDLE:
<span style="white-space:pre">			</span>Log.i("Main", "视图已经停止滑动");
<span style="white-space:pre">			</span>break;
<span style="white-space:pre">		</span>case SCROLL_STATE_TOUCH_SCROLL:
<span style="white-space:pre">			</span>Log.i("Main", "手指没有离开屏幕,视图正在滑动");
<span style="white-space:pre">			</span>break;
<span style="white-space:pre">		</span>default:
<span style="white-space:pre">			</span>break;
<span style="white-space:pre">		</span>}
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>
<span style="white-space:pre">	</span>@Override
<span style="white-space:pre">	</span>public void onScroll(AbsListView view,
<span style="white-space:pre">			</span>int firstVisibleItem,//当前能看见的第一个Item的ID,从0开始。
<span style="white-space:pre">			</span>int visibleItemCount,//能看到的Item总数,包括没有显示完整的item。
<span style="white-space:pre">			</span>int totalItmeCount){//整个ListView的Item总数
<span style="white-space:pre">		</span>// 滚动时一直调用
<span style="white-space:pre">		</span>Log.d("Test","onScroll");
<span style="white-space:pre">	</span>}
});

一些小判断:

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

if(firstVisibleItem > lastVisibleItemPosition){
	// 上滑
}else if(firstVisibleItem < lastVisibleItemPosition){
	// 下滑
}
lastVisibleItemPosition = firstVisibleItem;//记录上一次的位置。


学习小助手:Log!!!!!

还有一些封装的:

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


效果图:


9、OnTouchListener:

根据坐标判断用户滑动的方向,并在不同的事件中进行相应的逻辑处理:

mListView.setOnTouchListener(new View.OnTouchListener(){
	@Override
	public boolean onTouch(View v, MotionEvent event){
		switch(event.getAction()){
		case MotionEvent.ACTION_DOWN:
			// 触摸时操作
			break;
		case MotionEvent.ACTION_MOVE:
			// 移动时操作
			break;
		case MotionEvent.ACTION_UP:
			// 离开时操作
			break;
		}
		return false;
	}
});


9. 一个小小案例:


这个案例是指当用户将ListView拉到最低端时,列表自动更新新的项出现,我们后台是给数据源增加新的项,并刷新数据源:

@Override
	public void onScrollStateChanged(AbsListView arg0, int scrollState) {
		// TODO Auto-generated method stub
		switch(scrollState){
		case SCROLL_STATE_FLING:
			Log.i("Main","用户在手指离开屏幕前,由于用力的滑了以下,视图可以依靠惯性继续滑");
			Map<String, Object>map = new HashMap<String, Object>();
			map.put("PIC",R.drawable.ic_launcher);
			map.put("TEXT", "增加项");
			datalist.add(map);
			simp_adapter.notifyDataSetChanged();	// 数据源发生变化,就要用这个语句刷新一下,不然程序会崩溃的。
			break;
		case SCROLL_STATE_IDLE:
			Log.i("Main", "视图已经停止滑动");
			break;
		case SCROLL_STATE_TOUCH_SCROLL:
			Log.i("Main", "手指没有离开屏幕,视图正在滑动");
			break;
		default:
			break;
		}
	}

效果图:



10. 注意点:




五、ListView缓存机制

1. 什么是BaseAdapter:最常用的数据适配器,降低耦合性,容易扩展。




2. ListView的显示与缓存机制:





六、BaseAdapter的文艺使用方法






[java]  view plain copy print ?
  1. package com.example.listviewdemo;  
  2. import java.util.List;  
  3.   
  4. import com.example.listviewdemo.ItemBean;  
  5.   
  6. import android.R;  
  7. import android.content.Context;  
  8. import android.view.LayoutInflater;  
  9. import android.view.View;  
  10. import android.view.ViewGroup;  
  11. import android.widget.BaseAdapter;  
  12. import android.widget.ImageView;  
  13. import android.widget.TextView;  
  14.   
  15.   
  16. public class MyAdapter extends BaseAdapter{  
  17.   
  18.     private List<ItemBean> mList;  
  19.     private LayoutInflater mInflater;  
  20.       
  21.     // 通过构造方法将数据源与适配器进行关联:  
  22.     public MyAdapter(List<ItemBean> list,Context context){  
  23.         mList = list;  
  24.         // context要使用当前的Adapter的界面对象  
  25.         // mInflater:布局装载器对象。  
  26.         mInflater = LayoutInflater.from(context);  
  27.     }  
  28.       
  29.     @Override  
  30.     public int getCount() {  
  31.         // TODO Auto-generated method stub  
  32.         return mList.size();  
  33.     }  
  34.   
  35.     @Override  
  36.     public Object getItem(int position) {  
  37.         // TODO Auto-generated method stub  
  38.         return mList.get(position);  
  39.     }  
  40.   
  41.     @Override  
  42.     public long getItemId(int position) {  
  43.         // TODO Auto-generated method stub  
  44.         return position;  
  45.     }  
  46.   
  47.     /* 
  48.      * 返回每一项的显示内容: 
  49.      * */  
  50.     @Override  
  51.     public View getView(int position, View convertView, ViewGroup parent) {  
  52.         // TODO Auto-generated method stub  
  53.           
  54.         /* 逗比式 
  55.         // 第一个参数是需要装载到item中的布局文件,第二个通常写null 
  56.         View view = mInflater.inflate(R.layout.item, null); 
  57.         ImageView imageView = (ImageView)view.findViewById(R.id.iv_image); 
  58.         TextView title = (TextView)view.findViewById(R.id.tv_title); 
  59.         TextView content = (TextView)view.findViewById(R.id.tv_content); 
  60.          
  61.         ItemBean bean = mList.get(position); 
  62.         imageView.setImageResource(bean.ItemImageResid); 
  63.         title.setText(bean.ItemTitle); 
  64.         content.setText(bean.ItemContent); 
  65.         return view; 
  66.         */  
  67.           
  68.         /* 
  69.          * 普通式与逗比式差别并不是很大,只是对convertView的处理不同, 
  70.          * 但正是这样的处理,我们充分利用了ListView的缓存机制, 
  71.          * 避免重复的创建convertView对象。 
  72.          * 因为我们将一个布局通过inflate转化为一个view时是非常耗资源的。 
  73.          * 通过这样一个简单的判断,我们就可以避免创建大量的convertView对象。 
  74.          * 从而对getView方法进行一个很好的优化。 
  75.          * */  
  76.         /* 
  77.         if(convertView == null){ 
  78.             convertView = mInflater.inflate(R.layout.item, null); 
  79.         } 
  80.         ImageView imageView = (ImageView)convertView.findViewById(R.id.iv_image); 
  81.         TextView title = (TextView)convertView.findViewById(R.id.tv_title); 
  82.         TextView content = (TextView)convertView.findViewById(R.id.tv_content); 
  83.         ItemBean bean = mList.get(position); 
  84.         imageView.setImageResource(bean.ItemImageResid); 
  85.         title.setText(bean.ItemTitle); 
  86.         content.setText(bean.ItemContent); 
  87.          
  88.         return convertView; 
  89.         */  
  90.           
  91.         ViewHolder viewHolder;  
  92.         if(convertView == null){  
  93.             viewHolder = new ViewHolder();  
  94.             convertView = mInflater.inflate(R.layout.item, null);  
  95.             viewHolder.imageView = (ImageView)convertView.findViewById(R.id.iv_image);  
  96.             viewHolder.title = (TextView)convertView.findViewById(R.id.tv_title);  
  97.             viewHolder.content = (TextView) convertView.findViewById(R.id.tv_content);    
  98.             // 建立convertView与viewHolder之间的关系:  把那个viewHolder保存起来,日后再用
  99.             convertView.setTag(viewHolder);  
  100.         }else{  
  101.             viewHolder = (ViewHolder) convertView.getTag();  
  102.         }  
  103.         ItemBean bean = mList.get(position);  
  104.         viewHolder.imageView.setImageResource(bean.ItemImageResid);  
  105.         viewHolder.title.setText(bean.ItemTitle);  
  106.         viewHolder.content.setText(bean.ItemContent);  
  107.         return convertView;  
  108.     }  
  109.   
  110.     /* 
  111.      * 定义内部类ViewHolder 
  112.      * */  
  113.     class ViewHolder{  
  114.         public ImageView imageView;  
  115.         public TextView title;  
  116.         public TextView content;  
  117.     }  
  118. }  


七、关于ListView的一些使用小技巧

1、设置项目间分割线:

        android:divider="@android:color/darker_gray"	// 分割线背景色,灰色,也可以是图片资源
        android:dividerHeight="10dp" 			// 分割线高度
        android:divider="@null"				// 分割线背景色也可以设置为透明,也就是取消分割线的显示。

2、隐藏ListView的滚动条:


android:scrollbars="none"	// 隐藏滚动条

3、取消ListView的Item点击效果:

        android:listSelector="#00000000"	// 透明色
        android:listSelector="@android:color/transparent" // 透明色

4、设置ListView需要显示在第几项:

// 瞬间移动
listView.setSelection(N);

// 平滑移动
mListView.smoothScrollBy(distance,duration);
mListView.smoothScrollByOffset(offset);
mListView.smoothScrollToPositon(index);

5、动态修改ListView:

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


6、遍历ListView中的所有Item:

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

7、处理空ListView:

就是在当前布局文件中通过FrameLayout给ListView后面再添加一个控件,这个控件可以是一个ImageView,然后用来显示一张图片什么的,最后在MainActivity中进行绑定。

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



八、ListView常用扩展


1、具有弹性的ListView:


貌似方法很多,作者介绍了一种很简单的控制滑动到边缘的方法,如下:

其中的重点在 mMaxOverDistance 上,这个值是用户自己定义的啦。

<code class="hljs perl has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">/<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">**</span>
*
* <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">@param</span> maxOverScrollX Number of pixels to overscroll by <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">in</span> <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">either</span> direction along the X axis.        
* <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">@param</span> maxOverScrollY Number of pixels to overscroll by in either direction along the Y axis.默认为0.
<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">**</span> /   

<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">@Override</span>
    protected boolean overScrollBy(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> deltaX, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> deltaY, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> scrollX, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> scrollY, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> scrollRangeX, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> scrollRangeY,
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> maxOverScrollX, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> maxOverScrollY, boolean isTouchEvent) {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, maxOverScrollX,
                 mMaxOverDistance, isTouchEvent);
    }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li></ul>

完整的弹性ListView如下:

<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">MyListView</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">extends</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">ListView</span> {</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> Context mContext;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> mMaxOverDistance = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">50</span>;

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-title" style="box-sizing: border-box;">MyListView</span>(Context context) {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">super</span>(context);
        mContext = context;
        initView();
    }

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-title" style="box-sizing: border-box;">MyListView</span>(Context context, AttributeSet attrs) {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">super</span>(context, attrs);
        mContext = context;
        initView();
    }

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-title" style="box-sizing: border-box;">MyListView</span>(Context context, AttributeSet attrs, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> defStyle) {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">super</span>(context, attrs, defStyle);
        mContext = context;
        initView();
    }

    <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@SuppressLint</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"NewApi"</span>)
    <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">boolean</span> <span class="hljs-title" style="box-sizing: border-box;">overScrollBy</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> deltaX, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> deltaY, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> scrollX, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> scrollY, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> scrollRangeX, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> scrollRangeY,
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> maxOverScrollX, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> maxOverScrollY, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">boolean</span> isTouchEvent) {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">super</span>.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, maxOverScrollX,
                 mMaxOverDistance, isTouchEvent);
    }

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">initView</span>() {
        DisplayMetrics metrics = mContext.getResources().getDisplayMetrics();
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">float</span> density = metrics.density;
        mMaxOverDistance = (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>) (density * mMaxOverDistance);
    }

}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li></ul>

在上面的initView中,为了能够满足多分辨率的需求,通过屏幕的density来计算具体值,让不同分辨率的弹性距离基本一致。


2 .自定显示、隐藏布局的ListView

就是通过监听ListView的onTouchListener事件,然后判断当ListView在滑动时,来用动画来控制Toolbar的出现和消失:
/**
 * Created by acer on 2015/10/30.
 */
public class MyActivity extends Activity {
	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;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.scroll_hide);
		mListView = (ListView) findViewById(R.id.listview);

		// 首先需要给ListView增加一个HeaderView,避免第一个Item被Toolbar遮挡:
		View header = new View(this);
		header.setLayoutParams(new AbsListView.LayoutParams(
				ViewGroup.LayoutParams.MATCH_PARENT, // 宽 充满屏幕
				(int) getResources().getDimension( // 高 获取系统Actionbar的高度。
						R.dimen.abc_action_bar_default_height_material)));
		mListView.addHeaderView(header);

		// 获取系统认为的最少滑动距离:
		mTouchSlop = ViewConfiguration.get(this).getScaledTouchSlop();

		// 逐渐用Toolbar来取代ActionBar了,但是在使用的时候一定要注意使用的Theme要NoActionBar的,不然引起冲突。
		mToolbar = (Toolbar) findViewById(R.id.toolbar);
		// 设置数据源:
		for (int i = 0; i < mStr.length; i++) {
			mStr[i] = "item" + i;
		}
		mListView.setAdapter(new ArrayAdapter<String>(MyActivity.this,
				android.R.layout.simple_expandable_list_item_1, mStr));
		mListView.setOnTouchListener(myTouchListener);
	}

	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();
				Log.e("mess", "-----currentY=" + mCurrentY + ",firstY="
						+ mFirstY + ",======" + (mCurrentY - mFirstY));
				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;
			default:
				break;
			}
			return false;
		}
	};
	
	private void toolbarAnim(int flag) {
		if (mAnimator != null && mAnimator.isRunning()) {
			mAnimator.cancel();
		}
		// mToolbar.getTranslationY()获取View的绝对位置,
		Log.e("mess", "transtionY==============" + mToolbar.getTranslationY()
				+ ",height=========" + mToolbar.getHeight());
		if (flag == 0) {// show toolbar
						// down,从mToolbar.getTranslationY()位置,移动到当前位置 y ,
			mAnimator = ObjectAnimator.ofFloat(mToolbar, "translationY",
					mToolbar.getTranslationY(), 0);
		} else {// hide toolbar up,从当前位置,移动到mToolbar.getTranslationY()位置 y
			mAnimator = ObjectAnimator.ofFloat(mToolbar, "translationY",
					mToolbar.getTranslationY(), -mToolbar.getHeight());
		}
		mAnimator.start();
	}

}



3、聊天ListView:


聊天时的ListView它和平时最大的不同在于它拥有两个不同的布局——收到布局和发送布局。
在定义BaseAdapter时,需要去重写它的getVIew方法,那么只需要在获取布局的时候,判断一下该获取哪一种布局就可以了。
在ListView中它提供两个方法,需要重写:
/***
 * 返回第position个Item是何种类型:
 */
@Override
public int getItemViewType(int position) {
	return type;
}

/**
 * 返回不同布局的总数:
 */
@Override
public int getViewTypeCount() {
	return number;
}

下面举个例子吧:主要是在getView函数中进行判断。

package defaultPackage;

import java.util.List;

import com.mtest.test.R;

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;

public class ChatItemListViewAdapter extends BaseAdapter {

	private List<ChatTiemListViewBean> mData;
	private LayoutInflater mInflater;

	public ChatItemListViewAdapter(Context context,
			List<ChatTiemListViewBean> data) {
		this.mData = data;
		mInflater = LayoutInflater.from(context);
	}

	@Override
	public int getCount() {
		// TODO Auto-generated method stub
		return mData.size();
	}

	@Override
	public Object getItem(int position) {
		// TODO Auto-generated method stub
		return mData.get(position);
	}

	@Override
	public long getItemId(int position) {
		// TODO Auto-generated method stub
		return position;
	}

	/***
	 * 这两个方法是我们平时不会用到的 返回第position个Item是何种类型:
	 */
	@Override
	public int getItemViewType(int position) {
		ChatTiemListViewBean bean = mData.get(position);
		return bean.getType();
	}

	/**
	 * 返回不同布局的总数:
	 */
	@Override
	public int getViewTypeCount() {
		return 2;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		ViewHolder holder;
		if (convertView == null) {
			if (getItemViewType(position) == 0) {
				holder = new ViewHolder();
				convertView = mInflater
						.inflate(R.layout.chat_item_itemin, null);
				holder.icon = (ImageView) convertView
						.findViewById(R.id.icon_in);
				holder.text = (TextView) convertView.findViewById(R.id.text_in);
			} else {
				holder = new ViewHolder();
				convertView = mInflater.inflate(R.layout.chat_item_itemout,
						null);
				holder.icon = (ImageView) convertView
						.findViewById(R.id.icon_out);
				holder.text = (TextView) convertView
						.findViewById(R.id.text_out);
			}
			convertView.setTag(holder);
		} else {
			holder = (ViewHolder) convertView.getTag();
		}

		holder.icon.setImageBitmap(mData.get(position).getIcon());
		holder.text.setText(mData.get(position).getText());
		return convertView;
	}

	public final class ViewHolder {
		public ImageView icon;
		public TextView text;
	}
}
没什么其他的特别之处了。


4、动态改变ListView布局:


据书中介绍一般有2种方式:

  • 两种布局写在一起,通过控制布局的隐藏,显示,控制切换布局

  • 通过判断来选择加载不同的布局

以第二种方式来作为示例:

public class FocusListViewAdapter extends BaseAdapter {

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

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

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

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

    @Override
    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 setCurrentItem(int currentItem) {
        this.mCurrentItem = currentItem;
    }

    private View addFocusView(int i) {
        ImageView iv = new ImageView(mContext);
        iv.setImageResource(R.drawable.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.drawable.in_icon);
        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(
                LinearLayout.LayoutParams.WRAP_CONTENT,
                LinearLayout.LayoutParams.WRAP_CONTENT));
        
        layout.setGravity(Gravity.CENTER);
        return layout;
    }
}

当适配器内容发生变化时,调用notifyDataSetChanged();
public class FocusListViewTest extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.focus);
        ListView listView = (ListView) findViewById(R.id.focus_listView);
        List<String> data = new ArrayList<String>();
        data.add("I am item 1");
        data.add("I am item 2");
        data.add("I am item 3");
        data.add("I am item 4");
        data.add("I am item 5");
        final FocusListViewAdapter adapter = new FocusListViewAdapter(this, data);
        listView.setAdapter(adapter);
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view,
                                    int position, long id) {
                adapter.setCurrentItem(position);
                adapter.notifyDataSetChanged();
            }
        });
    }
}

























评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值