UI界面编写(仿QQ聊天界面)

UI界面编写实战

这里我们模拟QQ聊天的主界面,编写一个简单的聊天界面。

项目描述

首先搭建我们的主界面,在最上边放一个标题栏,然后是一个ListView,用于展示发送的消息,最下边是选择要发送的表情,内容类型,一个发送框和一个发送按钮。
先写一个颜色的资源

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="light_blue">#18B4ED</color>
    <color name="gray">#EBECEE</color>
    <color name="white">#ffffff</color>
</resources>

然后就是主界面

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:background="@color/light_blue"
        android:padding="15dp"
      >
        <ImageView
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:src="@mipmap/jzw"
            />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="20sp"
            android:textColor="@color/white"
            android:text="消息"/>
        <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:textSize="25sp"
            android:textColor="@color/white"
            android:gravity="center"
            android:text="模拟聊天"
             />
        <ImageView
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:src="@mipmap/login_icon01"
            />
        <ImageView
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:src="@mipmap/personal_normal"
            android:layout_marginLeft="10dp"
            />

    </LinearLayout>
    <ListView
        android:id="@+id/listview"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:background="@drawable/chat_background"
        android:divider="#0000"></ListView>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:background="@color/gray"
        android:layout_margin="10dp"
        android:gravity="center">
        <ImageView
            android:id="@+id/biaoqing"
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:src="@mipmap/eol"/>
        <ImageView
            android:id="@+id/choose"
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:src="@mipmap/addcommodity"
            android:layout_marginLeft="10dp"/>
        <EditText
            android:id="@+id/edittext"
            android:layout_width="0dp"
            android:layout_height="30dp"
            android:layout_weight="1"
            android:background="@color/white"
            android:layout_marginLeft="10dp"/>
        <Button
            android:id="@+id/send"
            android:layout_width="wrap_content"
            android:layout_height="30dp"
            android:text="发送"
            android:background="@drawable/button"
            android:layout_marginLeft="10dp"/>
    </LinearLayout>
</LinearLayout>

然后是我们的drawable文件的内容:
为发送按钮写了一个shape:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <corners android:radius="5dp"/>
    <solid android:color="@color/light_blue"/>
</shape>

为展示消息的ListVeiw设置一个背景,也是用一个渐变色。

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <gradient
        android:startColor="#ACE7EF"
        android:centerColor="#CAE0D9"
        android:endColor="#E7D9C5"
        android:angle="270"></gradient>
</shape>

为昵称前边的标签设置一个背景

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <corners android:radius="15dp"/>
    <solid android:color="#86D070"/>
    <padding android:left="20dp" android:right="20dp"/>
</shape>

接着,因为我们要发送和接收消息,让接收的消息呈现在左边,发送的消息呈现在右边,所以要为两边各写一个消息的布局。
左边的布局:

<?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">
    <TextView
        android:id="@+id/time"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:padding="10dp"
        android:text="星期五  14:29" />
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <ImageView
            android:id="@+id/touxiang"
            android:layout_width="60dp"
            android:layout_height="60dp"
            android:src="@mipmap/weheartit" />
        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:orientation="vertical">
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="horizontal">
                <TextView
                    android:id="@+id/title"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:background="@drawable/textbackground"
                    android:text="营长"
                    android:textColor="@color/white"
                    android:textSize="15sp" />
                <TextView
                    android:id="@+id/name"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:textSize="16sp"
                    android:text="美女"
                    android:layout_marginLeft="10dp"/>
            </LinearLayout>
            <TextView
                android:id="@+id/message"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginRight="60sp"
                android:layout_marginTop="10sp"
                android:background="@mipmap/eng"
                />
        </LinearLayout>
    </LinearLayout>
</LinearLayout>

右边的布局:

<?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">
    <TextView
        android:id="@+id/time"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:padding="10dp"
        android:text="星期五  14:29" />
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:gravity="right"
            android:orientation="vertical">
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:gravity="right"
                android:orientation="horizontal">
                <TextView
                    android:id="@+id/name"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:textSize="16sp"
                    android:text="美女"
                    android:layout_marginLeft="10dp"/>
                <TextView
                    android:id="@+id/title"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:background="@drawable/textbackground"
                    android:text="营长"
                    android:textColor="@color/white"
                    android:textSize="15sp" />
            </LinearLayout>
            <TextView
                android:id="@+id/message"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="60sp"
                android:layout_marginTop="10sp"
                android:background="@mipmap/qqright"
                />
        </LinearLayout>
        <ImageView
            android:id="@+id/touxiang"
            android:layout_width="60dp"
            android:layout_height="60dp"
            android:src="@mipmap/weheartit" />
    </LinearLayout>
</LinearLayout>

接着定义我们消息内容的实体类ChatMessage.java

/**
 * Created by Administrator on 2015/8/31.
 */
public class ChatMessage {
    private int touxiang;//头像
    private String title;//标签
    private String name;//昵称
    private String message;//消息内容
    private long time;//发送时间
    private int type;//消息类型,即左边或者右边

    public ChatMessage(int touxiang, String title, String name, String message, long time) {
        this.touxiang = touxiang;
        this.title = title;
        this.name = name;
        this.message = message;
        this.time = time;
    }

    public int getType() {
        return type;
    }

    public void setType(int type) {
        this.type = type;
    }

    public int getTouxiang() {
        return touxiang;
    }

    public void setTouxiang(int touxiang) {
        this.touxiang = touxiang;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public long getTime() {
        return time;
    }

    public void setTime(long time) {
        this.time = time;
    }
}

定义我们消息内容的适配器MessageAdapter

import android.text.Html;
import android.text.Spanned;
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.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;

/**
 * Created by Administrator on 2015/8/31.
 */
public class MessageAdapter extends BaseAdapter{

    private LayoutInflater inflater;
    private ArrayList<ChatMessage> data;
    private Html.ImageGetter getter;
    private static final int TYPE=2;
    public static final int MESSAGE_LEFT=0;
    public static final int MESSAGE_RIGHT=1;

    public MessageAdapter(LayoutInflater inflater, ArrayList<ChatMessage> data,Html.ImageGetter getter) {
        this.inflater = inflater;
        this.data = data;
        this.getter=getter;
    }

    @Override
    public int getViewTypeCount() {//得到当前缓存布局类型的数量
        return TYPE;//因为有左右两种布局,返回常量2
    }

    @Override
    public int getItemViewType(int position) {
        return data.get(position).getType();//返回当前布局的类型
    }

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

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

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ChatMessage chatMessage=data.get(position);
        View view=null;
        ViewHolder viewHolder;
        int type=getItemViewType(position);
        if(convertView==null){
            switch (type){
                case MESSAGE_LEFT:
                    view=inflater.inflate(R.layout.message,null);
                    break;
                case MESSAGE_RIGHT:
                    view=inflater.inflate(R.layout.message_right,null);
                    break;
                default:
                    break;
            }
            viewHolder=new ViewHolder();
            viewHolder.touxiang= (ImageView) view.findViewById(R.id.touxiang);
            viewHolder.title= (TextView) view.findViewById(R.id.title);
            viewHolder.name= (TextView) view.findViewById(R.id.name);
            viewHolder.message= (TextView) view.findViewById(R.id.message);
            viewHolder.time= (TextView) view.findViewById(R.id.time);
            view.setTag(viewHolder);
        }else {
            view=convertView;
            viewHolder= (ViewHolder) view.getTag();
        }
        viewHolder.touxiang.setImageResource(chatMessage.getTouxiang());
        viewHolder.title.setText(chatMessage.getTitle());
        viewHolder.name.setText(chatMessage.getName());
        Spanned spanned=Html.fromHtml(chatMessage.getMessage(),getter,null);
        viewHolder.message.setText(spanned);//因为内容可能添加表情,所以传入富文本
        SimpleDateFormat format= new SimpleDateFormat("EEE HH:mm");
        String time=format.format(new Date(chatMessage.getTime()));
        viewHolder.time.setText(time);//设置显示时间的格式
        return view;
    }
    
