Android学习-ListView
2016-02-17 16:59
393 查看
今天复习的内容是ListView,来做一个简单的仿微信的聊天界面
这是微信的界面
效果图
然后新建class,取名title,继承LinearLayout
因为没准备素材所以有一些偏差,不过大致上是出来了。
然后为ListView子项即聊天列表新建一个自定义布局,分为左右两种,左边的是收到的信息,右边的是发出的信息,所以对应着建两个LinearLayout
这里每次输入消息后,ListView中都会有新的子项,先调用adapter.notifyDataSetChanged()来刷新ListView,因为新加的消息是在ListView的最后一项,如果超出屏幕范围了,就不能显示出来,需要用户手动划到ListView的最后一项才能看到,所以需要再调用chat_list.setSelection(messages.size())将ListView定位到最后一行,保证新消息能显示出来。
最后效果图
TextView的字的位置有点问题,需要微调一下,不过主要的还是对ListView的练习。
这是微信的界面
自定义Layout
先写个自定义Layout来仿标题栏,新建一个title_layout.xml<?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="wrap_content" android:orientation="horizontal" android:background="#393a3e">//设置背景颜色 <ImageButton android:id="@+id/btn_title_back" android:layout_height="60dp" android:layout_width="60dp" android:padding="21dp"//控制返回按钮显示的大小 android:scaleType="centerInside"//图片缩放模式为居中缩放 android:src="@drawable/back" android:background="#393a3e"/> <View android:layout_height="25dp" android:layout_width="1dp" android:layout_gravity="center_vertical" android:background="#000000"/>//设置back与名字中间的分割线 <TextView android:layout_height="wrap_content" android:layout_width="0dp" android:textSize="20sp" android:paddingLeft="5dp" android:layout_gravity="center_vertical" android:textColor="#FFFF" android:layout_weight="1" android:text="小冰"/> <ImageButton android:layout_height="match_parent" android:layout_width="wrap_content" android:scaleType="centerInside" android:padding="17dp" android:src="@drawable/people" android:background="#393a3e"/> </LinearLayout>
效果图
然后新建class,取名title,继承LinearLayout
public class title extends LinearLayout{ public title(Context context, AttributeSet attrs) {//重写2个参数的构造函数 super(context, attrs); // TODO Auto-generated constructor stub LayoutInflater.from(context).inflate(R.layout.title_layout, this);//动态加载布局文件,用LayoutInflater.from()构建LayoutInflater对象,再调用它的inflate()方法来加载布局,它的第一个参数是要加载的布局文件,第二个参数是它的父布局 ImageButton back=(ImageButton)findViewById(R.id.btn_title_back);//这里是ImageButton,之前写成了Button,一直报错,要仔细 back.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub ((Activity)getContext()).finish();//给back键动作,关掉这个activity } }); } }
主界面
接下来写聊天界面的布局,总共包含一个自定义的title,一个ListView,一个语音的Button,这里用来接收消息,一个EditText用来输入聊天信息,一个Button加号,就是微信里面的更多,这里用来发送消息,效果如图因为没准备素材所以有一些偏差,不过大致上是出来了。
定制ListView界面
布局写完了就该写ListView里面的东西了,先建一个类来储存聊天列表里的信息,包括消息的类型(收到的和发出的),头像,以及聊天的内容public class Message { public static final int RECEIVE=0; public static final int SEND=1;//用来代表消息的类型 private String content; private int type;//消息的类型 private int imageId; public String getContent() { return content; } public int getType() { return type; } public int getImageId() { return imageId; } public Message(int type,int imageId,String content) { this.content=content; this.imageId=imageId; this.type=type; 4000 } }
然后为ListView子项即聊天列表新建一个自定义布局,分为左右两种,左边的是收到的信息,右边的是发出的信息,所以对应着建两个LinearLayout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:background="#ebebeb" > <LinearLayout//收到的消息 android:id="@+id/receive_layout" android:layout_height="wrap_content" android:layout_width="match_parent" android:orientation="horizontal"> <ImageView android:id="@+id/left_image" android:layout_width="60dp" android:layout_height="60dp" android:padding="10dp" /> <TextView android:id="@+id/left_content" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="-5dp" android:singleLine="false" android:maxEms="12" android:padding="10dp" android:textSize="15sp" android:layout_marginTop="10dp" android:background="@drawable/receive_bg" /> </LinearLayout> <LinearLayout //发出去的消息 android:id="@+id/send_layout" android:layout_height="wrap_content" android:gravity="right" android:layout_width="match_parent" android:orientation="horizontal"> <TextView android:id="@+id/right_content" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginRight="-5dp" android:singleLine="false" android:maxEms="12" android:padding="10dp" android:textSize="15sp" android:layout_marginTop="10dp" android:background="@drawable/send_bg" /> <ImageView android:id="@+id/right_image" android:layout_width="60dp" android:layout_height="60dp" android:padding="10dp" /> </LinearLayout> </LinearLayout>
自定义适配器MessageAdapter
然后就是写适配器,继承ArrayAdapter,泛型为之前创建的Messagepublic class MessageAdapter extends ArrayAdapter<Message>{ private int resId; public MessageAdapter(Context context, int resource, List<Message> objects) { super(context, resource, objects); // TODO Auto-generated constructor stub resId=resource; } @Override public View getView(int position, View convertView, ViewGroup parent) {//使listview的子项一出现在屏幕上就会调用这个方法来显示 // TODO Auto-generated method stub Message message=getItem(position); View view; ViewHolder viewHolder; if (convertView==null) {//判断上一个子项加载后的缓存是否为空,若不为空,就可以直接调用之前的,节省内存 view=LayoutInflater.from(getContext()).inflate(resId, null);//加载传入的布局 viewHolder=new ViewHolder(); viewHolder.left_layou=(LinearLayout)view.findViewById(R.id.receive_layout); viewHolder.right_layout=(LinearLayout)view.findViewById(R.id.send_layout); viewHolder.left_content=(TextView)view.findViewById(R.id.left_content); viewHolder.right_content=(TextView)view.findViewById(R.id.right_content); viewHolder.left_image=(ImageView)view.findViewById(R.id.left_image); viewHolder.right_image=(ImageView)view.findViewById(R.id.right_image); view.setTag(viewHolder);//将设置好的viewHolder放入缓存,以便下次使用 }else { view=convertView; viewHolder=(ViewHolder)view.getTag(); }if (message.getType()==Message.RECEIVE) {//判断显示哪一个LinearLayout viewHolder.left_layou.setVisibility(View.VISIBLE); viewHolder.right_layout.setVisibility(View.GONE); viewHolder.left_content.setText(message.getContent()); viewHolder.left_image.setImageResource(message.getImageId()); }else { viewHolder.right_layout.setVisibility(View.VISIBLE); viewHolder.left_layou.setVisibility(View.GONE); viewHolder.right_content.setText(message.getContent()); viewHolder.right_image.setImageResource(message.getImageId()); } return view; } @Override public boolean isEnabled(int position) {//设置子项不可点击 // TODO Auto-generated method stub return false; } class ViewHolder{//用来管理需要加载的控件以及布局 LinearLayout left_layou; LinearLayout right_layout; TextView left_content; TextView right_content; ImageView left_image; ImageView right_image; } }
在Activity中调用、更新逻辑
接下来就是在activity中去调用了public class fuxi extends Activity implements OnClickListener{ private ImageButton btn_receive; private ImageButton btn_send; private ListView chat_list; private EditText et_content; private List<Message> messages=new ArrayList<Message>();//新建Message的list,待会儿用来传入adapter private MessageAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.chat); initView();//初始化控件 initMessage();//初始化聊天内容,这里一边放入一个你好 adapter=new MessageAdapter(this, R.layout.chat_list, messages); chat_list.setAdapter(adapter); } private void initView() { btn_receive=(ImageButton)findViewById(R.id.btn_receive); btn_send=(ImageButton)findViewById(R.id.btn_send); chat_list=(ListView)findViewById(R.id.chat_list); et_content=(EditText)findViewById(R.id.chat_content); btn_receive.setOnClickListener(this); btn_send.setOnClickListener(this); } private void initMessage() { Message message1=new Message(Message.RECEIVE, R.drawable.receive, "你好"); messages.add(message1); Message message2=new Message(Message.SEND, R.drawable.send, "你好"); messages.add(message2); } @Override public void onClick(View v) { // TODO Auto-generated method stub String content=et_content.getText().toString(); switch (v.getId()) { case R.id.btn_receive://之前语音图标的Button用来接收消息,模拟别人发过来消息 if (!TextUtils.isEmpty(content)) { Message message=new Message(Message.RECEIVE, R.drawable.receive, content); messages.add(message); adapter.notifyDataSetChanged(); chat_list.setSelection(messages.size());//刷新列表 et_content.setText("");//清空输入框 } break; case R.id.btn_send://之前加号图标的Button,这里用作发送 if (!TextUtils.isEmpty(content)) { Message message=new Message(Message.SEND, R.drawable.send, content); messages.add(message); adapter.notifyDataSetChanged(); chat_list.setSelection(messages.size()); et_content.setText(""); } break; default: break; } } }
这里每次输入消息后,ListView中都会有新的子项,先调用adapter.notifyDataSetChanged()来刷新ListView,因为新加的消息是在ListView的最后一项,如果超出屏幕范围了,就不能显示出来,需要用户手动划到ListView的最后一项才能看到,所以需要再调用chat_list.setSelection(messages.size())将ListView定位到最后一行,保证新消息能显示出来。
最后效果图
TextView的字的位置有点问题,需要微调一下,不过主要的还是对ListView的练习。
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories