Android 聊天界面布局设计(一)

前言:具体的聊天功能我也是第一次做,在通过Bmob获取后端云之前现有显示,这里我主要用 Listview 界面就简单的模拟一下,先不连数据库。

效果图:

消息布局:

<?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:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical"
              tools:context=".ChatFragment">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        >

        <SearchView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/bg_white"
            >
        </SearchView>

        <ListView
            android:id="@+id/list_test2"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@color/bg_white"/>

    </LinearLayout>

</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              xmlns:app="http://schemas.android.com/apk/res-auto"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:background="@color/bg_white"
              android:orientation="horizontal"
              android:weightSum="1">

    <!-- 定义一个用于显示头像的ImageView -->

    <ImageView
        android:id="@+id/imgtou"
        android:layout_width="64dp"
        android:layout_height="64dp"
        android:baselineAlignBottom="true"
        android:paddingLeft="8dp"/>

    <!-- 定义一个竖直方向的LinearLayout,把QQ呢称与说说的文本框设置出来 -->

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="66dp"
        android:layout_weight="0.79"
        android:orientation="vertical">

        <TextView
            android:id="@+id/name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:paddingLeft="8dp"
            android:textColor="#1D1D1C"
            android:textSize="20sp"/>

        <TextView
            android:id="@+id/says"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:paddingLeft="8px"
            android:textColor="#B4B4B9"
            android:textSize="14sp"/>

    </LinearLayout>


public class ChatFragment extends Fragment {

    private ListView listView;
    private String[] names=new String[]{"桃艺园果蔬合作社",
            "丰年合作社","向往合作社", "养殖合作社","王润农村合作社","长生合作社","惠农农业发展合作社"};
    private String[] says=new String[]{"北京市延庆县康庄镇小丰营村西3000米","广西壮族自治区-河池市","河南省-驻马店市"
            ,"山西省-吕梁市 ","新疆维吾尔自治区-克孜勒苏柯尔克孜自治州","云南省-西双版纳傣族自治州","重庆市-彭水苗族土家族自治县"};
    private int[] imgIds=new int[]{R.mipmap.h1,R.mipmap.h2,R.mipmap.h3,R.mipmap.h4,R.mipmap.h5,R.mipmap.h6,R.mipmap.h7,R.mipmap.h8};
    public ChatFragment() {
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_chat, container, false);
        // Inflate the layout for this fragment
        List<Map<String, Object>> listitem = new ArrayList<Map<String, Object>>();
        for (int i = 0; i < names.length; i++) {
            Map<String, Object> showitem = new HashMap<String, Object>();
            showitem.put("touxiang", imgIds[i]);
            showitem.put("name", names[i]);
            showitem.put("says", says[i]);
            listitem.add(showitem);
        }
        //创建一个simpleAdapter
        SimpleAdapter myAdapter = new SimpleAdapter(getActivity(), listitem, R.layout.qun_item, new String[]{"touxiang", "name", "says"}, new int[]{R.id.imgtou, R.id.name, R.id.says});
        listView = (ListView) view.findViewById(R.id.list_test2);
        listView.setAdapter(myAdapter);

        return view;
    }

}

这里我觉得如果获取云数据库的数据,将string[] 内容加载的部分修改。消息列表的话,就是检测该用户是否有人和他说话,说话的话,就把用户的头像,用户名,说说 适配进listview.通过实例加载。可以直接加载用户实例User。

聊天界面:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <ListView
        android:id="@+id/msg_list_view"
        android:layout_height="0dp"
        android:layout_width="match_parent"
        android:layout_weight="1"
        android:divider="#0000"/>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <EditText
            android:id="@+id/input_text"
            android:layout_height="wrap_content"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:hint="输入你想说的话"
            android:maxLines="2"/>
        <Button
            android:id="@+id/send"
            android:layout_height="wrap_content"
            android:layout_width="wrap_content"
            android:text="发送"/>

    </LinearLayout>

</LinearLayout>

msg_item.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="match_parent"
    android:orientation="vertical"
    android:padding="10dp">

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <ImageView
            android:id="@+id/head_left"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="left"
            android:src="@drawable/head1"/>

        <LinearLayout
            android:id="@+id/left_layout"
            android:layout_height="wrap_content"
            android:layout_width="wrap_content"
            android:layout_gravity="left"
            android:background="@drawable/left_messages">

            <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>

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="right"
        android:orientation="horizontal">

    <LinearLayout
        android:id="@+id/right_layout"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:layout_gravity="right"
        android:background="@drawable/right_messages">

        <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>
        <ImageView
            android:id="@+id/head_right"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/head2"/>
    </LinearLayout>

</LinearLayout>

消息实体类: 如果连接Bomb 这里就要改改,换成插入的数据,这里的话,数据库的数据表,说法也多。

public class Msg {
    public static final int TYPE_RECEIVED = 0;
    public static final int TYPE_SEND = 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;
    }
}

