Android开发——控件_ListView
来源:互联网 发布:手机吉他教学软件 编辑:程序博客网 时间:2024/05/08 04:52
- 属性
- 初见ListView
- 深入ListView
- 定义适配器的适配类Msg
- 创建子项的布局msg_item
- 创建适配器类MsgAdapter
- 主活动的布局activity_main
- 编写主活动MainActivity类
- ListView的点击事件
- 实时更新
- 子项获得焦点
- ListView中嵌入ListView
- ListView中将某一行滚动到第一行
当要显式的数据很多时,屏幕无法完全装下,这时就要用到控件ListView。只需在屏幕上滑动,未在屏幕显示的数据将滚动到屏幕内。
属性
android:divider="#fffff" 分割线颜色android:dividerHeight="1px" 分割线高度
初见ListView
创建项目,项目名称为ListView_simple。
- 首先,在布局文件中添加控件ListView
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent"> <ListView android:id="@+id/simple_list_view" android:layout_width="match_parent" android:layout_height="match_parent" /></RelativeLayout>
- 然后,修改主活动MainActivity类
我们需要向上面的ListView提供要显示的数据。首先准备好这样一组数据,比如下面示例中的字符串数组data。然后通过adapter向ListView传递数据。
package com.example.victoria.listview_simple;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.widget.ArrayAdapter;import android.widget.ListView;public class MainActivity extends AppCompatActivity { private ListView simpleListView; private String[] data = {"apple", "banana", "orange", "watermalon", "lemon", "mango", "cherry", "pear", "peach", "apple", "grape"};//希望显示在屏幕上的一组数据 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ArrayAdapter<String> adapter = new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_list_item_1, data);//创建适配器:第二个参数表示子项布局的id,这里传入的android.R.layout.simple_list_item_1是内置布局 simpleListView = (ListView) findViewById(R.id.simple_list_view); simpleListView.setAdapter(adapter);//通过adapter向ListView传递数据 }}
深入ListView
这里使用《第一行代码》第三章的聊天例子。消息是一条条显示在屏幕上的,而且屏幕一般无法显示所有的聊天记录,这里就可以用到ListView。
- 首先,创建nine patch图片作为消息的背景
参考绘制nine patch图片
得到图片message_left.9.png和message_right.9.png。
定义适配器的适配类Msg
类Msg相当于初见ListView中的String类型,存储的是想要展示的子项的内容。
package com.example.victoria.myapplication;public class Msg{ //消息的实体类 public static final int TYPE_RECEIVED = 0; //属于类的不可变变量 public static final int TYPE_SEND = 1; private String content; //消息内容 private int type; //消息类型,可以是TYPE_RECEIVED或者TYPE_SEND public Msg(String content, int type){ this.content = content; this.type = type; } public String getContent(){ return content; } public int getType(){ return type; }}
在创建适配器实例时,需要把一组Msg传给适配器构造函数。
创建子项的布局msg_item
<?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" android:padding="10dp"> <LinearLayout android:id="@+id/left_layout" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="left" android:background="@drawable/message_left"> <TextView android:id="@+id/left_msg" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_margin="10dp" android:textColor="#fff"/> </LinearLayout> <LinearLayout android:id="@+id/right_layout" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="right" android:background="@drawable/message_right"> <TextView android:id="@+id/right_msg" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_margin="10dp" android:textColor="#fff"/> </LinearLayout></LinearLayout>
这里包含左右两个LinearLayout,因为聊天消息是以一个接收消息和一个发送消息(或者反过来)为一个显示单位的,聊天记录就是重复显式接收-发送对。
但是消息毕竟是一条一条的,接受-发送之间应该是独立的。如何控制其独立性?答案是通过设置控件的可见属性。
创建适配器类MsgAdapter
继承自ArrayAdapter类,泛型指定为Msg。
重写父类的构造函数:
public MsgAdapter(Context context, int textViewResourceId, List < Msg > objects):
context:
textViewResourceId:子项布局id
objects:待显示消息列表
重写getView方法
这个方法在每个子项被滚动到屏幕内的时候被调用,用于返回每个位置应该显示的子项。首先通过参数textResourceId动态加载子项布局,然后按id读取子项布局中的控件或者布局,根据提供的消息数据设置它们的属性。
这里有两处重复操作,一个是加载子项布局,一个是按id取出子项布局的控件或者嵌套布局。前者可以通过使用convertView参数进行优化,因为converView中缓存了子项布局;后者可以通过定义类ViewHolder进行优化,ViewHolder中存储了控件实例,通过把view的tag设为ViewHolder方便后面直接读取。
package com.example.victoria.myapplication;import android.content.Context;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.ArrayAdapter;import android.widget.LinearLayout;import android.widget.TextView;import java.util.List;/** * Created by victoria on 2017/2/6. */public class MsgAdapter extends ArrayAdapter<Msg> { private int resourceId; public MsgAdapter(Context context, int textViewResourceId, List<Msg> objects) { super(context, textViewResourceId, objects); resourceId = textViewResourceId; //子项布局的id } @Override public View getView(int position, View convertView, ViewGroup parent){ //convertView参数的目的是把之前加载好的布局缓存以便之后可以重用 Msg msg = (Msg) getItem(position); /*******************************************************************************/ /*经过两个优化操作,加载子项布局以及读取控件实例*/ View view; ViewHolder viewHolder; //viewHolder的目的是避免重复获取控件实例 if(convertView == null){ //没有缓存子项布局:缓存子项布局 view = LayoutInflater.from(getContext()).inflate(resourceId, null); //动态加载一个布局文件,inflate方法的两个参数分别代表加载的布局文件的id、给加载的布局再添加一个父布局。 viewHolder = new ViewHolder(); viewHolder.leftLayout = (LinearLayout) view.findViewById(R.id.left_layout); viewHolder.rightLayout = (LinearLayout) view.findViewById(R.id.right_layout); viewHolder.leftMsg = (TextView) view.findViewById(R.id.left_msg); viewHolder.rightMsg = (TextView) view.findViewById(R.id.right_msg); view.setTag(viewHolder); //把子项布局的控件以更简单的格式保存到view自身,方面后面直接的读取,而不用每次都要按id获取控件实例 }else{//有缓存的子项布局 view = convertView; viewHolder = (ViewHolder) view.getTag(); } /*******************************************************************************/ /*******************************************************************************/ /*根据消息Msg数据设置控件属性*/ if(msg.getType() == Msg.TYPE_RECEIVED){ viewHolder.leftLayout.setVisibility(View.VISIBLE); viewHolder.rightLayout.setVisibility(View.GONE); viewHolder.leftMsg.setText(msg.getContent()); }else if(msg.getType() == Msg.TYPE_SEND){ viewHolder.rightLayout.setVisibility(View.VISIBLE); viewHolder.leftLayout.setVisibility(View.GONE); viewHolder.rightMsg.setText(msg.getContent()); } /*******************************************************************************/ return view; } class ViewHolder{ LinearLayout leftLayout; LinearLayout rightLayout; TextView leftMsg; TextView rightMsg; }}
主活动的布局activity_main
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <ListView android:id="@+id/msg_list_view" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:divider="#0000"> </ListView> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <EditText android:id="@+id/input_text" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:hint="something here" android:maxLines="2"/> <Button android:id="@+id/send" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Send"/> </LinearLayout></LinearLayout>
编写主活动MainActivity类
提供Msg数据列表,并通过适配器向ListView传递数据。
package com.example.victoria.myapplication;import android.net.Uri;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.view.View;import android.view.Window;import android.widget.Button;import android.widget.EditText;import android.widget.ListView;import com.google.android.gms.appindexing.Action;import com.google.android.gms.appindexing.AppIndex;import com.google.android.gms.appindexing.Thing;import com.google.android.gms.common.api.GoogleApiClient;import java.util.ArrayList;import java.util.List;public class MainActivity extends AppCompatActivity { private ListView msgListView; private EditText inputText; private Button send; private MsgAdapter adapter; private List<Msg> msgList = new ArrayList<Msg>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_main); /*******************************************************************************/ /*通过适配器向ListView传递数据*/ initMsg();//提供待显示数据 adapter = new MsgAdapter(MainActivity.this, R.layout.msg_item, msgList);#创建适配器 msgListView = (ListView) findViewById(R.id.msg_list_view); msgListView.setAdapter(adapter); /*******************************************************************************/ inputText = (EditText) findViewById(R.id.input_text); /*******************************************************************************/ /*为Button的点击事件注册监听器:当点击按钮时,获取EditText控件中的内容,并添加到消息列表中,并通知ListView有新消息需要显示*/ send = (Button) findViewById(R.id.send); send.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String content = inputText.getText().toString();//获取编辑内容 if(! "".equals(content)){ Msg msg = new Msg(content, Msg.TYPE_SEND); msgList.add(msg); adapter.notifyDataSetChanged();//当有新消息时,刷新ListView中的显示 msgListView.setSelection(msgList.size());//将显式的数据定位到最后一行,以确保一定可以看到最后一行消息 inputText.setText(""); //清空输入框中的内容 } } }); /*******************************************************************************/ } private void initMsg(){ Msg msg1 = new Msg("hello guy.", Msg.TYPE_RECEIVED); msgList.add(msg1); Msg msg2 = new Msg("hi. who is that?.", Msg.TYPE_SEND); msgList.add(msg2); Msg msg3 = new Msg("victoria.", Msg.TYPE_RECEIVED); msgList.add(msg3); Msg msg4 = new Msg("bye", Msg.TYPE_SEND); msgList.add(msg4); }}
ListView的点击事件
video_list.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { VideoInfo video = videoList.get(position); Intent intent = new Intent(VideoList.this, PlayVideo.class); intent.putExtra("data", "video.data"); startActivity(intent); }});
实时更新
adapter.notifyDatasetChanged();
子项获得焦点
在子项目布局文件中的根布局中添加
android:descendantFocusability="blocksDescendants"
ListView中嵌入ListView
在ListView中嵌入ListView的时候,发现嵌入的ListView无法显式完全。可以通过统计每个子项的高度来确定ListView应该有多高:
public class Utility { public static void setListViewHeightBasedOnChildren(ListView listView) { ListAdapter listAdapter = listView.getAdapter(); if (listAdapter == null) { // pre-condition return; } int totalHeight = 0; for (int i = 0; i < listAdapter.getCount(); i++) { View listItem = listAdapter.getView(i, null, listView); listItem.measure(0, 0); totalHeight += listItem.getMeasuredHeight(); } ViewGroup.LayoutParams params = listView.getLayoutParams(); params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1)); listView.setLayoutParams(params); }}
在对ListView设置好适配器后,将其传入此静态方法。
ListView中将某一行滚动到第一行
比如一个菜单应用,左边显示食物种类,右边具体的食物。当点击左边的某个种类时,右边对应的食物应该滑动到第一行开始显式。
- Android开发——控件_ListView
- Android开发_ListView跑马灯
- 15_C# 实现VMS客户端——控件_ListView
- Android控件_ListView优化[分批加载]
- Android_自定义控件_ListView侧滑删除
- 写给初学者16_android_常用控件_ListView
- Android开发——Chronometer计时器控件
- Android开发技巧——自定义控件之组合控件
- Android 界面—UI开发控件
- Android 界面—UI 开发控件
- iOS开发系列之常用自定义控件开发集—Android的Toast控件开发
- [android开发教程] 新手入门—Android控件入门知识分享
- Android成长之路-Android组件_ListView例子小解
- android学习笔记---64_ListView数据异步加载与AsyncTask
- Android错误之ListView加载错位_ListView图片错位
- Android开发——文本控件——Textview
- 《Android开发从零开始》——4.TextView控件学习
- 《Android开发从零开始》——5.EditText控件学习
- PAT甲级练习1007. Maximum Subsequence Sum (25)
- vue-prop父组件向子组件进行传值
- UINavigationBar和UINavigationItem的区别和联系
- 用Java连接sqlserver数据库引包后仍出现“java.lang.ClassNotFoundException”错误解决方法
- 1023. Have Fun with Numbers (20)
- Android开发——控件_ListView
- hdu 1078 记忆化搜索
- 2 eclipse安装插件的四种方式
- The usage Color State List Resource
- 开源大数据查询分析引擎现状
- android studio使用记录
- 手机OCR
- 使用fastjson出现json中键值与属性名不一致
- 云端开发随思