Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android RecyclerView 上拉加載更多及下拉刷新功能的實現方法

Android RecyclerView 上拉加載更多及下拉刷新功能的實現方法

編輯:關於Android編程

RecyclerView 已經出來很久了,但是在項目中之前都使用的是ListView,最近新的項目上了都大量的使用了RecycleView.尤其是瀑布流的下拉刷新,網上吧啦吧啦沒有合適的自己總結了一哈。

先貼圖上來看看:

這裡寫圖片描述 

 
這裡寫圖片描述

使用RecyclerView實現上拉加載更多和下拉刷新的功能我自己有兩種方式:

1.使用系統自帶的Android.support.v4.widget.SwipeRefreshLayout這個控價來實現。

2.自定義的裡面帶有RecyleView的控件。

使用RecycleView很不好添加頭部,之前在使用listview當中自己可以添加header和bootm,但是RecycleView好像不是那麼的好操作。對於第一種使用系統自帶的Android.support.v4.widget.SwipeRefreshLayout來實現的,也很好用,但是產品一般不要這種下拉刷新,為了讓自己顯得牛逼,他一般會搞一個自己的帶有動畫,這就比較扯淡了。。。所以就只能用方法2了。

大致說一哈方法2的實現方式,父布局為ViewGroup,裡面添加View第一個為控件為header第二個控件為RecycleView,至於最底部的下拉加載更多試圖,通過RecycleViw的Adapter來添加。

有了思路就搞起來:

package com.krain.srecyclerview.fruitview;
import android.content.Context;
import android.graphics.drawable.AnimationDrawable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import com.krain.srecyclerview.R;
/**
* Created by dafuShao on 2016/9/9 0009.
*
*/
public class ElizabethView extends FrameLayout {
private ImageView imageView;
private AnimationDrawable animationDrawable;
public ElizabethView(Context context) {
super(context);
initview(context);
}
public ElizabethView(Context context, AttributeSet attrs) {
super(context, attrs);
initview(context);
}
public ElizabethView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initview(context);
}
private void initview(Context context){
View view= LayoutInflater.from(context).inflate(R.layout.elizabeth_item,null);
imageView=(ImageView) view.findViewById(R.id.elizabeth_im);
animationDrawable= (AnimationDrawable) imageView.getBackground();
addView(view);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
//開始動畫
public void startAnim(){
animationDrawable.start();
}
//停止動畫
public void stopAnim(){
animationDrawable.stop();
}
}

這是頭部控價很簡單裡面有一個小的臭蛋眼睛左右擠一哈的效果就不貼圖了。

下面是自定義的包含RecyclerView的控件代碼如下:

package com.krain.srecyclerview.srecyclerview;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.support.v4.view.MotionEventCompat;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.Scroller;
import android.widget.TextView;
import com.krain.srecyclerview.R;
import com.krain.srecyclerview.fruitview.ElizabethView;
public class SRecyclerView extends ViewGroup {
Context context;
RecyclerView mRecyclerView;
ElizabethView mHeaderView;
TextView mFootViewTips;//footview的文字顯示
AdapterWrapper mAdapter;
boolean mIsTop = true;//是否滑動到了最頂部
RecyclerView.LayoutManager mLayoutManager;
int mLastVisibleItem;
int mFirstVisibleItem;
OnRecyclerStatusChangeListener mRecyclerChangeListener;
int mStatus;//當前狀態
int mHeadviewHeight;//headview的高度
Scroller mScroller;
int mFristScollerY;//最開始的getscrolly
boolean mHasFooter;//是否有上拉加載的功能
boolean mShowFootVisible;//是否顯示FOOTERview在mHasFooter為true的時候生效
boolean mHasRefresh = true;//是否支持下拉刷新
private final int DEFAULT_MIN_PAGEINDEX = 1;//默認最小的頁數
int mMaxPage = DEFAULT_MIN_PAGEINDEX;//分頁的總頁數
int mCurrentPage = DEFAULT_MIN_PAGEINDEX;//當前的頁數,從1開始
private final int STATUS_NORMAL = 0, STATUS_REFRESH = 1, STATUS_LOAD = 2;
private final int MSG_LOAD_COMPLETE = 1, MSG_REFRESH_COMPLETE = 0;//handle的常量
private final int DELAY_LOAD_COMPLETE = 1000, DELAY_REFRESH_COMPLETE = 1000;//加載完成延時回收的時間
public SRecyclerView(Context context) {
super(context);
init(context);
}
public SRecyclerView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public SRecyclerView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
/**
* 設置最大頁數
*
* @param maxPage
*/
public void setMaxPage(int maxPage) {
this.mMaxPage = maxPage;
}
/**
* 是否支持上拉加載
*
* @param hasLoadmore
*/
public void setLoadmore(boolean hasLoadmore) {
mHasFooter = hasLoadmore;
}
public void setRecyclerViewLayoutManage(RecyclerView.LayoutManager mLayoutManage){
this.mLayoutManager=mLayoutManage;
}
/**
* 關閉下拉刷新功能
*/
public void disableRefresh() {
mHasRefresh = false;
}
public void setAdapter(BaseRecyclerViewAdapter adapter) {
int height = 0;
if (mMaxPage == DEFAULT_MIN_PAGEINDEX) {
mHasFooter = false;
}
mAdapter = new AdapterWrapper(context, adapter);
mRecyclerView.setAdapter(mAdapter);
}
private int getViewHeight(View view) {
int measure = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
view.measure(measure, measure);
return view.getMeasuredHeight();
}
/**
* 獲取viewgroup裡面的recyclerview
*
* @return
*/
public RecyclerView getRecyclerView() {
return mRecyclerView;
}
public void setOnRecyclerChangeListener(OnRecyclerStatusChangeListener listener) {
mRecyclerChangeListener = listener;
}
/**
* 設置RecyclerView添加、刪除Item的動畫
*
* @param animator
*/
public void setItemAnimator(RecyclerView.ItemAnimator animator) {
mRecyclerView.setItemAnimator(animator);
}
public void notifyDataSetChanged() {
mStatus = STATUS_NORMAL;//重新set數據代表loadmore結束了,此時恢復成普通狀態
mAdapter.notifyDataSetChanged();
}
public void notifyDataInsert(int positionStart, int itemCount) {
mStatus = STATUS_NORMAL;//重新set數據代表loadmore結束了,此時恢復成普通狀態
mAdapter.notifyItemRangeInserted(positionStart, itemCount);
}
public void notifyDataRemove(int position) {
mStatus = STATUS_NORMAL;//重新set數據代表loadmore結束了,此時恢復成普通狀態
mAdapter.notifyItemRemoved(position);
}
/**
* 初始化操作
*
* @param context
*/
void init(Context context) {
this.context = context;
mScroller = new Scroller(context);
// if (mLayoutManager!=null){
// addChildView(context,mLayoutManager);
// }else{
// addChildView(context, new LinearLayoutManager(context));
// }
addChildView(context);
}
@Override
public void computeScroll() {
if (mScroller.computeScrollOffset()) {
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
postInvalidate();
}
}
/**
* 增加子View
*
* @param context
*/
void addChildView(Context context, RecyclerView.LayoutManager mLayoutManager) {
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
mHeaderView = new ElizabethView(context);
mRecyclerView = new RecyclerView(context);
addView(mHeaderView);
addView(mRecyclerView);
//mLayoutManager = new LinearLayoutManager(context);
// mLayoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
mRecyclerView.setLayoutManager(mLayoutManager);
// 設置Item增加、移除默認動畫
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
mRecyclerView.addOnScrollListener(onScrollListener);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setLayoutParams(params);
}
void addChildView(Context contex) {
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
mHeaderView = new ElizabethView(context);
mRecyclerView = new RecyclerView(context);
addView(mHeaderView);
addView(mRecyclerView);
//mLayoutManager = new LinearLayoutManager(context);
mLayoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
mRecyclerView.setLayoutManager(mLayoutManager);
// 設置Item增加、移除默認動畫
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
mRecyclerView.addOnScrollListener(onScrollListener);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setLayoutParams(params);
}
/**
* 屏蔽Recyclerview的觸摸事件(下拉刷新的時候)
*/
float lastY;
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
final int action = MotionEventCompat.getActionMasked(ev);
switch (action) {
case MotionEvent.ACTION_DOWN:
lastY = ev.getRawY();
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
return false;
case MotionEvent.ACTION_MOVE:
if (mHasRefresh && mIsTop && ev.getRawY() > lastY)
return true;
break;
}
return false;
}
float offsetY = 0;
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
offsetY = Math.abs(event.getRawY() - lastY); //Y差值絕對值
if (offsetY > 0)
scrollToOffset(offsetY);
else {
mIsTop = false;
}
break;
case MotionEvent.ACTION_UP:
if (getScrollY() <= 0) {
doRefresh();
mHeaderView.stopAnim();
mHeaderView.startAnim();
} else complete();
break;
}
return super.onTouchEvent(event);
}
/**
* 滾動這個view到手滑動的位置
*
* @param offsetY Y軸偏移量
*/
void scrollToOffset(float offsetY) {
//假如正在刷新並且現在的scrolly和初始值一樣的時候,代表准備下拉開始刷新,並執行一次only
if (getScrollY() == mFristScollerY && mRecyclerChangeListener != null)
mRecyclerChangeListener.startRefresh();
int value = Math.round(offsetY / 2.0F);
value = mFristScollerY - value;
scrollTo(0, value);
}
/**
* 執行刷新操作,移動到header剛出來的位置
*/
void doRefresh() {
mStatus = STATUS_REFRESH;
int currentY = getScrollY();
mScroller.startScroll(0, currentY, 0, (mFristScollerY - mHeadviewHeight) - currentY);
invalidate();
if (mRecyclerChangeListener != null) mRecyclerChangeListener.onRefresh();
handler.sendEmptyMessageDelayed(MSG_REFRESH_COMPLETE, DELAY_REFRESH_COMPLETE);
}
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == MSG_LOAD_COMPLETE) {
View footview = mAdapter.getFootView();
if (footview != null)
mRecyclerView.smoothScrollBy(0, -footview.getMeasuredHeight());
} else if (msg.what == MSG_REFRESH_COMPLETE)
complete();
}
};
/**
* header返回原處完全隱藏
*/
public void complete() {
mCurrentPage = DEFAULT_MIN_PAGEINDEX;//完成之後當前的page恢復默認值
if (mFootViewTips != null)
mFootViewTips.setText(context.getString(R.string.loading));//更改foot提示為正在加載中
if (mRecyclerChangeListener != null) mRecyclerChangeListener.refreshComplete();
mStatus = STATUS_NORMAL;
int currentY = getScrollY();
mScroller.startScroll(0, currentY, 0, mFristScollerY - currentY);
mHeaderView.stopAnim();
invalidate();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = 0;
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
measureChild(child, widthMeasureSpec, heightMeasureSpec);
height += child.getMeasuredHeight();
}
setMeasuredDimension(width, height);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int left = getPaddingLeft();
int top = getPaddingTop();
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
if (i == 0) {//當是header的時候居中顯示
int headerLeft = getMeasuredWidth() / 2 - child.getMeasuredWidth() / 2;
child.layout(headerLeft, top, headerLeft + child.getMeasuredWidth(), top + child.getMeasuredHeight());
} else
child.layout(left, top, left + child.getMeasuredWidth(), top + child.getMeasuredHeight());
top += child.getMeasuredHeight();
}
mHeadviewHeight = getPaddingTop() + mHeaderView.getMeasuredHeight();
scrollTo(0, mHeadviewHeight);//移動到header下方以顯示recyleview
mFristScollerY = getScrollY();
}
/**
* RecyclerView的滑動監聽事件
*/
RecyclerView.OnScrollListener onScrollListener = new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
//滑動到了頂部
if (mFirstVisibleItem == 0) {
mIsTop = true;
} else {
mIsTop = false;
if (mStatus != STATUS_LOAD && mShowFootVisible && mLastVisibleItem + 1 == mAdapter.getItemCount()) {
if (mCurrentPage == mMaxPage) {
//當前頁面是最後一頁的時候
mFootViewTips = (TextView) mAdapter.getFootView().findViewById(R.id.footer_tips);
mFootViewTips.setText(context.getString(R.string.last_page_tips));
handler.sendEmptyMessageDelayed(MSG_LOAD_COMPLETE, DELAY_LOAD_COMPLETE);
} else {
mStatus = STATUS_LOAD;
if (mRecyclerChangeListener != null) {
mRecyclerChangeListener.onLoadMore();
mCurrentPage++;
}
}
}
}
}
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if (mLayoutManager instanceof LinearLayoutManager) {
mLastVisibleItem = ((LinearLayoutManager) mLayoutManager).findLastVisibleItemPosition();
mFirstVisibleItem = ((LinearLayoutManager) mLayoutManager).findFirstCompletelyVisibleItemPosition();
setFootviewVisible();
} else if (mLayoutManager instanceof GridLayoutManager) {
mLastVisibleItem = ((GridLayoutManager) mLayoutManager).findLastVisibleItemPosition();
mFirstVisibleItem = ((GridLayoutManager) mLayoutManager).findFirstCompletelyVisibleItemPosition();
setFootviewVisible();
} else if (mLayoutManager instanceof StaggeredGridLayoutManager) {
//因為StaggeredGridLayoutManager的特殊性可能導致最後顯示的item存在多個,所以這裡取到的是一個數組
//得到這個數組後再取到數組中position值最大的那個就是最後顯示的position值了
int[] lastPositions = new int[((StaggeredGridLayoutManager) mLayoutManager).getSpanCount()];
((StaggeredGridLayoutManager) mLayoutManager).findLastVisibleItemPositions(lastPositions);
mLastVisibleItem = findMax(lastPositions);
mFirstVisibleItem = ((StaggeredGridLayoutManager) mLayoutManager).findFirstVisibleItemPositions(lastPositions)[0];
setFootviewVisible();
}
}
};
void setFootviewVisible() {
//當設置了擁有上拉加載功能但是第一頁的條目不足以盛滿Recyclerview的時候隱藏footer
if (mHasFooter && mFirstVisibleItem == 0) {
/**
* 這裡加上一個mShowFootVisible在上拉加載功能啟用的情況下生效,從來控制item數量不足鋪滿
* recyclerview高度的時刻隱藏footview,在item數量超過view高度的情況下顯示
*/
if (mLastVisibleItem + 1 == mAdapter.getItemCount()) {
mShowFootVisible = false;
} else mShowFootVisible = true;
notifyDataSetChanged();
}
}
private int findMax(int[] positions) {
int max = positions[0];
for (int value : positions) {
if (value > max) {
max = value;
}
}
return max;
}
private class AdapterWrapper extends RecyclerView.Adapter {
private static final int TYPE_ITEM = 0;
private static final int TYPE_FOOTER = 1;
private RecyclerView.Adapter mAdapter;
private Context mContext;
View footer;
public AdapterWrapper(Context context, RecyclerView.Adapter wrappedAdapter) {
this.mContext = context;
this.mAdapter = wrappedAdapter;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
RecyclerView.ViewHolder holder = null;
switch (viewType) {
case TYPE_ITEM:
holder = mAdapter.onCreateViewHolder(parent, viewType);
break;
case TYPE_FOOTER:
footer = LayoutInflater.from(mContext).inflate(R.layout.lib_recyle_footview, null);
LinearLayout linearLayout= (LinearLayout) footer.findViewById(R.id.loading_layout);
StaggeredGridLayoutManager.LayoutParams layoutParams =
new StaggeredGridLayoutManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
layoutParams.setFullSpan(true);
linearLayout.setLayoutParams(layoutParams);
holder = new FooterViewHolder(footer);
break;
}
return holder;
}
public View getFootView() {
return footer;
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (!mHasFooter || position + 1 != getItemCount()) {
mAdapter.onBindViewHolder(holder, position);
}
}
@Override
public int getItemCount() {
return mShowFootVisible ? mAdapter.getItemCount() + 1 : mAdapter.getItemCount();
}
@Override
public int getItemViewType(int position) {
if (mShowFootVisible && position + 1 == getItemCount()) {
return TYPE_FOOTER;
} else {
return TYPE_ITEM;
}
}
private class FooterViewHolder extends RecyclerView.ViewHolder {
public ProgressBar progressBar;
public TextView tvLoading;
public LinearLayout llyLoading;
public FooterViewHolder(View itemView) {
super(itemView);
progressBar = (ProgressBar) itemView.findViewById(R.id.progress_loading);
tvLoading = (TextView) itemView.findViewById(R.id.footer_tips);
llyLoading = (LinearLayout) itemView.findViewById(R.id.loading_layout);
}
}
}
}

