Android app开发学习笔记——Android高级控件-下

三、循环视图

RecyclerView是support-v7包中的新组件,是一个强大的滑动组件,是ListView 的升级版本,更加先进和灵活。RecyclerView通过设置
LayoutManager、ItemDecoration、ItemAnimator 可实现更多效果。

  • 使用LayoutManager来确定每一个item的排列方式。
  • 使用ItemDecoration 自己绘制分隔线,更加灵活。
  • 使用ItemAnimator为增加或删除一行设置动画效果。

1.RecyclerViewAdapter(循环视图适配器)

为RecyclerView新增适配器RecyclerViewAdapter,并让其继承于RecyclerView.Adapter,把泛型指定为RecyclerViewAdapter.MyViewHolder。
下面先给出代码再具体讲解

package com.example.hzhapplication;

import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

import androidx.recyclerview.widget.RecyclerView;

import java.util.List;

public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.MyViewHolder>{
    private List<String> datas;
    private LayoutInflater inflater;
    public  RecyclerViewAdapter(Context context, List<String> datas){
        inflater=LayoutInflater.from(context);
        this.datas=datas;
    }
    //创建每一行的View 用RecyclerView.ViewHolder包装
    @Override
    public RecyclerViewAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View itemView=inflater.inflate(R.layout.recycler_item,parent,false);
        return new MyViewHolder(itemView);
    }
    //给每一行View填充数据
    @Override
    public void onBindViewHolder(RecyclerViewAdapter.MyViewHolder holder, int position){
        holder.textview.setText(datas.get(position));
    }
    //数据源的数量
    @Override
    public int getItemCount() {
        return datas.size();
    }
    class MyViewHolder extends RecyclerView.ViewHolder{
        private TextView textview;
        public MyViewHolder(View itemView) {
            super(itemView);
            textview = (TextView) itemView.findViewById(R.id.textview);
        }
    }
}

recycler_item.xml中的内容

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
   <TextView
       android:id="@+id/textview"
       android:padding="10dp"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:textSize="20sp"/>
</FrameLayout>

继承自RecyclerView.Adapter,必须要重写onCreateViewHolder(),onBindViewHolder()和getItemCount()三个方法

  • onCreateViewHolder()用于创建ViewHolder实例,并把加载的布局传入到构造函数去,再把ViewHolder实例返回。
  • onBindViewHolder()则是用于对子项的数据进行赋值,会在每个子项被滚动到屏幕内时执行。position得到当前项的实例。
  • getItemCount()返回RecyclerView的子项数目。

2.LayoutManager(布局管理器)

仅有适配器的循环视图是不能显示视图的,只有在写完布局管理器之后才能显示视图。
在RecyclerView 中实现不同的列表,只需切换不同的 LayoutManager(布局管理器)即可。
RecyclerView.LayoutManager 与 RecyclerView.ItemDecoration一样,都是RecyclerView 静态抽象内部类,但是LayoutManager有三个官方写好的实现类。
LinearLayoutManager(线性布局管理器):与ListView功能相似。
·GridLayoutManager(网格布局管理器):与GridView 功能相似。
·StaggeredGridLayoutManager(瀑布流布局管理器)。
用法分别如下

recyclerView.setLayoutManager (new LinearLayoutManager (this));
recyclerView.setLayoutManager (new GridLayoutManager (this,2));
recyclerView.setLayoutManager(new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL));

如果要显示多列或者要纵向显示,只需新建不同的构造方法即可。以下代码纵向显示4列。
当然,如果还需要反方向显示,把false改成true即可。

recyclerView.setLayoutManager (new
GridLayoutManager(this, 4, GridLayoutManager. HORIZONTAL, false));

因为用的是网格布局,所以绘制分隔线的代码需要重新修改一下。网格布局一行可以有多列,
并且最后一列与最后一行不需要绘制,所以需要重新创建一个类:DividerGridItemDecoration.java.

