Android RefreshLayout实现下拉刷新布局

Android RefreshLayout实现下拉刷新布局,第1张

概述项目中需要下拉刷新的功能,但是这个View不是ListView这类的控件,需要ViewGroup实现这个功能,一开始网上大略找了一下,没发现特别合适的,代码也是没怎么看懂,所以决定还是自己写一个。

项目中需要下拉刷新的功能,但是这个VIEw不是ListVIEw这类的控件,需要VIEwGroup实现这个功能,一开始网上大略找了一下,没发现特别合适的,代码也是没怎么看懂,所以决定还是自己写一个。

  于是翻出XListVIEw的源码看是一点一点看,再大致理解了XlisvIEw源码,终于决定自己动手啦

  为了省事,headVIEw还是用了XListVIEw的headVIEw,省了很多事:)

  下拉刷新,下拉刷新,肯定是先实现下拉功能,最开始我是打算通过 extends ScrollVIEw 来实现,因为有现成的滚动效果嘛,可是实际因为两个原因放弃了:

1、ScrollVIEw下只能有一个子控件VIEw,虽然在    Scroll下添加一个VIEwGroup,然后讲headVIEw动态添加进前面的VIEwGroup,但是我还是比较习惯studio的可视化预览,总觉得不直观!

2、  ScrollVIEw内嵌ListVIEw时会发生    冲突,还需要去重写ListVIEw。于是放弃换个思路!

 关于上面的原因1:动态添加headVIEw进ScrollVIEw的中GroupVIEw中,可以在重写ScrollVIEw的onVIEwAdded()方法,将初始化时解析的headVIEw添加进子GroupVIEw