适配器:

public class MsgAdapter extends ArrayAdapter<Msg> {
    private int resourceId;

    public MsgAdapter(Context context, int textViewResourceId, List<Msg> objects) {
        super(context, textViewResourceId, objects);
        resourceId = textViewResourceId;
    }

    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);
            viewHolder.head1 = (ImageView)view.findViewById(R.id.head_left);
            viewHolder.head2 = (ImageView)view.findViewById(R.id.head_right);
            view.setTag(viewHolder);
        } else {
            view = convertView;
            viewHolder = (ViewHolder) view.getTag();
        }
        if(msg.getType() == Msg.TYPE_RECEIVED) {
            viewHolder.leftLayout.setVisibility(View.VISIBLE);
            viewHolder.head1.setVisibility(View.VISIBLE);
            viewHolder.rightLayout.setVisibility(View.GONE);
            viewHolder.head2.setVisibility(View.GONE);
            viewHolder.leftMsg.setText(msg.getContent());
        } else if(msg.getType() == Msg.TYPE_SEND) {
            viewHolder.rightLayout.setVisibility(View.VISIBLE);
            viewHolder.head2.setVisibility(View.VISIBLE);
            viewHolder.leftLayout.setVisibility(View.GONE);
            viewHolder.head1.setVisibility(View.GONE);
            viewHolder.rightMsg.setText(msg.getContent());
        }
        return view;
    }

    class ViewHolder {
        LinearLayout leftLayout;
        LinearLayout rightLayout;
        TextView leftMsg;
        TextView rightMsg;
        ImageView head1;
        ImageView head2;
    }
}
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);

        ActionBar actionBar = getSupportActionBar();
        actionBar.hide();

        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 View.OnClickListener() {
            @Override
            public void onClick(View view) {
                String content = inputText.getText().toString();
                if(!"".equals(content)) {
                    Msg msg = new Msg(content, Msg.TYPE_SEND);
                    msgList.add(msg);
                    adapter.notifyDataSetChanged();
                    msgListView.setSelection(msgList.size());
                    inputText.setText("");
                }
            }
        });
    }

    private void initMsgs() {
        Msg msg1 = new Msg("Hello, how are you?", Msg.TYPE_RECEIVED);
        msgList.add(msg1);
        Msg msg2 = new Msg("Fine, thank you, and you?", Msg.TYPE_SEND);
        msgList.add(msg2);
        Msg msg3 = new Msg("I am fine, too!", Msg.TYPE_RECEIVED);
        msgList.add(msg3);
    }
}

ViewHolder通常出现在适配器里,为的是listview滚动的时候快速设置值,而不必每次都重新创建很多对象,从而提升性能。

在android开发中Listview是一个很重要的组件,它以列表的形式根据数据的长自适应展示具体内容,用户可以自由的定义listview每一列的布局,但当listview有大量的数据需要加载的时候,会占据大量内存,影响性能,这时候就需要按需填充并重新使用view来减少对象的创建。 

Adapter :适配器,因为 ListView 是一个 View ,不能添加子项,因此在呈现数据的时候就需要某种工具将数据呈现在 ListView 上,而 Adapter 就能充当此角色。常用的 Adapter:ArrayAdapter、BaseAdapter等。

  • 继承 BaseAdapter (可在继承的时候指定泛型,扩展使用);
  • 重写四个基本方法:
    getCount():获取数据的总的数量,返回 int 类型的结果;
    getItem(int position) :获取指定位置的数据,返回该数据;
    getItemId(int position):获取指定位置数据的id,返回该数据的id,一般以数据所在的位置作为它的id;
    getView(int position,View convertView,ViewGroup parent):关键方法,用于确定列表项
  • 创建 ViewHolder (包含列表项的控件。)

ListView加载数据都是在public View getView(int position, View convertView,  
ViewGroup parent) {}方法中进行的(要自定义listview都需要重写listadapter:如BaseAdapter,SimpleAdapter,CursorAdapter的等的getvView方法),优化listview的加载速度就要让convertView匹配列表类型,并最大程度上的重新使用convertView。 

getView的加载方法一般有以下三种方式:

① 最慢的加载方式是每一次都重新定义一个View载入布局,再加载数据; 例:消息列表。

② 正确的加载方式是当convertView不为空的时候直接重新使用convertView从而减少了很多不必要的View的创建,然后加载数据;

使用convertView主要是为了缓存试图View,用以增加ListView的item view加载效率。有经验的Android开发者通常知道在Adapter的getView中,先判断convertView是否为空null,如果非空,则直接再次对convertView复用,否则才创建新的View

③最快的方式是定义一个ViewHolder,将convetView的tag设置为ViewHolder,不为空时重新使用即可。 例:聊天记录。

 现在的界面都是静态的布局,之后我用Bomb 及时通讯的接口,之后内容根据数据库进行变换。

发布了71 篇原创文章 · 获赞 19 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_39131246/article/details/90715845