最後還有一個就是Adapter的代碼:

package com.krain.srecyclerview.srecyclerview;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
public abstract class BaseRecyclerViewAdapter<VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<VH> {
private OnItemClickLisener mItemListener;
@Override
public VH onCreateViewHolder(ViewGroup parent, int viewType) {
View view = getItemView(viewType, parent);
VH vh = getViewHolder(view);
view.setOnClickListener(new OnRecyclerAdapterclickListener(vh, viewType));
view.setOnLongClickListener(new OnRecyclerAdapterclickListener(vh, viewType));
return vh;
}
public abstract VH getViewHolder(View itemView);
/**
* 返回item的view
*
* @return
*/
public abstract View getItemView(int viewType, ViewGroup parent);
/**
* 返回Adapter每個itemn的數據 可選
*/
public Object getItem(int position) {
return null;
}
/**
* item點擊事件接口
*
* @param mItemListener
*/
public void setOnItemListener(OnItemClickLisener mItemListener) {
this.mItemListener = mItemListener;
}
@Override
public abstract void onBindViewHolder(VH holder, int position);
@Override
public abstract int getItemCount();
class OnRecyclerAdapterclickListener implements View.OnClickListener, View.OnLongClickListener {
VH viewholder;
int viewType;
public OnRecyclerAdapterclickListener(VH viewholder, int viewType) {
this.viewholder = viewholder;
this.viewType = viewType;
}
@Override
public void onClick(View v) {
if (mItemListener != null && viewholder.getAdapterPosition() != RecyclerView.NO_POSITION) {
mItemListener.onItemClick(viewholder.getAdapterPosition(), viewType, viewholder, v);
}
}
@Override
public boolean onLongClick(View v) {
if (mItemListener != null && viewholder.getAdapterPosition() != RecyclerView.NO_POSITION) {
mItemListener.onItemLongClick(viewholder.getAdapterPosition(), viewType, viewholder, v);
}
return false;
}
}
}