    class ViewHolder{
        ImageView touxiang;
        TextView title;
        TextView name;
        TextView message;
        TextView time;
    }
}

下面就要设置表情了,我们点击表情图片时,弹出一个PopupWindow,然后在里边设置一个GridView来显示我们的全部表情。
新建一个Gridview布局

<?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">
    <GridView
        android:id="@+id/expression"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:numColumns="4"></GridView>
</LinearLayout>

然后是表情的布局,就是一个ImageView:

<?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:gravity="center"
    android:orientation="vertical">
    <ImageView
        android:id="@+id/image_expression"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</LinearLayout>

然后我们定义表情的实体类Expression

/**
 * Created by Administrator on 2015/8/31.
 */
public class Expression {
    private int image;//设置一张表情的图片

    public int getImage() {
        return image;
    }

    public void setImage(int image) {
        this.image = image;
    }
}

接着我们写一个表情的适配器ExpressionAdapter

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import java.util.ArrayList;

/**
 * Created by Administrator on 2015/8/31.
 */
public class ExpressionAdapter extends BaseAdapter {
    private LayoutInflater inflater;
    private ArrayList<Expression> expressions;

    public ExpressionAdapter(LayoutInflater inflater, ArrayList<Expression> expressions) {
        this.inflater = inflater;
        this.expressions = expressions;
    }

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

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

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        Expression expression=expressions.get(position);
        View view =inflater.inflate(R.layout.biaoqing,null);
        ImageView image= (ImageView) view.findViewById(R.id.image_expression);
        image.setImageResource(expression.getImage());
        return view;
    }
}

接下来呢,为了美观,当我们点击加号图片时,弹出一个PopupWindow,里边放置两个RadioButton,让我们选择发送信息的类型。
定义这个布局:

<?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:gravity="center"
    android:orientation="horizontal">
    <RadioGroup
        android:id="@+id/radiogroup"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <RadioButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="receive"/>
        <RadioButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="send"/>
    </RadioGroup>
</LinearLayout>

最后就是我们主活动的代码了!

import android.app.Activity;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.text.Html;
import android.text.Spanned;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.PopupWindow;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import java.util.ArrayList;

public class MainActivity extends Activity {
    private EditText editText;
    private ArrayList<ChatMessage> data;
    private MessageAdapter adapter;
    private Html.ImageGetter getter;
    private ListView listView;
    private LayoutInflater inflater;
    private GridView gridView;
    private ArrayList<Expression> expressions;
    private ExpressionAdapter expressionAdapter;
    private View view;
    private View chooseView;
    private ImageView imageView;
    private ImageView choose;
    private String name;
    private ChatMessage chatMessage;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        editText = (EditText) findViewById(R.id.edittext);
        imageView = (ImageView) findViewById(R.id.biaoqing);
        choose = (ImageView) findViewById(R.id.choose);
        Button send = (Button) findViewById(R.id.send);
        listView = (ListView) findViewById(R.id.listview);
        inflater = getLayoutInflater();
        view = inflater.inflate(R.layout.expression, null);
        chooseView = inflater.inflate(R.layout.sendreceive, null);
        data = new ArrayList<>();

        imageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                PopupWindow popupWindow = new PopupWindow(MainActivity.this);
                popupWindow.setWidth(ViewGroup.LayoutParams.MATCH_PARENT);
                popupWindow.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
                popupWindow.setContentView(view);
                popupWindow.setFocusable(true);
                popupWindow.setOutsideTouchable(true);
                popupWindow.update();
                popupWindow.showAtLocation(view, Gravity.CENTER, 0, 400);
            }
        });
        gridView = (GridView) view.findViewById(R.id.expression);
        expressions = new ArrayList<>();
        initExpression();
        expressionAdapter = new ExpressionAdapter(inflater, expressions);
        getter = new Html.ImageGetter() {
            @Override
            public Drawable getDrawable(String source) {
                Drawable drawable = getResources().getDrawable(Integer.parseInt(source));
                drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
                return drawable;
            }
        };
        gridView.setAdapter(expressionAdapter);
        gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Spanned spanned = Html.fromHtml("<img src='" + expressions.get(position).getImage() + "'/>", getter, null);
                //将表情插入到光标所在位置
                editText.getText().insert(editText.getSelectionStart(), spanned);
            }
        });

        choose.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                PopupWindow popupWindow = new PopupWindow(MainActivity.this);
                popupWindow.setWidth(ViewGroup.LayoutParams.MATCH_PARENT);
                popupWindow.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
                popupWindow.setContentView(chooseView);
                popupWindow.setFocusable(true);
                popupWindow.setOutsideTouchable(true);
                popupWindow.update();
                popupWindow.showAtLocation(view, Gravity.CENTER, 0, 450);
            }
        });
        RadioGroup radioGroup = (RadioGroup) chooseView.findViewById(R.id.radiogroup);
        radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(RadioGroup group, int checkedId) {
                RadioButton radioButton = (RadioButton) chooseView.findViewById(checkedId);
                name = (String) radioButton.getText();
            }
        });

        send.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (name.equals("send")) {
                    String message = filterHtml(Html.toHtml(editText.getText()));
                    chatMessage = new ChatMessage(R.mipmap.weheartit, "老大", "巴黎铁塔前的黎明", message, System.currentTimeMillis());
                    chatMessage.setType(MessageAdapter.MESSAGE_RIGHT);
                } else if (name.equals("receive")) {
                    String message = filterHtml(Html.toHtml(editText.getText()));
                    chatMessage = new ChatMessage(R.mipmap.weheartit, "老二", "东京樱花后的黄昏", message, System.currentTimeMillis());
                    chatMessage.setType(MessageAdapter.MESSAGE_LEFT);
                }
                data.add(chatMessage);
                adapter.notifyDataSetChanged();
                listView.setSelection(data.size());//将ListView定位到最后一行
                editText.setText("");//清空输入框的内容
            }
        });
        adapter = new MessageAdapter(inflater, data, getter);
        listView.setAdapter(adapter);
    }


    /**
     * 将文本转化为HTML格式后,发送的时候去掉除富文本以外的内容
     *
     * @param str 转化为HTML格式的字符串
     * @return 富文本
     */
    public String filterHtml(String str) {
        str = str.replaceAll("<(?!br|img)[^>]+>", "").trim();
        return str;
    }
	
	/**
	 *初始化表情
	 */
    private void initExpression() {
        Expression expression1 = new Expression();
        expression1.setImage(R.mipmap.ebg);
        expressions.add(expression1);
        Expression expression2 = new Expression();
        expression2.setImage(R.mipmap.ebh);
        expressions.add(expression2);
        Expression expression3 = new Expression();
        expression3.setImage(R.mipmap.ebl);
        expressions.add(expression3);
        Expression expression4 = new Expression();
        expression4.setImage(R.mipmap.ebo);
        expressions.add(expression4);
        Expression expression5 = new Expression();
        expression5.setImage(R.mipmap.ebw);
        expressions.add(expression5);
        Expression expression6 = new Expression();
        expression6.setImage(R.mipmap.eca);
        expressions.add(expression6);
        Expression expression7 = new Expression();
        expression7.setImage(R.mipmap.ecb);
        expressions.add(expression7);
        Expression expression8 = new Expression();
        expression8.setImage(R.mipmap.ecc);
        expressions.add(expression8);
        Expression expression9 = new Expression();
        expression9.setImage(R.mipmap.eew);
        expressions.add(expression9);
    }
}

好了,至此大功告成!让我们测试一下结果吧!
##运行结果:
首先是我们的界面
这里写图片描述
然后点击加号,选择我们要发送的类型,选择send
这里写图片描述
输入发送内容,点击表情,选择要发送的表情
这里写图片描述
点击发送
这里写图片描述
最后的效果:
这里写图片描述

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值