AndroidAndroid开发程序员

03UI开发-RecyclerView及简单聊天界面

2018-03-18  本文已影响22人  何惧l

基本用法

  1. 想要使用这个控件,首先在项目的build.gradle中添加相应的依赖库才行
    打开app/build.gradle文件,在dependencies闭包中添加
dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:26.1.0'
    // 添加的是这一句
    compile 'com.android.support:recyclerview-v7:26.1.0'
    implementation 'com.android.support.constraint:constraint-layout:1.0.2'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.1'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
}

  1. 添加完成后点击一下Sync Now来进行同步,然后修改activity_main.xml中的代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recycler_view_1"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</LinearLayout>

添加一个控件,宽度和高度都是占满整部布局空间的

  1. 接下来定义一个自定义布局fruit_item.xml,这个时候注意layout_width="wrap_content"的设置,让它自适应大就可以了
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">

    <ImageView
        android:id="@+id/img"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />

    <TextView
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="center_vertical"
        android:layout_marginLeft="20dp"
        />

</LinearLayout>

4.定义一个实体类,作为RecyclerView适配器的适配类型,建立Fruit


public class Fruit {
    private String name;
    private int imageId;

    public Fruit(String name,int imageId){
        this.imageId = imageId;
        this.name = name;
    }
    public String getName() {
        return name;
    }

    public int getImageId() {
        return imageId;
    }
}

  1. 为RecyclerView准备一个适配器,新建FruitAdapter类,让这个适配器继承RecyclerView.Adapter,并将泛型指定为FruitAdapter.ViewHolder,其中ViewHolder是我们在FruitAdapter中定义的一个内部类

public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder> {

    private List<Fruit> mFruitList;

    static class ViewHolder extends RecyclerView.ViewHolder{
        ImageView fruitImage;
        TextView fruitName;

        public ViewHolder(View view){
            super(view);
            fruitImage=(ImageView)view.findViewById(R.id.img);
            fruitName = (TextView)view.findViewById(R.id.text);
        }
    }

    public FruitAdapter(List<Fruit> fruitList){
        mFruitList = fruitList;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.fruit_item,parent,false);
        ViewHolder holder = new ViewHolder(view);
        return holder;
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        Fruit fruit = mFruitList.get(position);
        holder.fruitImage.setImageResource(fruit.getImageId());
        holder.fruitName.setText(fruit.getName());
    }

    @Override
    public int getItemCount() {
        return mFruitList.size();
    }


}


  1. 接下来就可以使用RecyclerView,修改MainActivity中的代码

public class MainActivity extends AppCompatActivity {

    private List<Fruit> fruitList = new ArrayList<>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // 用于初始化水果
        initFruits();
        RecyclerView recyclerView = (RecyclerView)findViewById(R.id.recycler_view_1);
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        recyclerView.setLayoutManager(layoutManager);
        FruitAdapter adapter = new FruitAdapter(fruitList);
        recyclerView.setAdapter(adapter);
    }


    private void initFruits(){
        for (int i= 0;i<2;i++){
            Fruit apple = new Fruit("Apple",R.drawable.apple_pic);
            fruitList.add(apple);
            Fruit banana = new Fruit("Banana",R.drawable.banana_pic);
            fruitList.add(banana);
            Fruit orange = new Fruit("orange",R.drawable.orange_pic);
            fruitList.add(orange);
            Fruit watermelon = new Fruit("watermelon",R.drawable.watermelon_pic);
            fruitList.add(watermelon);
            Fruit pear = new Fruit("pear",R.drawable.pear_pic);
            fruitList.add(pear);
            Fruit grape = new Fruit("grape",R.drawable.grape_pic);
            fruitList.add(grape);
            Fruit pineapple = new Fruit("pineapple",R.drawable.pineapple_pic);
            fruitList.add(pineapple);
            Fruit strawberry = new Fruit("strawberry",R.drawable.strawberry_pic);
            fruitList.add(strawberry);
            Fruit cherry = new Fruit("cherry",R.drawable.cherry_pic);
            fruitList.add(cherry);
            Fruit mango = new Fruit("mango",R.drawable.mango_pic);
            fruitList.add(mango);
        }
    }

}

实现横向滚动和瀑布流布局

  1. 首先要对fruit_item布局进行修改,实现横向滚动,得把这里面的元素改成垂直排列的方式
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="100dp"
    android:layout_height="wrap_content">

    <ImageView
        android:id="@+id/img"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        />

    <TextView
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="20dp"
        />

</LinearLayout>

  1. 修改MainActivity中的代码
package com.example.md.recyclerview;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {


    private List<Fruit> fruitList = new ArrayList<>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // 用于初始化水果
        initFruits();
        RecyclerView recyclerView = (RecyclerView)findViewById(R.id.recycler_view_1);
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        // 多添加这一句话
        layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
        recyclerView.setLayoutManager(layoutManager);
        FruitAdapter adapter = new FruitAdapter(fruitList);
        recyclerView.setAdapter(adapter);
    }
        
    ..............

}


  1. 除了LinearLayoutManager之外,RecyclerView还提供了GridLayoutManagerStaggeredGridLayoutManager这样中内置的布局排列方式,GridLayoutManager是用于网络布局,StaggeredGridLayoutManager用于瀑布布局
    修改fruit_item.xml中的代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="5dp">

    <ImageView
        android:id="@+id/img"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        />

    <TextView
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="left"
        android:layout_marginTop="20dp"
        />

</LinearLayout>

只有几处调整,把宽度有100dp改成match_parent,因为瀑布的宽度是根据布局的列数自动匹配的,不是一个固定的值,还用margin属性,让子项之间留点间距,文字的对齐方式改成了左对齐

  1. 修改MainActivity中的代码

public class MainActivity extends AppCompatActivity {


    private List<Fruit> fruitList = new ArrayList<>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // 用于初始化水果
        initFruits();
        RecyclerView recyclerView = (RecyclerView)findViewById(R.id.recycler_view_1);
//        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        // 多添加这一句话
//        layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);

//      主要就是这一行代码,瀑布
        StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(
                3, StaggeredGridLayoutManager.VERTICAL
        );

        // 网络
        //GridLayoutManager layoutManager = new GridLayoutManager(this,4);

        recyclerView.setLayoutManager(layoutManager);
        FruitAdapter adapter = new FruitAdapter(fruitList);
        recyclerView.setAdapter(adapter);
    }

    private void initFruits(){
        for (int i= 0;i<2;i++){
            Fruit apple = new Fruit(getRandomLengthName("Apple"),R.drawable.apple_pic);
            fruitList.add(apple);
            Fruit banana = new Fruit(getRandomLengthName("Banana"),R.drawable.banana_pic);
            fruitList.add(banana);
            Fruit orange = new Fruit(getRandomLengthName("orange"),R.drawable.orange_pic);
            fruitList.add(orange);
            Fruit watermelon = new Fruit(getRandomLengthName("watermelon"),R.drawable.watermelon_pic);
            fruitList.add(watermelon);
            Fruit pear = new Fruit(getRandomLengthName("pear"),R.drawable.pear_pic);
            fruitList.add(pear);
            Fruit grape = new Fruit(getRandomLengthName("grape"),R.drawable.grape_pic);
            fruitList.add(grape);
            Fruit pineapple = new Fruit(getRandomLengthName("pineapple"),R.drawable.pineapple_pic);
            fruitList.add(pineapple);
            Fruit strawberry = new Fruit(getRandomLengthName("strawberry"),R.drawable.strawberry_pic);
            fruitList.add(strawberry);
            Fruit cherry = new Fruit(getRandomLengthName("cherry"),R.drawable.cherry_pic);
            fruitList.add(cherry);
            Fruit mango = new Fruit(getRandomLengthName("mango"),R.drawable.mango_pic);
            fruitList.add(mango);
        }
    }

// 不想实现也可以不用写
    private String getRandomLengthName(String name){
        Random random = new Random();
        int length = random.nextInt(20) + 1;
        StringBuilder builder = new StringBuilder();
        for(int i = 0;i<length;i++){
            builder.append(name);
        }
        return builder.toString();
    }

}

RecyclerView的点击事件

这个的注册监听器方法是需要我们自己给子项具体的View去注册点击事件的

  1. 修改FruitAdapter中的代码

public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder> {

    private List<Fruit> mFruitList;

    static class ViewHolder extends RecyclerView.ViewHolder{
        // 这里定义一个View变量
        View fruitView;
        ImageView fruitImage;
        TextView fruitName;

        public ViewHolder(View view){
            super(view);
            // 保存最外层的布局实例
            fruitView  = view;
            fruitImage = view.findViewById(R.id.img);
            fruitName = view.findViewById(R.id.text);
        }
    }

    public FruitAdapter(List<Fruit> fruitList){
        mFruitList = fruitList;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.fruit_item,parent,false);
       // 
        final ViewHolder holder = new ViewHolder(view);

        //分别为最外层的布局和Image注册点击事件
        holder.fruitView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 获取到position,然后拿到Fruit实例
                int position = holder.getAdapterPosition();
                Fruit fruit = mFruitList.get(position);
                Toast.makeText(v.getContext(),"you click view"+fruit.getName(),Toast.LENGTH_SHORT).show();
            }
        });
        holder.fruitImage.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int position = holder.getAdapterPosition();
                Fruit fruit = mFruitList.get(position);
                Toast.makeText(v.getContext(),"you clcik image"+fruit.getImageId(),Toast.LENGTH_SHORT).show();
            }
        });
        return holder;
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        Fruit fruit = mFruitList.get(position);
        holder.fruitImage.setImageResource(fruit.getImageId());
        holder.fruitName.setText(fruit.getName());
    }

    @Override
    public int getItemCount() {
        return mFruitList.size();
    }
}

了解Nine-Patch

  1. 现在项目中有一个气泡状的图片,将这个图片设置为背景图片
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/beijing"
    >
</LinearLayout>

2018-03-17_13-53-54.png

