编写界面的最佳实践——聊天界面

        既然是要编写一个聊天界面,那就肯定要有收到的消息和发出的消息。通过 nine-patch 制作 message_left.9.png 和 message_right.9.png 可以作为收到消息的背景图和发出消息的背景图。

        图片都提供好了之后就可以开始编码了,首先还是编写主界面,修改 activity_main.xml 中的代码,如下所示:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent"  
    android:background="#d8e0e8"  
    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="Type somthing here"  
            android:maxLines="2" />  
  
        <Button  
            android:id="@+id/send"  
            android:layout_width="wrap_content"  
            android:layout_height="wrap_content"  
            android:text="Send" />  
          
    </LinearLayout>  
  
</LinearLayout>  

        这里在主界面中放置一个 ListView 用于显示聊天的消息内容,又放置了一个 EditText 用于输入消息,还放置了一个 Button 用于发送消息。ListView 中用到了一个 Android:divider 属性,它可以指定 ListView 分隔线的颜色,这里 #0000 表示将分割线设为透明色

        然后我们来定义消息的实体类,新建 Msg,代码如下所示:

public class Msg {  
  
    public static final int TYPE_RECEIVED = 0;  
  
    public static final int TYPE_SENT = 1;  
  
    private String content;  
  
    private int type;  
  
    public Msg(String content, int type) {  
        this.content = content;  
        this.type = type;  
    }  
  
    public String getContent() {  
        return content;  
    }  
  
    public int getType() {  
        return type;  
    }  
} 

       Msg 类中只有两个字段,content 表示消息的内容,type 表示消息的类型。其中消息类型有两个值可选,TYPE_RECEIVED 表示这是一条收到的消息,TYPE_SENT 表示这是一条发出的消息。

        接着来编写 ListView 子项的布局,新建 msg_item.xml,代码如下所示:

<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" />  
    </LinearLayout>  
  
</LinearLayout> 

        这里我们让收到的消息居左对齐,发出的消息居右对齐,并且分别使用 message_left.9.png 和 mesage_right.9.png 作为背景图。你可能会有些疑虑,怎么能让收到的消息和发出的消息都放在同一个布局里呢?不用担心,还记得可见属性吗,只要稍后在代码中根据消息的类型来决定隐藏和显示哪种消息就可以了

        接下来需要创建 ListView 的适配器类,让它继承自 ArrayAdapter,并将泛型指定为 Msg 类。新建类 MsgAdapter,代码如下所示:

public class MsgAdapter extends ArrayAdapter<Msg> {  
  
    private int resourceId;  
  
    public MsgAdapter(Context context, int textViewResourceId, List<Msg> objects) {  
        super(context, textViewResourceId, objects);  
        resourceId = textViewResourceId;  
    }  
  
    @Override  
    public View getView(int position, View convertView, ViewGroup parent) {  
        Msg msg = getItem(position);  
        View view;  
        ViewHolder viewHolder;  
        if (convertView == null) {  
            view = LayoutInflater.from(getContext()).inflate(resourceId, null);  
            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);  
        } else {  
            view = convertView;  
            viewHolder = (ViewHolder) view.getTag();  
        }  
        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_SENT) {  
                 // 如果是发出的消息,则显示右边的消息布局,将左边的消息布局隐藏  
                       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;  
     }  
} 

        最后修改 MainActivity 中的代码,来为 ListView 初始化一些数据,并给发送按钮加入事件响应,代码如下所示:

public class MainActivity extends Activity {  
  
    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);  
        initMsgs(); // 初始化消息数据  
        adapter = new MsgAdapter(MainActivity.this, R.layout.msg_item, msgList);  
        inputText = (EditText) findViewById(R.id.input_text);  
        send = (Button) findViewById(R.id.send);  
        msgListView = (ListView) findViewById(R.id.msg_list_view);  
        msgListView.setAdapter(adapter);  
        send.setOnClickListener(new OnClickListener() {  
            @Override  
            public void onClick(View v) {  
                String content = inputText.getText().toString();  
                if (!"".equals(content)) {  
                    Msg msg = new Msg(content, Msg.TYPE_SENT);  
                    msgList.add(msg);  
                    adapter.notifyDataSetChanged(); // 当有新消息时,刷新 ListView 中的显示  
                    msgListView.setSelection(msgList.size()); // 将 ListView 定位到最后一行  
                    inputText.setText(""); // 清空输入框中的内容  
                }  
            }  
        });  
    }  
  
    private void initMsgs() {  
        Msg msg1 = new Msg("Hello guy.", Msg.TYPE_RECEIVED);  
        msgList.add(msg1);  
        Msg msg2 = new Msg("Hello. Who is that?", Msg.TYPE_SENT);  
        msgList.add(msg2);  
        Msg msg3 = new Msg("This is Tom. Nice talking to you. ", Msg.TYPE_RECEIVED);  
        msgList.add(msg3);  
    }  
} 

        在 initMsg() 方法中我们先初始化了几条数据用于在 ListView 中显示。然后在发送按钮的点击事件里获取了 EditText 中的内容,如果内容不为空则创建出一个新的 Msg 对象,并把它添加到 msgList 列表中去。之后又调用了适配器的 notifyDataSetChanged() 方法,用于通知列表的数据发生了变化,这样新增的一条消息才能够在 ListView 中显示。接着调用 ListView 的 setSelection() 方法将显示的数据定位到最后一行,以保证一定可以看得到最后发出的一条消息。最后调用 EditText 的 setText() 方法将输入的内容清空。

        这样所有的工作就都完成了,终于可以检验一下我们的成果了,运行程序之后你将会看到非常美观的聊天界面,并且可以输入和发送消息,如图 3.43 所示。

                                      

                                                                                                           图  3.43

摘自《第一行代码》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值