3.ItemDecoration(自己绘制分割符)

RecycleView是没有android:divider与android:dividerHeight属性的,如果需要分隔线,只能自己手动实现

  • 需要继承ItemDecoration类实现onDraw与getItemOffsets方法
  • 调用RecyclerView的addItemDecoration方法

代码中的paint以及Canvas可以参考学习:Android 自定义 view(三)—— onDraw 方法理解

线性布局分割线

先编写一个DividerItem类,继承RecyclerView.ItemDecoration,在getItemOffsets留出Item之间的间隔,然后调用onDraw方法绘制(onDraw的绘制优先于每一行的绘制)

public class DividerItemDecoration extends RecyclerView.ItemDecoration {
    /*
    * RecycleView的布局方向,默认先赋值未纵向布局
    * RecycleView布局可横向,也可纵向
    * 横向和纵向对应的画法不一样
    * */
    private int mOrientation = LinearLayoutManager.VERTICAL;
    private int mItemSize =1;//Item之间分割线的size,默认为1
    private Paint mPaint;//绘制item分割线的画笔,并设置其属性
    public DividerItemDecoration(){}
    public DividerItemDecoration(Context context)
    {
        this(context,LinearLayoutManager.VERTICAL);
    }
    public DividerItemDecoration(Context context,int orientation)
    {
        this(context,orientation,R.color.浅蓝);
    }
    public DividerItemDecoration(Context context,int orientation,int dividerColor)
    {
        this(context,orientation,dividerColor,1);
    }
    /*
    * @param context
    * @patam orientation 绘制方向
    * @param dividerColor分割线颜色,颜色资源id
    * @param mItemSize 分割线宽度,传入dp值就行
    * */
    public DividerItemDecoration(Context context,int orientation,int dividerColor,int mItemSize)
    {
        this.mOrientation=orientation;
        if(orientation!= LinearLayoutManager.VERTICAL&& orientation!=LinearLayoutManager.HORIZONTAL)
        {
            throw new  IllegalArgumentException("请传入正确的参数值");
        }
        //把dp值换算成px
        this.mOrientation = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,mItemSize,context.getResources().getDisplayMetrics());
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setColor(context.getResources().getColor(dividerColor));
    }
    @Override
    public void onDraw(Canvas c,RecyclerView parent,RecyclerView.State state)
    {
        if(mOrientation == LinearLayoutManager.VERTICAL){
            drawVertical(c,parent);
        }
        else{
            drawHorizontal(c,parent);
        }
    }
    /*
     * 绘制纵向 item分割线
     * @param canvas
     * @param parent
     * */
    private  void  drawVertical(Canvas canvas,RecyclerView parent)
    {
        final int left=parent.getPaddingLeft();
        final int right=parent.getMeasuredWidth()-parent.getPaddingRight();
        final int childSize = parent.getChildCount();
        for(int i=0;i<childSize;i++)
        {
            final View child = parent.getChildAt(i);
            RecyclerView.LayoutParams layoutParams =(RecyclerView.LayoutParams) child.getLayoutParams();
            final int top = child.getBottom()+layoutParams.bottomMargin;
            final int bottom =top+mItemSize;
            canvas.drawRect(left,top,right,bottom,mPaint);

        }
    }/*
     * 绘制横向 item分割线
     * @param canvas
     * @param parent
     * */
    private  void  drawHorizontal(Canvas canvas,RecyclerView parent)
    {
        final int top=parent.getPaddingTop();
        final int bottom=parent.getMeasuredHeight()-parent.getPaddingBottom();
        final int childSize = parent.getChildCount();
        for(int i=0;i<childSize;i++)
        {
            final View child = parent.getChildAt(i);
            RecyclerView.LayoutParams layoutParams =(RecyclerView.LayoutParams) child.getLayoutParams();
            final int left = child.getRight()+layoutParams.rightMargin;
            final int right=left+mItemSize;
            canvas.drawRect(left,top,right,bottom,mPaint);

        }
    }
    /*
    * 设置item分割线的size
    * @param outRect
    * @param view
    * @param parent
    * @param state
    * */
    @Override
    public void getItemOffsets(Rect outRect,View view,RecyclerView parent,RecyclerView.State state)
    {
        if(mOrientation==LinearLayoutManager.VERTICAL)
        {
            outRect.set(0,0,0,mItemSize);
            //垂直排列,底部偏移
        }
        else {
            outRect.set(0,0,mItemSize,0);
            //水平排列,右边偏移
        }
    }
}

