UI之ListView

一、ListView
作用:该控件是一类列表控件,允许用户通过手指上下滑动的方式将屏幕外的数据滚动到屏幕内,同时屏幕上原有的数据则会滚出屏幕
二、定制ListView的界面
以定制一个球星姓名的列表为例:
1、由于ListView这一控件是由一个个item组成,因此我们首先需要定义一个实体bean类。类中的数据成员包含着每一个item所要展示的元素。这个实体类还是作为ListView适配器的适配类型。代码如下图所示:

			public class soccerName {
    
    
			    private String name;
			    public soccerName(String name){
    
    
			        this.name = name;
			    }
			    public void setName(String name){
    
    
			        this.name = name;
			    }
			    public String getName(){
    
    
			        return name;
			    }
			}

2、然后需要为ListView的子项指定一个我们自定义的布局,在layout目录下新建name_item.xml,代码如下图所示:

		<LinearLayout
		    xmlns:android="http://schemas.android.com/apk/res/android"
		    android:layout_width="match_parent"
		    android:layout_height="wrap_content">
		    <TextView
		        android:id="@+id/name"
		        android:layout_width="match_parent"
		        android:layout_height="100px"
		        android:gravity="center"
		        android:layout_margin="10px" 
		        />
		</LinearLayout>

3、接下来创建一个自定义的适配器,该适配器能将我们要展示的数据传入到ListView控件当中。这里我们适配器要继承自ArrayAdapter,并将泛型指定为类。新建一个FruitAdapter类,代码如下:

	public class SoccerAdapter extends ArrayAdapter<Soccer> {
    
    
	    private int resourceId;
		//1、SoccerAdapter重写了父类的一组构造函数,用于将上下文、ListView的子项布局文件的id和数据都传进来
	    public SoccerAdapter(@NonNull Context context, int resource, int textViewResourceId, @NonNull List<Soccer> objects) {
    
    
	        super(context, resource, textViewResourceId, objects);
	        resourceId = textViewResourceId;
	    }
	    //2、重写了getView()方法,这个方法在每个子项被滚动到屏幕内的时候会被调用
	    @NonNull
	    @Override
	    public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
    
    
	        //3、通过getItem()方法得到当前项的Soccer实例
	        Soccer soccer = getItem(position);
	        //4、使用LayoutInflater来为这个子项加载我们传入的布局,inflate()方法中传入的第三个参数表示只
	        //让我们在父布局中声明的layout属性生效,但不会为这个View添加父布局
	        View view = LayoutInflater.from(getContext()).inflate(resourceId,parent,false);
			//5、获取实例,并且赋值,最后返回
	        TextView name = view.findViewById(R.id.name);
	        name.setText(soccer.getName());
	        return view;
	    }
	}

4、在我们要引用ListView的布局文件中添加ListView这个控件

    <ListView
        android:id="@+id/list_name"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:ignore="MissingConstraints" />

5、最后在java中的代码如下:

	 private List<Soccer> soccerList = new ArrayList<>();
	
	    @Override
	    protected void onCreate(Bundle savedInstanceState) {
    
    
	        super.onCreate(savedInstanceState);
	        setContentView(R.layout.activity_main);
	        initName();
	        SoccerAdapter soccerAdapter = new SoccerAdapter(MainActivity.this,R.layout.name_item,soccerList);
	        ListView listView = findViewById(R.id.list_name);
	        listView.setAdapter(soccerAdapter);
	    }
	    public void initName(){
    
    
	        for(int i=0;i<2;i++){
    
    
	            Soccer name1 = new Soccer("c罗");
	            soccerList.add(name1);
	            Soccer name2 = new Soccer("本泽马");
	            soccerList.add(name2);
	            Soccer name3 = new Soccer("贝尔");
	            soccerList.add(name3);
	            Soccer name4 = new Soccer("莫德里奇");
	            soccerList.add(name4);
	            Soccer name5 = new Soccer("卡塞米罗");
	            soccerList.add(name5);
	            Soccer name6 = new Soccer("克罗斯");
	            soccerList.add(name6);
	            Soccer name7 = new Soccer("马塞洛");
	            soccerList.add(name7);
	            Soccer name8 = new Soccer("拉莫斯");
	            soccerList.add(name8);
	            Soccer name9 = new Soccer("瓦拉内");
	            soccerList.add(name9);
	            Soccer name10 = new Soccer("卡瓦哈尔");
	            soccerList.add(name10);
	            Soccer name11 = new Soccer("纳瓦斯");
	            soccerList.add(name11);
	            Soccer name12 = new Soccer("齐达内");
	            soccerList.add(name12);
	        }
    	}

结果如下:
在这里插入图片描述