@OverrIDe public voID onVIEwAdded(VIEw child) {   super.onVIEwAdded(child);   //因为headVIEw要在最上面,最先想到的就是Vertical的linearLayout   linearLayout linearLayout = (linearLayout) getChildAt(0);   linearLayout.addVIEw(vIEw,0); } 

  换个思路,通过extends linearLayout来实现吧!
先做准备工作,我们需要一个headerVIEw以及要获取到headerVIEw的高度,还有初始时Layout的高度

private voID initVIEw(Context context) {    mheaderVIEw = new SRefreshheader(context);    mheaderVIEwContent = (relativeLayout) mheaderVIEw.findVIEwByID(R.ID.sListvIEw_header_content);    setorIEntation(VERTICAL);    addVIEw(mheaderVIEw,0);    getheaderVIEwHeight();    getVIEwHeight();  } 

mheaderVIEw = new SRefreshheader(context);
通过构造方法实例化headerVIEw

mheaderVIEwContent = (relativeLayout)

mheaderVIEw.findVIEwByID(R.ID.sListvIEw_header_content);

 这是解析headerVIEw内容区域IEw,等会儿要获取这个vIEw的高度,你肯定会问为啥不用上面的mheaderVIEw来获取高度,点进构造方法里可以看到如下代码

// 初始情况,设置下拉刷新vIEw高度为0 LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT,0); mContainer = (linearLayout) LayoutInflater.from(context).inflate(R.layout.ListvIEw_head_vIEw_layout,null); w(mContainer,lp); 

如果直接获取mheaderVIEw的高度 那肯定是0
getheaderVIEwHeight();
getVIEwHeight();

分别是获取headerVIEw的高度和Layout的初始高度

/**   * 获取headVIEw高度   */   private voID getheaderVIEwHeight() {     VIEwTreeObserver vto2 = mheaderVIEwContent.getVIEwTreeObserver();     vto2.addOnGlobalLayoutListener(new VIEwTreeObserver.OnGlobalLayoutListener() {       @OverrIDe       public voID onGlobalLayout() {         mheaderVIEwHeight = mheaderVIEwContent.getHeight();         mheaderVIEwContent.getVIEwTreeObserver().removeGlobalOnLayoutListener(this);       }     });   }    /**   * 获取SRefreshLayout当前实例的高度   */   private voID getVIEwHeight() {     VIEwTreeObserver thisVIEw = getVIEwTreeObserver();     thisVIEw.addOnGlobalLayoutListener(new VIEwTreeObserver.OnGlobalLayoutListener() {       @OverrIDe       public voID onGlobalLayout() {         SRefreshLayout.this.mHeight = SRefreshLayout.this.getHeight();         SRefreshLayout.this.getVIEwTreeObserver().removeGlobalOnLayoutListener(this);       }     });   } 

准备工作完成了,接下来就是要成下拉 *** 作了
到这里,肯定一下就想到了ontouchEvent()方法,是的!现在就开始在这里施工

实现下拉一共 会经历三个过程
ACTION_UP→ACTION_MOVE→ACTION_UP
在ACTION_UP事件中,也就是手指按下的时候,我们需要做的只是记录按下时候的坐标

switch (ev.getAction()) {       case MotionEvent.ACTION_DOWN:         //记录起始高度         mLastY = ev.getRawY();//记录按下时的Y坐标         break; 

然后就是ACTION_MOVE事件了,这里是最重要的,因为下拉时headVIEw和Layout的高度变化都在这里进行

case MotionEvent.ACTION_MOVE:        if (!isRefreashing)          isRefreashing = true;        final float deltaY = ev.getRawY() - mLastY;        mLastY = ev.getRawY();        updateheaderVIEwHeight(deltaY / 1.8f);//按一定比例缩小移动距离        updateHeight();        break; 

里面的updateheaderVIEwHeight和updateHeight分别是改变headerVIEw的高度和Layout的高度

 private voID updateHeight() {     VIEwGroup.LayoutParams lp = getLayoutParams();     //更新当前layout实例高度为headerVIEw高度加上最初的layout高度     //如果不更新layout 会造成内容高度压缩 无法保持比例     lp.height = (mHeight + mheaderVIEw.getVisiableHeight());     setLayoutParams(lp);   }    private voID updateheaderVIEwHeight(float space) { //    if (space < 0) //      space = 0; //    int factHeight = (int) (space - mheaderVIEwHeight);     if (mheaderVIEw.getStatus() != SRefreshheader.STATE_REFRESHING) {       //如果不处于刷新中同时如果高度       if (mheaderVIEw.getVisiableHeight() < mheaderVIEwHeight * 2 && mheaderVIEw.getStatus() != SRefreshheader.STATE_norMAL) {         mheaderVIEw.setState(SRefreshheader.STATE_norMAL);       }       if (mheaderVIEw.getVisiableHeight() > mheaderVIEwHeight * 2 && mheaderVIEw.getStatus() != SRefreshheader.STATE_READY) {         mheaderVIEw.setState(SRefreshheader.STATE_READY);       }     }     mheaderVIEw.setVisiableHeight((int) space         + mheaderVIEw.getVisiableHeight());   } 

更新header高度时,通过下拉的距离来判断是否到达刷新的距离,上面代码中我设定的是到达mheaderVIEw初始高度的两倍,就进入“释放刷新”的状态,如果没有达到则保持“下拉刷新”的状态
headerVIEw中的状态一共设定了3个分别是

public final static int STATE_norMAL = 0;//下拉刷新  public final static int STATE_READY = 1;//释放刷新  public final static int STATE_REFRESHING = 2;//刷新中 

更新高度的方法headerVIEw和layout都是相同的,就是原高度加上移动的距离重新赋给headerVIEw或者layout

mheaderVIEw.setVisiableHeight((int) space 
               + mheaderVIEw.getVisiableHeight()); 

最后就是ACTION_UP事件了就是手指离开屏幕的时候,在这里我们需要根据headerVIEw目前状态来决定headerVIEw的最终状态!

case MotionEvent.ACTION_UP:         //松开时         //避免点击事件触发         if (!isRefreashing)           break;         //如果headVIEw状态处于READY状态 则说明松开时应该进入REFRESHING状态         if (mheaderVIEw.getStatus() == SRefreshheader.STATE_READY) {           mheaderVIEw.setState(SRefreshheader.STATE_REFRESHING);         }         //根据状态重置SrefreshLayout当前实例和headVIEw高度         resetheadVIEw(mheaderVIEw.getStatus());         reset(mheaderVIEw.getStatus());         mLastY = -1;//重置坐标         break; 

resetheadVIEw和reset分别是重置headerVIEw高度和layout高度的方法

private voID reset(int status) {     VIEwGroup.LayoutParams lp = getLayoutParams();     switch (status) {       case SRefreshheader.STATE_REFRESHING:         lp.height = mHeight + mheaderVIEwHeight;         break;       case SRefreshheader.STATE_norMAL:         lp.height = mHeight;         break;     }     setLayoutParams(lp);   }    private voID resetheadVIEw(int status) {     switch (status) {       case SRefreshheader.STATE_REFRESHING:         mheaderVIEw.setVisiableHeight(mheaderVIEwHeight);         break;       case SRefreshheader.STATE_norMAL:         mheaderVIEw.setVisiableHeight(0);         break;     }   } 

实现方式也是一样的。根据状态来判断,如果是处于刷新中,那headerVIEw应该正常显示,并且高度是初始的高度,如果处于norMAL,也就是"下拉刷新"状态,那么说未触发刷新,重置时,headerVIEw应该被隐藏,也就是高度重置为0

到这里下拉刷新 *** 作也基本完成了,还需要加一个回调接口进行通知

interface OnRefreshListener {     voID onRefresh();   } 
case MotionEvent.ACTION_UP:         //松开时         //避免点击事件触发         if (!isRefreashing)           break;         //如果headVIEw状态处于READY状态 则说明松开时应该进入REFRESHING状态         if (mheaderVIEw.getStatus() == SRefreshheader.STATE_READY) {           mheaderVIEw.setState(SRefreshheader.STATE_REFRESHING);           if (mOnRefreshListener != null)             mOnRefreshListener.onRefresh();         }         //根据状态重置SrefreshLayout当前实例和headVIEw高度         resetheadVIEw(mheaderVIEw.getStatus());         reset(mheaderVIEw.getStatus());         mLastY = -1;//重置坐标         break; 

好,到这里就基本完成了,试试效果吧。咦,发现一个问题,嵌套ListVIEw的时候为什么这个Layout不能执行下拉刷新!仔细想想应该是事件分发的问题,还需要处理一下事件的拦截!
关于事件拦截的处理,阅读了鸿洋大神写的vIEwgroup事件分发的博客和AndroID-ultra-Pull-To-Refresh的部分源码,从中找到了解决办法:

@OverrIDe   public boolean onIntercepttouchEvent(MotionEvent ev) {     AbsListVIEw absListVIEw = null;     for (int n = 0; n < getChildCount(); n++) {       if (getChildAt(n) instanceof AbsListVIEw) {         absListVIEw = (ListVIEw) getChildAt(n);         Logs.v("查找到ListVIEw");       }     }     if (absListVIEw == null)       return super.onIntercepttouchEvent(ev);     switch (ev.getAction()) {       case MotionEvent.ACTION_DOWN:         mStartY = ev.getRawY();         break;       case MotionEvent.ACTION_MOVE:         float space = ev.getRawY() - mStartY;         Logs.v("space:" + space);         if (space > 0 && !absListVIEw.canScrollVertically(-1) && absListVIEw.getFirstVisibleposition() == 0) {           Logs.v("拦截成功");           return true;         } else {           Logs.v("不拦截");           return false;         }     }     return super.onIntercepttouchEvent(ev);   } 

其中

if (space > 0 && !absListVIEw.canScrollVertically(-1) && absListVIEw.getFirstVisibleposition() == 0)
space即移动的距离 canScrollVertically()是判断ListVIEw能否在垂直方向上滚动,参数为负数时代表向上,为正数时代码向下滚动,最后一个就是ListVIEw第一个可见的item的postion

加上上面的事件拦截处理,一个可以满足开头提到的需求的VIEwgroup也就完成了!

下面贴上Layout的源码和headerVIEw(直接使用的XListVIEw的headerVIEw)的源码

public class SRefreshLayout extends linearLayout {   private SRefreshheader mheaderVIEw;   private relativeLayout mheaderVIEwContent;   private boolean isRefreashing;   private float mLastY = -1;//按下的起始高度   private int mheaderVIEwHeight;//headerVIEw内容高度   private int mHeight;//布局高度   private float mStartY;    interface OnRefreshListener {     voID onRefresh();   }    public OnRefreshListener mOnRefreshListener;    public SRefreshLayout(Context context) {     super(context);     initVIEw(context);   }    public SRefreshLayout(Context context,AttributeSet attrs) {     super(context,attrs);     initVIEw(context);   }    public SRefreshLayout(Context context,AttributeSet attrs,int defStyleAttr) {     super(context,attrs,defStyleAttr);     initVIEw(context);   }    private voID initVIEw(Context context) {     mheaderVIEw = new SRefreshheader(context);     mheaderVIEwContent = (relativeLayout) mheaderVIEw.findVIEwByID(R.ID.sListvIEw_header_content);     setorIEntation(VERTICAL);     addVIEw(mheaderVIEw,0);     getheaderVIEwHeight();     getVIEwHeight();   }    /**    * 获取headVIEw高度    */   private voID getheaderVIEwHeight() {     VIEwTreeObserver vto2 = mheaderVIEwContent.getVIEwTreeObserver();     vto2.addOnGlobalLayoutListener(new VIEwTreeObserver.OnGlobalLayoutListener() {       @OverrIDe       public voID onGlobalLayout() {         mheaderVIEwHeight = mheaderVIEwContent.getHeight();         mheaderVIEwContent.getVIEwTreeObserver().removeGlobalOnLayoutListener(this);       }     });   }    /**    * 获取SRefreshLayout当前实例的高度    */   private voID getVIEwHeight() {     VIEwTreeObserver thisVIEw = getVIEwTreeObserver();     thisVIEw.addOnGlobalLayoutListener(new VIEwTreeObserver.OnGlobalLayoutListener() {       @OverrIDe       public voID onGlobalLayout() {         SRefreshLayout.this.mHeight = SRefreshLayout.this.getHeight();         SRefreshLayout.this.getVIEwTreeObserver().removeGlobalOnLayoutListener(this);       }     });   }    @OverrIDe   public boolean onIntercepttouchEvent(MotionEvent ev) {     AbsListVIEw absListVIEw = null;     for (int n = 0; n < getChildCount(); n++) {       if (getChildAt(n) instanceof AbsListVIEw) {         absListVIEw = (ListVIEw) getChildAt(n);         Logs.v("查找到ListVIEw");       }     }     if (absListVIEw == null)       return super.onIntercepttouchEvent(ev);     switch (ev.getAction()) {       case MotionEvent.ACTION_DOWN:         mStartY = ev.getRawY();         break;       case MotionEvent.ACTION_MOVE:         float space = ev.getRawY() - mStartY;         Logs.v("space:" + space);         if (space > 0 && !absListVIEw.canScrollVertically(-1) && absListVIEw.getFirstVisibleposition() == 0) {           Logs.v("拦截成功");           return true;         } else {           Logs.v("不拦截");           return false;         }     }     return super.onIntercepttouchEvent(ev);   }    @OverrIDe   public boolean ontouchEvent(MotionEvent ev) {     if (mLastY == -1)       mLastY = ev.getRawY();     switch (ev.getAction()) {       case MotionEvent.ACTION_DOWN:         //记录起始高度         mLastY = ev.getRawY();//记录按下时的Y坐标         break;       //手指离开屏幕时       case MotionEvent.ACTION_UP:         //松开时         //避免点击事件触发         if (!isRefreashing)           break;         //如果headVIEw状态处于READY状态 则说明松开时应该进入REFRESHING状态         if (mheaderVIEw.getStatus() == SRefreshheader.STATE_READY) {           mheaderVIEw.setState(SRefreshheader.STATE_REFRESHING);           if (mOnRefreshListener != null)             mOnRefreshListener.onRefresh();         }         //根据状态重置SrefreshLayout当前实例和headVIEw高度         resetheadVIEw(mheaderVIEw.getStatus());         reset(mheaderVIEw.getStatus());         mLastY = -1;//重置坐标         break;       case MotionEvent.ACTION_MOVE:         if (!isRefreashing)           isRefreashing = true;         final float deltaY = ev.getRawY() - mLastY;         mLastY = ev.getRawY();         updateheaderVIEwHeight(deltaY / 1.8f);//按一定比例缩小移动距离         updateHeight();         break;     }     return super.ontouchEvent(ev);   }     private voID reset(int status) {     VIEwGroup.LayoutParams lp = getLayoutParams();     switch (status) {       case SRefreshheader.STATE_REFRESHING:         lp.height = mHeight + mheaderVIEwHeight;         break;       case SRefreshheader.STATE_norMAL:         lp.height = mHeight;         break;     }     setLayoutParams(lp);   }    private voID resetheadVIEw(int status) {     switch (status) {       case SRefreshheader.STATE_REFRESHING:         mheaderVIEw.setVisiableHeight(mheaderVIEwHeight);         break;       case SRefreshheader.STATE_norMAL:         mheaderVIEw.setVisiableHeight(0);         break;     }   }    private voID updateHeight() {     VIEwGroup.LayoutParams lp = getLayoutParams();     //更新当前layout实例高度为headerVIEw高度加上最初的layout高度     //如果不更新layout 会造成内容高度压缩 无法保持比例     lp.height = (mHeight + mheaderVIEw.getVisiableHeight());     setLayoutParams(lp);   }    private voID updateheaderVIEwHeight(float space) { //    if (space < 0) //      space = 0; //    int factHeight = (int) (space - mheaderVIEwHeight);     if (mheaderVIEw.getStatus() != SRefreshheader.STATE_REFRESHING) {       //如果不处于刷新中同时如果高度       if (mheaderVIEw.getVisiableHeight() < mheaderVIEwHeight * 2 && mheaderVIEw.getStatus() != SRefreshheader.STATE_norMAL) {         mheaderVIEw.setState(SRefreshheader.STATE_norMAL);       }       if (mheaderVIEw.getVisiableHeight() > mheaderVIEwHeight * 2 && mheaderVIEw.getStatus() != SRefreshheader.STATE_READY) {         mheaderVIEw.setState(SRefreshheader.STATE_READY);       }     }     mheaderVIEw.setVisiableHeight((int) space         + mheaderVIEw.getVisiableHeight());   }     public voID stopRefresh() {     if (mheaderVIEw.getStatus() == SRefreshheader.STATE_REFRESHING) {       mheaderVIEw.setState(SRefreshheader.STATE_norMAL);       resetheadVIEw(SRefreshheader.STATE_norMAL);       reset(SRefreshheader.STATE_norMAL);     }   }    public voID setonRefreshListener(OnRefreshListener onRefreshListener) {     this.mOnRefreshListener = onRefreshListener;   } } 

public class SRefreshheader extends linearLayout {   private linearLayout mContainer;   private int mState = STATE_norMAL;    private Animation mRotateUpAnim;   private Animation mRotateDownAnim;    private final int ROTATE_ANIM_DURATION = 500;    public final static int STATE_norMAL = 0;//下拉刷新   public final static int STATE_READY = 1;//释放刷新   public final static int STATE_REFRESHING = 2;//刷新中   private ImageVIEw mheadArrowImage;   private TextVIEw mheadLastRefreashTimeTxt;   private TextVIEw mheadHintTxt;   private TextVIEw mheadLastRefreashTxt;   private Progressbar mRefreshingProgress;    public SRefreshheader(Context context) {     super(context);     initVIEw(context);   }    /**    * @param context    * @param attrs    */   public SRefreshheader(Context context,attrs);     initVIEw(context);   }    private voID initVIEw(Context context) {     // 初始情况,设置下拉刷新vIEw高度为0     LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT,0);     mContainer = (linearLayout) LayoutInflater.from(context).inflate(R.layout.ListvIEw_head_vIEw_layout,null);     addVIEw(mContainer,lp);     setGravity(Gravity.BottOM);      mheadArrowImage = (ImageVIEw) findVIEwByID(R.ID.sListvIEw_header_arrow);     mheadLastRefreashTimeTxt = (TextVIEw) findVIEwByID(R.ID.sListvIEw_header_time);     mheadHintTxt = (TextVIEw) findVIEwByID(R.ID.sListvIEw_header_hint_text);     mheadLastRefreashTxt = (TextVIEw) findVIEwByID(R.ID.sListvIEw_header_last_refreash_txt);     mRefreshingProgress = (Progressbar) findVIEwByID(R.ID.sListvIEw_header_progressbar);      mRotateUpAnim = new RotateAnimation(0.0f,-180.0f,Animation.relative_TO_SELF,0.5f,0.5f);     mRotateUpAnim.setDuration(ROTATE_ANIM_DURATION);     mRotateUpAnim.setFillAfter(true);     mRotateDownAnim = new RotateAnimation(-180.0f,0.0f,0.5f);     mRotateDownAnim.setDuration(ROTATE_ANIM_DURATION);     mRotateDownAnim.setFillAfter(true);   }    public voID setState(int state) {     if (state == mState) return;      if (state == STATE_REFRESHING) {  // 显示进度       mheadArrowImage.clearanimation();       mheadArrowImage.setVisibility(VIEw.INVISIBLE);       mRefreshingProgress.setVisibility(VIEw.VISIBLE);     } else {  // 显示箭头图片       mheadArrowImage.setVisibility(VIEw.VISIBLE);       mRefreshingProgress.setVisibility(VIEw.INVISIBLE);     }     switch (state) {       case STATE_norMAL:         if (mState == STATE_READY) {           mheadArrowImage.startAnimation(mRotateDownAnim);         }         if (mState == STATE_REFRESHING) {           mheadArrowImage.clearanimation();         }         mheadHintTxt.setText("下拉刷新");         break;       case STATE_READY:         if (mState != STATE_READY) {           mheadArrowImage.clearanimation();           mheadArrowImage.startAnimation(mRotateUpAnim);           mheadHintTxt.setText("松开刷新");         }         break;       case STATE_REFRESHING:         mheadHintTxt.setText("正在刷新");         break;       default:     }      mState = state;   }    public voID setVisiableHeight(int height) {     if (height < 0)       height = 0;     LayoutParams lp = (LayoutParams) mContainer         .getLayoutParams();     lp.height = height;     mContainer.setLayoutParams(lp);   }     public int getStatus() {     return mState;   }    public int getVisiableHeight() {     return mContainer.getHeight();   } } 

最后是布局文件

<linearLayout xmlns:androID="http://schemas.androID.com/apk/res/androID"   androID:layout_wIDth="match_parent"   androID:layout_height="wrap_content"   androID:gravity="bottom">    <relativeLayout     androID:ID="@+ID/sListvIEw_header_content"     androID:layout_wIDth="match_parent"     androID:layout_height="60dp">      <linearLayout       androID:ID="@+ID/sListvIEw_header_text"       androID:layout_wIDth="wrap_content"       androID:layout_height="wrap_content"       androID:layout_centerInParent="true"       androID:gravity="center"       androID:orIEntation="vertical">        <TextVIEw         androID:ID="@+ID/sListvIEw_header_hint_text"         androID:layout_wIDth="wrap_content"         androID:layout_height="wrap_content"         androID:text="下拉刷新" />        <linearLayout         androID:layout_wIDth="wrap_content"         androID:layout_height="wrap_content"         androID:layout_margintop="3dp">          <TextVIEw           androID:ID="@+ID/sListvIEw_header_last_refreash_txt"           androID:layout_wIDth="wrap_content"           androID:layout_height="wrap_content"           androID:text="上次刷新时间"           androID:textSize="12sp" />          <TextVIEw           androID:ID="@+ID/sListvIEw_header_time"           androID:layout_wIDth="wrap_content"           androID:layout_height="wrap_content"           androID:textSize="12sp" />       </linearLayout>     </linearLayout>       <Progressbar       androID:ID="@+ID/sListvIEw_header_progressbar"       androID:layout_wIDth="30dp"       androID:layout_height="30dp"       androID:layout_centerVertical="true"       androID:layout_toleftOf="@ID/sListvIEw_header_text"       androID:visibility="invisible" />      <ImageVIEw       androID:ID="@+ID/sListvIEw_header_arrow"       androID:layout_wIDth="wrap_content"       androID:layout_height="wrap_content"       androID:layout_alignleft="@ID/sListvIEw_header_progressbar"       androID:layout_centerVertical="true"       androID:layout_toleftOf="@ID/sListvIEw_header_text"       androID:src="@drawable/mmtListvIEw_arrow" />    </relativeLayout>  </linearLayout> 

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程小技巧。

总结

以上是内存溢出为你收集整理的Android RefreshLayout实现下拉刷新布局全部内容,希望文章能够帮你解决Android RefreshLayout实现下拉刷新布局所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1141457.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-31
下一篇 2022-05-31

发表评论

登录后才能评论

评论列表(0条)

保存