网格布局分割线

由于布局的不同说以分割线的代码绘制需要重新修改。
网格布局一行可以有多列并且最后一列与最后一行不需要绘制,所以需要重新创建一个类:DividerGridItemDecoration

package com.example.hzhapplication;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.TypedValue;
import android.view.View;

import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.StaggeredGridLayoutManager;

/**
 * Created by  ansen
 * Create Time 2016-08-23
 */
public class DividerGridItemDecoration extends RecyclerView.ItemDecoration {
    /*
     * RecyclerView的布局方向,默认先赋值 为纵向布局
     * RecyclerView 布局可横向,也可纵向
     * 横向和纵向对应的分割线画法不一样
     * */
    private int mOrientation = LinearLayoutManager.VERTICAL;
    private int mItemSize = 1;//item之间分割线的size,默认为1
    private Paint mPaint;//绘制item分割线的画笔,和设置其属性
    public DividerGridItemDecoration(Context context) {
        this(context,LinearLayoutManager.VERTICAL,R.color.浅蓝);
    }
    public DividerGridItemDecoration(Context context, int orientation) {
        this(context,orientation, R.color.浅蓝);
    }
    public DividerGridItemDecoration(Context context, int orientation, int dividerColor){
        this(context,orientation,dividerColor,1);
    }
    /**
     * @param context
     * @param orientation 绘制方向
     * @param dividerColor 分割线颜色 颜色资源id
     * @param mItemSize 分割线宽度 传入dp值就行
     */
    public DividerGridItemDecoration(Context context, int orientation, int dividerColor, int mItemSize){
        this.mOrientation = orientation;
        if(orientation != LinearLayoutManager.VERTICAL && orientation != LinearLayoutManager.HORIZONTAL){
            throw new IllegalArgumentException("请传入正确的参数") ;
        }
        //把dp值换算成px
        this.mItemSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,mItemSize,context.getResources().getDisplayMetrics());
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setColor(context.getResources().getColor(dividerColor));
    }
    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        drawHorizontal(c, parent);
        drawVertical(c, parent);
    }
    private int getSpanCount(RecyclerView parent) {
        // 列数
        int spanCount = -1;
        RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
        if (layoutManager instanceof GridLayoutManager) {
            spanCount = ((GridLayoutManager) layoutManager).getSpanCount();
        } else if (layoutManager instanceof StaggeredGridLayoutManager) {
            spanCount = ((StaggeredGridLayoutManager) layoutManager).getSpanCount();
        }
        return spanCount;
    }
    public void drawHorizontal(Canvas canvas, RecyclerView parent) {
        int childCount = parent.getChildCount();
        for (int i = 0; i < childCount; i++) {
            final View child = parent.getChildAt(i);
            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
            final int left = child.getLeft() - params.leftMargin;
            final int right = child.getRight() + params.rightMargin + mItemSize;
            final int top = child.getBottom() + params.bottomMargin;
            final int bottom = top + mItemSize;
            canvas.drawRect(left,top,right,bottom,mPaint);
        }
    }
    public void drawVertical(Canvas canvas, RecyclerView parent) {
        final int childCount = parent.getChildCount();
        for (int i = 0; i < childCount; i++) {
            final View child = parent.getChildAt(i);
            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
            final int top = child.getTop() - params.topMargin;
            final int bottom = child.getBottom() + params.bottomMargin;
            final int left = child.getRight() + params.rightMargin;
            final int right = left + mItemSize;
            canvas.drawRect(left,top,right,bottom,mPaint);
        }
    }
    @Override
    public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {
        int spanCount = getSpanCount(parent);
        int childCount = parent.getAdapter().getItemCount();
        if (isLastRow(parent, itemPosition, spanCount, childCount)){//如果是最后一行,不需要绘制底部
            outRect.set(0, 0, mItemSize, 0);
        } else if (isLastColum(parent, itemPosition, spanCount, childCount)){// 如果是最后一列,不需要绘制右边
            outRect.set(0, 0, 0, mItemSize);
        } else {
            outRect.set(0, 0, mItemSize,mItemSize);
        }
    }
    private boolean isLastColum(RecyclerView parent, int pos, int spanCount, int childCount) {
        RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
        if (layoutManager instanceof GridLayoutManager) {
            if ((pos + 1) % spanCount == 0){// 如果是最后一列,则不需要绘制右边
                return true;
            }
        } else if (layoutManager instanceof StaggeredGridLayoutManager) {
            int orientation = ((StaggeredGridLayoutManager) layoutManager).getOrientation();
            if (orientation == StaggeredGridLayoutManager.VERTICAL) {
                if ((pos + 1) % spanCount == 0){// 如果是最后一列,则不需要绘制右边
                    return true;
                }
            } else {
                childCount = childCount - childCount % spanCount;
                if (pos >= childCount)// 如果是最后一列,则不需要绘制右边
                    return true;
            }
        }
        return false;
    }
    private boolean isLastRow(RecyclerView parent, int pos, int spanCount, int childCount) {
        RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
        if (layoutManager instanceof GridLayoutManager) {
            childCount = childCount - childCount % spanCount;
            if (pos >= childCount)//最后一行
                return true;
        } else if (layoutManager instanceof StaggeredGridLayoutManager) {
            int orientation = ((StaggeredGridLayoutManager) layoutManager).getOrientation();
            if (orientation == StaggeredGridLayoutManager.VERTICAL){//纵向
                childCount = childCount - childCount % spanCount;
                if (pos >= childCount)//最后一行
                    return true;
            } else{ //横向
                if ((pos + 1) % spanCount == 0) {//是最后一行
                    return true;
                }
            }
        }
        return false;
    }
}