三、 提升ListView 的运行效率

  • (一)在正常情况下getView()方法中,每次都会将布局重新加载一遍,而当ListView快速滚动时,这就会成为性能的瓶颈。而getView()方法中convertView参数,用于将之前加载好的布局进行缓存,便于之后进行重新使用。以下是优化方法:
		   Soccer soccer = getItem(position);
		        
	       View view;
	        if(convertView == null)
	            view = LayoutInflater.from(getContext()).inflate(resourceId,parent,false);
	        else
	            view = convertView;
	        
	        TextView name = view.findViewById(R.id.name);
	        name.setText(soccer.getName());
	        return view;
  • (二)解决重复加载布局之后,我们还发现现在getView()方法每加载一次都会调用view.findById()方法获取一次控件的实例,以下是优化方法:
	 @Override
	    public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
    
    
	        Soccer soccer = getItem(position);
	
	        View view;
	        ViewHolder viewHolder;
	        if(convertView == null) {
    
    
	            view = LayoutInflater.from(getContext()).inflate(resourceId, parent, false);
	            viewHolder  = new ViewHolder();
	            viewHolder.name = view.findViewById(R.id.name);
	            view.setTag(viewHolder);
	        }else {
    
    
	            view = convertView;
	            viewHolder = (ViewHolder) view.getTag();
	        }
	   
	        viewHolder.name.setText(soccer.getName());
	        return view;
	    }
	    
	    class ViewHolder{
    
    
	        TextView name;
	    }
	我们定义了一个ViewHolder的内部类,用于存放所需要实例化控件。第一次加载布局时,实例化控件并且通过调用View对象的setTag()方法将ViewHolder的对象存入到view的Tag当中;再次加载布局时,调用getTag()方法找回实例化的控件 

四、ListView其他设定
(一)设置项目间分割线

    android:divider="@color/black" //设置分割线颜色
    android:dividerHeight="3dp"	   //设置分割线高度

(二)影藏ListView的滚动条

  	android:scrollbars="none"    

(三)取消ListView的Item点击效果

	android:listSelector="#00000000"    

(四)设置ListView需要显示在第几项

扫描二维码关注公众号,回复: 13231616 查看本文章
	listView.setSelection(N); //N即需要显示的第N个Item

(五)动态修改ListView

	adapter.notifyDataSetChanged();

(六)遍历ListView中所有的Item

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

(七)处理空ListView
首先在ListView布局后面放一个控件,用于展示ListView为空时要显示的内容

<android.support.constraint.ConstraintLayout
    .....  >
    <ListView
        android:id="@+id/list_name"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:ignore="MissingConstraints" />
    <TextView
        android:id="@+id/empty"
        android:text="hello world"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        tools:ignore="MissingConstraints" />
</android.support.constraint.ConstraintLayout>

然后在代码中实现如下语句,即可实现调用:

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

(八)ListView滑动监听

  • 1)OnTouchListener
    OnTouchListener是View中的监听事件,通过监听如下几个事件发生时坐标,就可以判断用户滑动操作,并进行相应的逻辑处理
	 listView.setOnTouchListener(new View.OnTouchListener() {
    
    
            @SuppressLint("ClickableViewAccessibility")
            @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;
            }
        });
  • 2)OnScrollListener
    OnScrollListener是ABSListView中的监听事件,它封装了许多与ListView相关的信息,使用模板如下:
    listView.setOnScrollListener(new OnScrollListener() {
    
    
            @Override
            public 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:
                        //手指抛动时,即手指用力滑动时,在离开后ListView由于惯性继续滑动时调用
                        break;
                }
            }
            @Override
            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
    
    
                //滚动时一直调用
                //这里传入四个参数
                	//firstVisibleItem:当前能看见的第一个Item的ID
                	//visibleItemCount:当前能看见的Item总数(这里能看见的包括了只显示一半的Item)
                	//totalItemCount:整个ListView的Item总数
            }
        });

通过上述的onScroll()方法里的几个参数,我们可以通过代码判断是否滚动到了最后一行,如:

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

此外还可以通过几个参数判断滚动的方向,如:

		if(firstVisibleItem > lastVisiblePosition){
    
    
     		 //上滑
         }else if (firstVisibleItem < lastVisiblePosition){
    
    
             //下滑
         }
         lastVisiblePosition = firstVisibleItem;
	其中:lastVisiblePosition用于记录上次第一个可视的Item的ID

同时,ListView也提供了一些封装的方法来获取当前可视的Item的位置等

    	listView.getFirstVisiblePosition();
        listView.getLastVisiblePosition();

五、 ListVIew的点击事件

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initName();
        SoccerAdapter soccerAdapter = new SoccerAdapter(MainActivity.this,R.layout.name_item,soccerList);
        ListView listView = findViewById(R.id.list_name);
        listView.setAdapter(soccerAdapter);
        
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    
    
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
    
    
                Soccer soccer = soccerList.get(position);
                Toast.makeText(MainActivity.this,soccer.getName(),Toast.LENGTH_LONG).show();
            }
        });
        
    }
使用setOnItenClickListener()方法为ListView注册了一个监听器,当用户点击了ListView中的任何一个子项时,都会回调onItemClick()方法,在该方法中通过判断用户点击了哪一个子项然后获取到相应的名字,并通过Toast将水果名字显现出来

猜你喜欢

转载自blog.csdn.net/Cristiano_san/article/details/120279484