刚开始接触到ListView,总是看见别人做出来很多稀奇古怪的界面自己就是不会,随后学习到了自定义View,就想着ListView也可以自定义出想要的样式,然后在网上搜集很多的的方法,要不就是看不懂,代码复制出来还无运行,要么就是不是自己想要的那款。今天在这里使用的不需要自定义ListView控件,e而是利用ListView自带的控件就能完成。

我们熟知的QQ、微信界面,至少会展示两种界面,有双方发送消息的版面,只要大家勤于动脑,我相信如果你看了今天我的方法,可以在ListView上添加两种以上的布局。老师不会告诉你,老师只是将你带入门,让你了解程序,认识程序,编写程序,其他的技能提升需要的是自己不断的提出问题,向别人提出问题,回答别人的问题,这样就会得到很多答案。

一个与我们平时所使用的ListView不同,就是它拥有2个不同的布局——收到的布局和发送的布局,如果需要实现这样的效果,必须要拿Adapter开头,在定义BaseAdapter时,需要重写getView()方法,需要哪种布局,只要判断一下获取哪种布局就可以了,ListView在设计的时候就已经考虑到这样的情况,所以提供的两个方法。

public int getItemView(int position){}   返回第position的item是何种类型

public  int getViewTypeCount(){}; 返回不同布局的总数

1. 效果图

2 设计两个布局文件,就是所谓的接收布局和发送布局,由于两个布局文件基本都是一样的,不同的只是控件的位置不同,还有就是现实的图片的方位不同,适配图片请选用九宫图片适配。这里只列出一种布局文件

<?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"
    android:gravity="center_vertical"
    android:padding="10dp">
    <ImageView
        android:id="@+id/icon_in"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:src="@drawable/ic_launcher_background"/>
    <TextView
        android:id="@+id/text_in"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:textSize="20sp"
        android:textColor="#DF0606"
        android:gravity="center"
        android:background="@drawable/popoleft"
        android:text="打开工单各大品牌地方公开董鹏飞水电费控股电饭锅电饭锅"/>
</LinearLayout>

3 聊天内容,便于在Adapter中获取对象,我们需要封装一个javaBean对象,用来保存聊天的记录信息