瀑布流布局分割线

瀑布流布局分割线的绘制可以参考网格布局的分割线

4.瀑布流布局适配器

一般瀑布流列表的列高度是不一致的,为了模拟不同的宽高,把String类型改成对象,然后初始化一个随机高度即可。

package com.example.hzhapplication;

public class ItemData {
    private String content;//item内容
    private int height;//item高度
    public ItemData() {
    }
    public ItemData(String content, int height) {
        this.content = content;
        this.height = height;
    }
    public String getContent() {
        return content;
    }
    public void setContent(String content) {
        this.content = content;
    }
    public int getHeight() {
        return height;
    }
    public void setHeight(int height) {
        this.height = height;
    }
}

对应的适配器代码:

package com.example.hzhapplication;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import androidx.recyclerview.widget.RecyclerView;

import java.util.List;

public class StaggeredGridAdapter extends RecyclerView.Adapter<StaggeredGridAdapter.MyViewHolder>{
    private List<ItemData> datas;
    private LayoutInflater inflater;

    public StaggeredGridAdapter(Context context, List<ItemData> datas){
        inflater=LayoutInflater.from(context);
        this.datas=datas;
    }

    //创建每一行的View 用RecyclerView.ViewHolder包装
    @Override
    public StaggeredGridAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View itemView=inflater.inflate(R.layout.recycler_item,parent,false);
        return new MyViewHolder(itemView);
    }

    //给每一行View填充数据
    @Override
    public void onBindViewHolder(StaggeredGridAdapter.MyViewHolder holder, int position) {
        ItemData itemData=datas.get(position);
        holder.textview.setText(itemData.getContent());
        //手动更改高度,不同位置的高度有所不同
        holder.textview.setHeight(itemData.getHeight());
    }

    //数据源的数量
    @Override
    public int getItemCount() {
        return datas.size();
    }

    class MyViewHolder extends RecyclerView.ViewHolder{
        private TextView textview;

        public MyViewHolder(View itemView) {
            super(itemView);
            textview= (TextView) itemView.findViewById(R.id.textview);
        }
    }
}

item对应布局文件

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
   <TextView
       android:id="@+id/textview"
       android:padding="10dp"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:textSize="20sp"/>
</FrameLayout>

5.添加header和footer

RecyclerView添加头部与底部是没有对应的api的,但是很多需求都会用到。于是只能自己通过适配器的getItemViewType方法实现这个功能
修改后的适配器代码:RecyclerHeadFootViewAdapter.java

public class RecyclerHeadFootViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{
    private List<String> datas;
    private LayoutInflater inflater;

    public static final int TYPE_HEADER=1;//header类型
    public static final int TYPE_FOOTER=2;//footer类型
    private View header=null;//头View
    private View footer=null;//脚View

    private RecyclerViewItemClick recyclerViewItemClick;

    public void setRecyclerViewItemClick(RecyclerViewItemClick recyclerViewItemClick) {
        this.recyclerViewItemClick = recyclerViewItemClick;
    }

    public  RecyclerHeadFootViewAdapter(Context context, List<String> datas){
        inflater=LayoutInflater.from(context);
        this.datas=datas;
    }

    //创建每一行的View 用RecyclerView.ViewHolder包装
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if(viewType==TYPE_HEADER){
            return new RecyclerView.ViewHolder(header){};
        }else if(viewType==TYPE_FOOTER){
            return new RecyclerView.ViewHolder(footer){};
        }
        View itemView=inflater.inflate(R.layout.recycler_item,parent,false);
        return new MyViewHolder(itemView);
    }

    //给每一行View填充数据
    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder,final int position){
        if(getItemViewType(position)==TYPE_HEADER||getItemViewType(position)==TYPE_FOOTER){
            return;
        }
        MyViewHolder myholder= (MyViewHolder) holder;
        myholder.textview.setText(datas.get(getRealPosition(position)));
        if(recyclerViewItemClick!=null) {
            myholder.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    recyclerViewItemClick.onItemClick(getRealPosition(position),position);
                }
            });
        }
    }

    //如果有头部 position的位置是从1开始的  所以需要-1
    public int getRealPosition(int position){
        return header==null?position:position-1;
    }

    //数据源的数量
    @Override
    public int getItemCount() {
        if(header == null && footer == null){//没有head跟foot
            return datas.size();
        }else if(header == null && footer != null){//head为空&&foot不为空
            return datas.size() + 1;
        }else if (header != null && footer == null){//head不为空&&foot为空
            return datas.size() + 1;
        }else {
            return datas.size() + 2;//head不为空&&foot不为空
        }
    }

    @Override
    public int getItemViewType(int position){
        //如果头布局不为空&&位置是第一个那就是head类型
        if(header!=null&&position==0){
            return TYPE_HEADER;
        }else if(footer!=null&&position==getItemCount()-1){//如果footer不为空&&最后一个
            return TYPE_FOOTER;
        }
        return super.getItemViewType(position);
    }

    public void setHeader(View header) {
        this.header = header;
        notifyItemInserted(0);//在第一行插入一条数据,然后刷新
    }

    public void setFooter(View footer) {
        this.footer = footer;
        notifyItemInserted(datas.size()-1);//在尾部插入一条数据,然后刷新
    }

    public interface RecyclerViewItemClick{
        /**
         * item点击
         * @param realPosition 数据源position
         * @param position view position
         */
        void onItemClick(int realPosition,int position);
    }

    class MyViewHolder extends RecyclerView.ViewHolder{
        private TextView textview;

        public MyViewHolder(View itemView) {
            super(itemView);
            textview= (TextView) itemView.findViewById(R.id.textview);
        }
    }
}
  • getltemCount:有header和footer时,需要在源数据长度基础上进行增加。
  • getltem ViewType:通过getltemViewType判断不同的类型。
  • onCreateViewHolder:通过不同的类型创建item的View.
  • onBindViewHolder:如果是header与footer类型是不需要绑定数据的,header与 footer的View
    一般在Activity 页面中创建,不需要处理,所以这两种类型就不往下执行。如果有头布局,
    position==0的位置就会被header占用,但是数据源也就是集合的下标是从0开始的,所以这
    里需要改为-1.
  • setHeader:设置头布局,在第一行插入一条数据,然后刷新。注意,这个方法调用后会有插
    入的动画,这个动画可以使用默认的,也可以自己定义。
  • setFooter:设置尾部布局,在尾部插入一条数据,然后刷新。