需要注意一哈:

如果想改變Reciview的布局方式在這個修改

void addChildView(Context contex) {
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
mHeaderView = new ElizabethView(context);
mRecyclerView = new RecyclerView(context);
addView(mHeaderView);
addView(mRecyclerView);
//mLayoutManager = new LinearLayoutManager(context);
mLayoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
mRecyclerView.setLayoutManager(mLayoutManager);
// 設置Item增加、移除默認動畫
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
mRecyclerView.addOnScrollListener(onScrollListener);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setLayoutParams(params);
}

mLayoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);這一行就是了改成對應的就可以了,這兒沒有封裝過幾天封裝一個出來。

還需要注意一哈就是在滑動判斷是不是最後一行,如果是瀑布流就要注意哈判斷的方式和其他的不一樣,

if (mLayoutManager instanceof StaggeredGridLayoutManager) {
//因為StaggeredGridLayoutManager的特殊性可能導致最後顯示的item存在多個,所以這裡取到的是一個數組
//得到這個數組後再取到數組中position值最大的那個就是最後顯示的position值了
int[] lastPositions = new int[((StaggeredGridLayoutManager) mLayoutManager).getSpanCount()];
((StaggeredGridLayoutManager) mLayoutManager).findLastVisibleItemPositions(lastPositions);
mLastVisibleItem = findMax(lastPositions);
mFirstVisibleItem = ((StaggeredGridLayoutManager) mLayoutManager).findFirstVisibleItemPositions(lastPositions)[0];
setFootviewVisible();
}

因為StaggeredGridLayoutManager的特殊性可能導致最後顯示的item存在多個,所以這裡取到的是一個數組,得到這個數組後再取到數組中position值最大的那個就是最後顯示的position值了再去設置最後一行加載更多的顯示。

以上所述是小編給大家介紹的Android RecyclerView 上拉加載更多及下拉刷新功能的實現方法,希望對大家有所幫助,如果大家有任何疑問歡迎給我留言,小編會及時回復大家的,在此也非常感謝大家對本站網址的支持!

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved