1. Android

来源:互联网 发布:双系统windows连不上网 编辑:程序博客网 时间:2024/06/14 06:52

一、RecyclerView 普通列表实现

RecyclerView 可以实现 ListView 的效果,它通过使用 LayoutManager 来确定每一个 item 的排列方式,同时为增加和删除项目提供默认的动画效果。

1. 列表显示

MainActivity:初始化数据并设置适配器

public class MainActivity extends AppCompatActivity {    private RecyclerView main_recycler_view;    private List<String> mData;    @Override    protected void onCreate(Bundle savedInstanceState) {        // ...        initData();        // 设置自定义适配器        main_recycler_view.setAdapter(new RecyclerAdapter(this, mData));        // 设置布局管理器        main_recycler_view.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));        // 设置动画        main_recycler_view.setItemAnimator(new DefaultItemAnimator());        // 设置分割线        main_recycler_view.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));    }    // 初始化数据    private void initData() {        mData = new ArrayList<>();        for (int i = 'A'; i <= 'z'; i++) {            mData.add("" + (char) i);        }    }}

Item 布局文件

<?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="80dp">    <LinearLayout        android:layout_width="360dp"        android:layout_height="wrap_content"        android:orientation="vertical">        <TextView            android:id="@+id/item_text_title"            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:text="XXX"            android:textSize="24sp"            android:textColor="@android:color/black"            android:padding="5dp"/>        <TextView            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:paddingLeft="5dp"            android:text="content"            android:textSize="16sp"            android:textColor="@android:color/black"/>    </LinearLayout></LinearLayout>

RecyclerAdapter:自定义适配器

// 设置 RecyclerAdapter 继承自 RecyclerView.Adapter<RecyclerAdapter.ViewHolder>public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.ViewHolder> {    private Context mContext;    private List<String> mData;    // 构造方法,传入上下文和列表数据    public RecyclerAdapter(Context context, List<String> data) {        this.mContext = context;        this.mData = data;    }    // 加载 Item 的布局项    @Override    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {        View view = View.inflate(mContext, R.layout.item_recycler_view, null);        return new ViewHolder(view);    }    @Override    public void onBindViewHolder(ViewHolder holder, int position) {        // 获得当前数据对象并设置显示        String data = mData.get(position);        holder.item_text_title.setText(data);    }    @Override    public int getItemCount() {        return mData.size();    }    // ViewHolder 内部类    class ViewHolder extends RecyclerView.ViewHolder {        TextView item_text_title;        public ViewHolder(View itemView) {            super(itemView);            item_text_title = (TextView) itemView.findViewById(R.id.item_text_title);        }    }}

主页面布局以及内容项布局可以按自己的喜好设置。以下是 LayoutManager 进行各种不同设置时的运行结果。

RecyclerView 线性垂直布局.png

RecyclerView 线性水平布局.png

RecyclerView GridLayoutManager布局.png

2. Item 点击事件

有两种方法可以实现 Item 的点击事件,且都可以传入数据。

第一种,改写 ViewHolder 内部类,为其添加点击事件。

ViewHolder 类实现 OnclickListener 接口,itemView 设置该点击事件。

class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {    // 在 bindData() 中传入数据(这里只是 String,一般为自定义数据对象)    private String mData;    // 视图对象    private TextView item_text_title;    public ViewHolder(View itemView) {        super(itemView);        // 为 itemView 设置点击事件        itemView.setOnClickListener(this);        item_text_title = (TextView) itemView.findViewById(R.id.item_text_title);    }    // 将点击的数据对象传入并设置视图对象的显示    public void bindData(String data) {        mData = data;        item_text_title.setText(mData);    }    @Override    public void onClick(View v) {        Toast.makeText(mContext, "你点击了" + mData, Toast.LENGTH_SHORT).show();    }}

之后在 adapter 的 onBindViewHolder(…) 中调用新添加的 bindData() 方法。

@Overridepublic void onBindViewHolder(ViewHolder holder, int position) {    holder.bindData(mData.get(position));}

第二种,添加接口,使外部可以回调内部的点击事件。

首先在自定义的 RecyclerAdapter 中添加一个接口以及对应方法。

private OnMyItemClickListener listener;interface OnMyItemClickListener {    void onItemClick(int position);}// 用于外部设置 RecyclerAdapter 中的接口,重写其方法。public void setOnMyItemClickListener(OnMyItemClickListener l) {    this.listener = l;}

改写 ViewHolder 内的构造方法。

public ViewHolder(View itemView) {    super(itemView);    item_text_title = (TextView) itemView.findViewById(R.id.item_text_title);    itemView.setOnClickListener(new View.OnClickListener() {        @Override        public void onClick(View v) {            if (listener != null) {                listener.onItemClick(getLayoutPosition());            }        }    });}

在主页面中为 RecyclerAdapter 设置接口,重写 onItemClick() 方法。

adapter.setOnMyItemClickListener(new RecyclerAdapter.OnMyItemClickListener() {    @Override    public void onItemClick(int position) {        Toast.makeText(MainActivity.this, mData.get(position) + " Clicked!", Toast.LENGTH_SHORT).show();    }});

3. 添加和删除 Item

在 adapter 中加入两个函数:addItem(position) 以及 removeItem(position)
在函数中,先对数据集合进行操作,再通知适配器数据已经更改。
注:这里使用 notifyItemInserted(position) 与 notifyItemRemoved (position) 通知适配器,而非 ListView 中常用的 adapter.notifyDataSetChanged()

//  添加 Item 项public void addItem(int position) {    mData.add(position, "XXX");    notifyItemInserted(position);}// 删除 Item 项public void removeItem(int position) {    mData.remove(position);    notifyItemRemoved(position);}

设置 ToolBar,加入“添加”以及“删除”两个按钮进行操作,效果如下:
加入ToolBar后的界面.png

因为我们已经在刚开始设置了默认的动画效果:

main_recycler_view.setItemAnimator(new DefaultItemAnimator());

所以添加或者删除 Item 项时会有很不错的效果~
添加 / 删除 Item 时的默认动画效果.gif


二、分类型 RecyclerView 的实现

分类型 RecyclerView 可以通过代码实现界面的多样化,如下图所示,一共三部分:最上方为轮播图片(Banner实现),中间是 GridView,下方是 ViewPager。
实现这样的效果,在总的布局文件中只需要定义一个 即可。

分类型 RecyclerView 示例.png

总 RecyclerView 及其 adapter

布局文件:

<?xml version="1.0" encoding="utf-8"?><RelativeLayout    xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent">    <android.support.v7.widget.RecyclerView        android:id="@+id/home_recycle_view"        android:layout_width="match_parent"        android:layout_height="match_parent" /></RelativeLayout>

Adapter 代码:

public class HomeFragmentAdapter extends RecyclerView.Adapter {    // 定义 3 种类型的编码    private static final int BANNER = 0;    private static final int CHANNEL = 1;    private static final int ACT = 2;    // 当前类型    private int currentType = BANNER;    private Context context;    private JsonResult.ResultBean result; // 联网获得的 json 数据    private LayoutInflater layoutInflater;    public HomeFragmentAdapter(Context context, JsonResult.ResultBean result) {        this.context = context;        this.result = result;        layoutInflater = LayoutInflater.from(context);    }    //根据 RecyclerView 中的类型返回不同的 ViewHolder    @Override    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {        if (viewType == BANNER) {            return new BannerViewHolder(context, layoutInflater.inflate(R.layout.banner_view_pager, null));        } else if (viewType == CHANNEL) {            return new ChannelViewHolder(context, layoutInflater.inflate(R.layout.channel_item, null));        } else if (viewType == ACT) {            return new ActViewHolder(context, layoutInflater.inflate(R.layout.act_item, null));        }        return null;    }    // 根据 position 判断 RecyclerView 类型并绑定数据    @Override    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {        if (getItemViewType(position) == BANNER) {            BannerViewHolder bannerViewHolder = (BannerViewHolder) holder;            bannerViewHolder.setData(result.getBanner_info());        } else if (getItemViewType(position) == CHANNEL) {            ChannelViewHolder channelViewHolder = (ChannelViewHolder) holder;            channelViewHolder.setData(result.getChannel_info());        } else if (getItemViewType(position) == ACT) {            ActViewHolder actViewHolder = (ActViewHolder) holder;            actViewHolder.setData(result.getAct_info());        }    }    // 获取当前 RecyclerView 的类型    @Override    public int getItemViewType(int position) {        switch (position) {            case BANNER:                currentType = BANNER;                break;            case CHANNEL:                currentType = CHANNEL;                break;            case ACT:                currentType = ACT;                break;        }        return currentType;    }    // 一共有 3 种不同类型的 RecyclerView    @Override    public int getItemCount() {        return 3;    }}

1. BannerViewHolder

Banner 是一个第三方库,用于实现 Android 的图片轮播,效果如下所示。
github 地址:Banner

Banner 的轮播和拖动.gif

布局文件:

<?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:orientation="vertical"    android:layout_width="match_parent"    android:layout_height="match_parent">    <com.youth.banner.Banner        android:id="@+id/home_banner"        android:layout_width="match_parent"        android:layout_height="150dp"        app:indicator_height="5dp"        app:indicator_width="5dp"        app:is_auto_play="true">    </com.youth.banner.Banner></LinearLayout>

代码:

public class BannerViewHolder extends RecyclerView.ViewHolder {    private Context mContext;    private Banner banner;    public BannerViewHolder(Context context, View itemView) {        super(itemView);        this.mContext = context;        this.banner = (Banner) itemView.findViewById(R.id.home_banner);    }    // 设置数据并开启轮播    public void setData(List<JsonResult.ResultBean.BannerInfoBean> banner_info) {        List<String> imageUrls = new ArrayList<>();        for (int i = 0; i < banner_info.size(); i++) {            imageUrls.add(banner_info.get(i).getImage());        }        banner.setImages(imageUrls); // 设置图片 URL 的集合        banner.setImageLoader(new GlideImageLoader());        banner.setBannerAnimation(Transformer.Accordion); // 设置动画效果        banner.start();    }    // 图片加载类    private class GlideImageLoader extends ImageLoader {        @Override        public void displayImage(Context context, Object path, ImageView imageView) {            // 使用 Glide 加载图片            Glide.with(context).load(path).into(imageView);        }    }}

2. ChannelViewHolder

可以看出,整个频道模块就是一个 numColumns 为 5 的 GridView。
因此在 ChannelViewHolder 中初始化视图对象后要为此 GridView 设置适配器。

频道.png

布局文件:

<?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="170dp"    android:background="#fff"    android:orientation="vertical">    <GridView        android:id="@+id/home_gv_channel"        android:layout_width="wrap_content"        android:layout_height="150dp"        android:numColumns="5">    </GridView></LinearLayout>

ChannelViewHolder 代码:

public class ChannelViewHolder extends RecyclerView.ViewHolder {    private Context mContext;    private GridView home_gv_channel;    public ChannelViewHolder(Context context, View itemView) {        super(itemView);        this.mContext = context;        home_gv_channel = (GridView) itemView.findViewById(R.id.home_gv_channel);    }    public void setData(List<JsonResult.ResultBean.ChannelInfoBean> channel_info) {        ChannelAdapter adapter = new ChannelAdapter(mContext, channel_info);        home_gv_channel.setAdapter(adapter);    }}

Adapter 代码:

public class ChannelAdapter extends BaseAdapter {    private Context mContext;    private List<ChannelInfoBean> channel_info;    public ChannelAdapter(Context context, List<ChannelInfoBean> channel_info) {        this.mContext = context;        this.channel_info = channel_info;    }    @Override    public int getCount() { return channel_info.size(); }    @Override    public Object getItem(int position) { return channel_info.get(position); }    @Override    public long getItemId(int position) { return 0; }    @Override    public View getView(int position, View convertView, ViewGroup parent) {        ViewHolder viewHolder;        if (convertView == null) {            viewHolder = new ViewHolder();            convertView = View.inflate(mContext, R.layout.item_channel, null);            viewHolder.iv_channel = (ImageView) convertView.findViewById(R.id.iv_channel);            viewHolder.tv_channel = (TextView) convertView.findViewById(R.id.tv_channel);            convertView.setTag(viewHolder);        } else {            viewHolder = (ViewHolder) convertView.getTag();        }        ChannelInfoBean data = channel_info.get(position);        Glide.with(mContext).load(data.getImage()).into(viewHolder.iv_channel);        viewHolder.tv_channel.setText(data.getChannel_name());        return convertView;    }    private static class ViewHolder {        ImageView iv_channel;        TextView tv_channel;    }}
原创粉丝点击