添加 header与footer的方法终于封装好了,在Activity页面中只需要两行代码就能添加 header,
与ListView 调用 addHeader方法一样简单。这里需要注意的是,初始化View时,inflate方法需要
三个参数。

  • resource:布局文件资源id.
  • root:父View.
  • attachToRoot:需要传入一个boolean类型的值。如果传入true,布局文件将转化为View并绑定到root,然后返回root作为根节点的整个View.如果传入false,布局文件转化为View但不绑定到root,返回以布局文件根节点为根节点的View.
       //添加header
        View header=LayoutInflater.from(this).inflate(R.layout.recycler_header,recyclerView,false);
        adapter.setHeader(header);

        //添加footer
        View footer=LayoutInflater.from(this).inflate(R.layout.recycler_footer,recyclerView,false);
        adapter.setFooter(footer);

6.item点击事件&&增加或删除带动画的效果

当调用RecyclerView的setOnItemClickListener方法时,发现居然没有该方法。用RecyclerView要习惯什么东西都自己封装。
首先从adapter入手,内部写一个接口、一个实例变量,提供一个公共方法,设置监听。

private  RecyclerViewItemClick recyclerViewItemClick;
    public void setRecyclerViewItemClick(RecyclerViewItemClick recyclerViewItemClick)
    {
     this.recyclerViewItemClick = recyclerViewItemClick;
    }
    public  interface RecyclerViewItemClick
    {
        /*
        * item点击
        * @param realPosition 数据源position
        * @param position view position
        * */
        void  onItemClick(int position);
    }

在onBindViewHolder方法中为item监听点击事件

if(recyclerViewItemClick!=null)
        {
            holder.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    recyclerViewItemClick.onItemClick(position);
                }
            });
        }

在Activity页面的onCreate方法中进行监听,顺便设置item增加或删除动画,用的是SDK自带的动画

adapter.setRecyclerViewItemClick(recyclerViewItemClick);
recyclerView.setItemAnimator(new DefaultItemAnimator());
private RecyclerViewAdapter.RecyclerViewItemClick recyclerViewItemClick=new RecyclerViewAdapter.RecyclerViewItemClick() {
        @Override
        public void onItemClick(int position) {
            Log.i("ansen","删除数据:"+position+" view位置:"+position);
            Log.i("ansen","当前位置:"+position+" 更新item数量:"+(adapter.getItemCount()-position-1));
            data.remove(position);//删除数据源
            adapter.notifyItemRemoved(position);//item删除动画
            //更新position至adapter.getItemCount()-1的数据
            adapter.notifyItemRangeChanged(position,adapter.getItemCount()-position-1);
        }
    };

四、SwipeRefreshLayout(下拉刷新)

先将循环布局最外层的控件改为