这个时候可以看到图片被均匀的拉伸了,效果极差,这个时候就可以使用Nine-Patch来处理了

  1. 右击要添加的图片,点击Create 9-Patch file


    2018-03-17_13-55-30.png
  2. 就进入到这个页面


    2018-03-17_13-57-25.png

    我们可以在四周绘制一个个小黑点,按住Shift键拖动就可以进行擦除,使用这个新的图片替换原来的,再运行程序就可以看到


    2018-03-17_14-00-18.png
  3. 这样,当图片需要拉伸的时候,就指定拉伸的区域,在外观上就好看了

编写聊天界面

  1. 首先使用到的是RecyclerView,所以首先进行在app/build.gradle中添加依赖库
dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:26.1.0'
    // 添加这行代码
    compile 'com.android.support:recyclerview-v7:26.1.0'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.1'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
}

  1. 编写主页面,修改activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#d8e0e8"
    >

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyc_1"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"/>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <EditText
            android:id="@+id/edit_1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:hint="Type something here"
            android:textSize="25sp"
            android:maxLines="2"/>

        <Button
            android:id="@+id/send"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="25sp"
            android:text="Send"/>

    </LinearLayout>



</LinearLayout>

  1. 定义消息的实体类,新建一个Msg
public class Msg {
    // 接收到一条消息
    public static final int TYPE_RECEVED = 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;
    }
}

  1. 接下来编写RecyclerView的子项布局,新建msg_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <LinearLayout
        android:id="@+id/left_layout"
        android:layout_gravity="left"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        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"
            android:textSize="25sp"/>

    </LinearLayout>


    <LinearLayout
        android:id="@+id/right_layout"
        android:layout_gravity="right"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        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"
            android:textColor="#000000"
            android:textSize="25sp"/>

    </LinearLayout>


</LinearLayout>

  1. 编写自定义的MagAdapter适配器,和在RecyclerView写的适配器代码基本一样

public class MsgAdapter extends RecyclerView.Adapter<MsgAdapter.ViewHolder> {

    private List<Msg> mMsgList;

    static class ViewHolder extends RecyclerView.ViewHolder{

        LinearLayout leftLayout;
        LinearLayout rightLayout;
        TextView lefMsg;
        TextView rightMsg;

        public ViewHolder(View itemView) {
            super(itemView);
            leftLayout = (LinearLayout)itemView.findViewById(R.id.left_layout);
            rightLayout = (LinearLayout)itemView.findViewById(R.id.right_layout);
            lefMsg = (TextView)itemView.findViewById(R.id.left_msg);
            rightMsg = (TextView)itemView.findViewById(R.id.right_msg);
        }

    }

    public MsgAdapter(List<Msg> msgList){
        mMsgList = msgList;
    }

    @Override
    public MsgAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.msg_item,parent,false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(MsgAdapter.ViewHolder holder, int position) {
        Msg msg = mMsgList.get(position);
        if (msg.getType() == Msg.TYPE_RECEVED){
            // 如果是接收到的消息,则显示左边的消息布局,将右边的隐藏
            holder.leftLayout.setVisibility(View.VISIBLE);
            holder.rightLayout.setVisibility(View.GONE);
            holder.lefMsg.setText(msg.getContent());
        }else if (msg.getType() == Msg.TYPE_SENT){
            // 如果是发送消息,那么显示右边的布局,把左边的布局隐藏
            holder.rightLayout.setVisibility(View.VISIBLE);
            holder.leftLayout.setVisibility(View.GONE);
            holder.rightMsg.setText(msg.getContent());
        }
    }

    @Override
    public int getItemCount() {
        return mMsgList.size();
    }
}


  1. 修改MainActivity中的代码

public class MainActivity extends AppCompatActivity {

    private List<Msg> msgList = new ArrayList<>();
    private EditText inputText;
    private Button send;
    private RecyclerView msgRecyclerView;
    private MsgAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main_layout);
        // 初始化消息数据
        initMsag();
        inputText = (EditText)findViewById(R.id.edit_1);
        send = (Button)findViewById(R.id.send);
        // 获取到这个滚动控件
        msgRecyclerView = (RecyclerView)findViewById(R.id.recyc_1);
        // 指定这个控件的布局方式
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        //设置到这个滚动控件中
        msgRecyclerView.setLayoutManager(layoutManager);
        // 数据传入到自定义的适配器中
        adapter = new MsgAdapter(msgList);
        msgRecyclerView.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_SENT);
                    msgList.add(msg);
                    // 当有新的消息的时候刷新ListView中的显示
                    adapter.notifyItemInserted(msgList.size()-1);
                    // 将ListView定位到最后一行
                    msgRecyclerView.scrollToPosition(msgList.size()-1);
                    // 清空输入框中的内容
                    inputText.setText("");
                }
            }
        });


    }

    public void initMsag(){
        Msg msg = new Msg("hello pony",Msg.TYPE_RECEVED);
        msgList.add(msg);
        Msg msg1 = new Msg("hello Tom",Msg.TYPE_SENT);
        msgList.add(msg1);
        Msg msg2 = new Msg("我们去哪里呀?",Msg.TYPE_RECEVED);
        msgList.add(msg2);
    }
}


参考数据:第一行代码
若有错误请指出

上一篇 下一篇

猜你喜欢

热点阅读