package com.example.demod6;
import android.graphics.Bitmap;
public class ChatItemListViewBean {
    private int type;
    private String text;
    private Bitmap icon;
    public int getType() {
        return type;
    public void setType(int type) {
        this.type = type;
    public String getText() {
        return text;
    public void setText(String text) {
        this.text = text;
    public Bitmap getIcon() {
        return icon;
    public void setIcon(Bitmap icon) {
        this.icon = icon;

4 最重要的就是BaseAdapter类了,同样使用ViewHolder模式来提高ListView的效率,并在getView()方法中进行布局类型的判断,从而确定使用哪种布局。

package com.example.demod6;
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;
import java.util.List;
public class ViewHolderView extends BaseAdapter {
    private List<ChatItemListViewBean> mData;
    private LayoutInflater inflater;
    public ViewHolderView(List<ChatItemListViewBean> mData, Context context) {
        this.mData = mData;
        inflater = LayoutInflater.from(context);
    @Override
    public int getCount() {
        return mData.size();
    @Override
    public Object getItem(int i) {
        return mData.get(i);
    @Override
    public long getItemId(int i) {
        return i;
    @Override
    public View getView(int position, View contentView, ViewGroup viewGroup) {
        ViewHolder holder = null;
        if(contentView == null){
            if(getItemViewType(position) == 0){
                holder = new ViewHolder();
                contentView = inflater.inflate(R.layout.chat_item_in,null);
                holder.imageView = (ImageView) contentView.findViewById(R.id.icon_in);
                holder.title = (TextView) contentView.findViewById(R.id.text_in);
            }else {
                holder = new ViewHolder();
                contentView = inflater.inflate(R.layout.chat_item_out,null);
                holder.imageView = (ImageView) contentView.findViewById(R.id.icon_in);
                holder.title = (TextView) contentView.findViewById(R.id.text_in);
            contentView.setTag(holder);
        }else {
            holder = (ViewHolder) contentView.getTag();//通过tag缓存找到对像
        holder.imageView.setImageBitmap(mData.get(position).getIcon());
        holder.title.setText(mData.get(position).getText());
        return contentView;
    @Override
    public int getViewTypeCount() { //返回地position是何种类型
        return 2;
    @Override
    public int getItemViewType(int position) { //返回不同布局的总数
        ChatItemListViewBean bean = mData.get(position);
        return bean.getType();
    public class ViewHolder{
        public ImageView imageView;
        public TextView title;

6 实现ListView中多個佈局,就需要添加一些测试代码

package com.example.demod6;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.animation.ObjectAnimator;
import android.app.ActionBar;
import android.app.Activity;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.AbsListView;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
    private List<ChatItemListViewBean> mData = new ArrayList<ChatItemListViewBean>();
    private int mTouchSlop;
    private  TextView header;
    private TextView toolBar;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        toolBar = (TextView) findViewById(R.id.img);
        MyListView myListView = (MyListView) findViewById(R.id.listView);
       initListView();
        ViewHolderView adapter = new ViewHolderView(mData,this);
        myListView.setAdapter(adapter);
//        header = new View(this);
        header = new TextView(this);
        header.setText("恭喜今天你和程辽辽成为好朋友");
        header.setTextColor(Color.GREEN);
        header.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
        header.setLayoutParams(new AbsListView.LayoutParams(AbsListView.LayoutParams.MATCH_PARENT, (int) getResources().getDimension(R.dimen.height)));
        myListView.addHeaderView(header); //标题头
        mTouchSlop = ViewConfiguration.get(this).getScaledTouchSlop(); //最低滑动距离
        //toolBar = getActionBar();
        myListView.setOnTouchListener(myTouchListenner);
    private void initListView() {
        ChatItemListViewBean bean1 = new ChatItemListViewBean();
        bean1.setIcon(BitmapFactory.decodeResource(getResources(),R.drawable.m1));
        bean1.setType(0);
        bean1.setText("嗨,你好,我在XXXX网站上看见你发的帖子,请问是单身吗?");
        ChatItemListViewBean bean2 = new ChatItemListViewBean();
        bean2.setIcon(BitmapFactory.decodeResource(getResources(),R.drawable.m2));
        bean2.setType(1);
        bean2.setText("是呀?这个与你有何干系。");
        ChatItemListViewBean bean3 = new ChatItemListViewBean();
        bean3.setIcon(BitmapFactory.decodeResource(getResources(),R.drawable.m1));
        bean3.setType(0);
        bean3.setText("是这样的,刚好我也单着,我看你各项条件都不错,对米有意。");
        ChatItemListViewBean bean4 = new ChatItemListViewBean();
        bean4.setIcon(BitmapFactory.decodeResource(getResources(),R.drawable.m2));
        bean4.setType(1);
        bean4.setText("我的各项条件真的正如你所说,很不错的。");
        ChatItemListViewBean bean5 = new ChatItemListViewBean();
        bean5.setIcon(BitmapFactory.decodeResource(getResources(),R.drawable.m1));
        bean5.setType(0);
        bean5.setText("我是一名打工族,最近家里老是催婚,家里介绍的那个是我一点都不喜欢,在深圳这边打工,很无奈。");
        ChatItemListViewBean bean6 = new ChatItemListViewBean();
        bean6.setIcon(BitmapFactory.decodeResource(getResources(),R.drawable.m2));
        bean6.setType(1);
        bean6.setText("那你做什么工作的?");
        ChatItemListViewBean bean7 = new ChatItemListViewBean();
        bean7.setIcon(BitmapFactory.decodeResource(getResources(),R.drawable.m1));
        bean7.setType(0);
        bean7.setText("前天被老板给开除,还不是因为家里那点事,惹的挺烦的,结果工作也弄丢了,还被罚了钱");
        ChatItemListViewBean bean8 = new ChatItemListViewBean();
        bean8.setIcon(BitmapFactory.decodeResource(getResources(),R.drawable.m2));
        bean8.setType(1);
        bean8.setText("看来挺糟糕的,那你准备回去吗?还是继续找新的工作?");
        ChatItemListViewBean bean9 = new ChatItemListViewBean();
        bean9.setIcon(BitmapFactory.decodeResource(getResources(),R.drawable.m1));
        bean9.setType(0);
        bean9.setText("哎!怎么说呢?前天去人才市场找工作,结果把钱弄丢了,现在钱只顾吃饭,在挺挺吧,等找到工作,就好了。");
        ChatItemListViewBean bean10 = new ChatItemListViewBean();
        bean10.setIcon(BitmapFactory.decodeResource(getResources(),R.drawable.m2));
        bean10.setType(1);
        bean10.setText("那你家在哪里?要不先回家后,在过一端事件再出来");
        ChatItemListViewBean bean11 = new ChatItemListViewBean();
        bean11.setIcon(BitmapFactory.decodeResource(getResources(),R.drawable.m1));
        bean11.setType(0);
        bean11.setText("我没钱回家,是钱不够,但是这边还是可以维持一段时间,下午我要去一个工厂面试。可能会在上班的。");
        mData.add(bean1);
        mData.add(bean2);
        mData.add(bean3);
        mData.add(bean4);
        mData.add(bean5);
        mData.add(bean6);
        mData.add(bean7);
        mData.add(bean8);
        mData.add(bean9);
        mData.add(bean10);
        mData.add(bean11);
    private int mFirstY = 0;
    private int currentY = 0;
    private int direction = 0;
    private boolean mShow = true;
    private ObjectAnimator mAnimator;
View.OnTouchListener myTouchListenner = new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, @NonNull MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                mFirstY = (int) event.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                currentY = (int) event.getY();
                if(currentY - mFirstY > mTouchSlop){
                    direction = 0; //向下
                }else if(mFirstY - currentY > mTouchSlop ){
                    direction = 1; //向上
                if(direction == 1){
                    if(mShow){
                        //header.setVisibility(View.GONE);
                        toolBarAnima(0);
                        mShow = !mShow;
                }else if(direction == 0){
                    if(!mShow){
                        //header.setVisibility(View.VISIBLE);
                        toolBarAnima(1);
                        mShow = !mShow;
                break;
        return false;
     * @param flag
    private void toolBarAnima(int flag){
        if(mAnimator != null && mAnimator.isRunning()){
            mAnimator.cancel();
        if(flag == 0){
            mAnimator = ObjectAnimator.ofFloat(toolBar,"translationY",toolBar.getTranslationY(),0);
        }else {
            mAnimator = ObjectAnimator.ofFloat(toolBar,"translationY",toolBar.getTranslationY(),-toolBar.getHeight());
        mAnimator.start();
 

轻轻松松完成模拟对话情景效果,赶快来试一试吧。

我们这么来分析: 整个聊天记录是一个listview,分为两种布局:发送的消息和收到的消息。 这里就是与平时使用的ListView有一个最大的不同:拥有两个不同的布局,在Adapter上下功夫! BaseAdapter中提供了两个方法: @Override public int getItemViewType(int position) 通常我们用惯的ListView每一项的布局都是相同的,只是控件所绑定的数据不同。但单单只是如此并不能满足我们某些特殊需求,比如我们常见的QQ、微信的聊天列表,除了有左右之分外,内容更是有很大区别,有文字、语音、图片、视频等等,他们真的是ListView可以实现的吗?答案是肯定的,只要我们做一下类型区别即可。实现效果如下所示:大家不要在意布局,这里为了方便就随意了。大家可以看到,这里有两种布局,一种... <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" 把生活的优质寄托于别人,一昧的祈求别人同情和怜悯,短时间可能会有所收获,但随着时间,同情和怜悯最终只会变成反感和厌恶。而真正能够改变自己命运的,只有自己努力。你若精彩,蝴蝶自来。 ——出自青坏坏语录大家还记得我们之前用BaseAdapter去实现Spinner的使用吗,其实适配器可以完成的工作不仅仅是Spinner的适配,还有很多控件都可以,比如我们今天要学习的ListVi... 最近搞一个项目,需要用到类似于新浪微博的消息流,即每一项有文字、有九宫格图片,因此这就涉及到ListView或者ScrollView嵌套GridView的问题。其中GridView的高度问题在网上都很容易找到答案,即覆写onMeasure方法,然后设置高度的MeasureSpec。但是宽度问题确实没有什么资料,这里所说的宽度问题是比如GridView的列数为3,那么即使只有一张图片,gridvie... 我正在Android上编写一个聊天客户端,但是在我的客户端中有一个聊天泡泡问题.我的聊天屏幕包括一个包含文本框的ListView和底部的发送按钮.对于外发消息,文本在ListView行中保持对齐.对于传入消息,文本在ListView行中对齐.但是,聊天泡泡不会调整到传入消息文本的长度.左对齐的传出消息不会发生此问题.这里的屏幕截图如下.聊天消息文本存储在数据库中,并通过光标适配器显示在ListVi... WPF仿微信界面发送消息简易版 参考别的博主的例子用WPF MVVM框架来仿了一个微信聊天界面,做了个发送消息简易功能,下面一起来看看吧! 以下为View视图布局代码,消息对话框的样式直接在这里定义了,主要定义的是用户头像、对话框和发送时间的样式,其中设置了文字消息自动换行。 <Window x:Class="DEMO.View.ChatWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 说说怎么实现的吧。打磨一个聊天气泡的想法由来已久。 WinForm 最开始用的WInForm,想重绘ListBox或者RichTextBox来做,可是借助万能的度娘也没找到思路,不熟... 2、Name: 程序里调用的名称,Text:表格里显示的信息,其它可以设置大小等信息。3、显示网格线 属性 GridLines --- True。1、点击表格右上角的三角形,添加表头信息。这样,一个listView就画出来了。4、往表格里填写数据,跟着来就可以了。5、改变背景颜色,和字体颜色。