androidx.swiperefreshlayout.widget.SwipeRefreshLayout

注意:SwipeRefreshLayout控件只允许有一个子元素,子元素一般是ListView或者RecyclerView
然后仅需在活动文件中添加如下代码即可

swipeRefreshLayout = (SwipeRefreshLayout)findViewById(R.id.xiala);
        //监听刷新状态
        swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                if(data.size()>0)
                {
                    data.remove(0);
                    adapter.notifyDataSetChanged();//更新第一条记录
                    swipeRefreshLayout.setRefreshing(false);
                    //false刷新完成,true,正在刷新
                }
            }
        });

五、ViewPager(翻页视图)

ViewPage的用法与ListView相似,需要设置PagerAdapter来完成页面和数据的绑定,这个PagerAdapter是一个基类适配器,经常用来实现App引导图。它的子类有FragmentPagerAdapter和FragmentStatePagerAdapter,和Fragment一起使用。
布局首先查找Viewpager控件,设置缓存页数,设置当前显示第几个Fragment,然后初始化Fragment适配器,这个适配器是我们自己写的集成自FragmentStatePagerAdapter,接下来调用适配器addFragment方法将要显示的Fragme添加进去。最后调用ViewPager的setAdapter方法将适配器设置进去。当想知道ViewPager滑动到哪个Fragment时,可以通过addOnPageChangeListener方法来设置监听

public class fanye extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_fanye);
        ViewPager vPager=(ViewPager) findViewById(R.id.fanye);
        vPager.setOffscreenPageLimit(2);//设置缓存页数
        vPager.setCurrentItem(0);//设置当前显示的item 0表示显示第一个
        FragmentAdapter pagerAdapter = new FragmentAdapter(getSupportFragmentManager());
        pagerAdapter.addFragment(new FragmentTest("页面1",android.R.color.holo_red_dark));
        pagerAdapter.addFragment(new FragmentTest("页面2",android.R.color.holo_green_dark));
        pagerAdapter.addFragment(new FragmentTest("页面3",android.R.color.holo_blue_bright));
        pagerAdapter.addFragment(new FragmentTest("页面4",android.R.color.holo_green_dark));
        //给ViewPager设置适配器
        vPager.setAdapter(pagerAdapter);
        //页面改变监听
        vPager.addOnPageChangeListener(onPageChangeListener);
    }
    private ViewPager.OnPageChangeListener onPageChangeListener=new ViewPager.OnPageChangeListener() {
        //页面滑动
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {}
        //页面选择
        @Override
        public void onPageSelected(int position) {
            Log.i("MainActivity","选中了页面"+(position+1));
        }
        //页面滑动状态改变
        @Override
        public void onPageScrollStateChanged(int state) {}
    };
}

翻页视图的适配器FragmentAdapter.java

ublic class FragmentAdapter extends FragmentStatePagerAdapter {
    private final List<Fragment> fragmentList = new ArrayList<Fragment>();
    public FragmentAdapter(FragmentManager fm) {
        super(fm);
    }
    @Override
    public Fragment getItem(int arg0) {
        return fragmentList.get(arg0);
    }
    @Override
    public int getCount() {
        return fragmentList.size();
    }
    public void addFragment(Fragment fragment) {
        fragmentList.add(fragment);
    }
}

FragmentTest.java

public class FragmentTest extends Fragment {
    private String content;
    private int backgroundResourceId;

    public FragmentTest(String content,int backgroundResourceId){
        this.content=content;
        this.backgroundResourceId=backgroundResourceId;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
        View rootView=LayoutInflater.from(getActivity()).inflate(R.layout.fragment_test, null);
        TextView tvContent= (TextView) rootView.findViewById(R.id.tv_content);
        tvContent.setText(content);

        rootView.setBackgroundResource(backgroundResourceId);
        return rootView;
    }
}

部分内容和代码参考自《Android app开发从入门到精通》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

for-nothing

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值