AndroidはRecyclerViewのドロップダウン・リフレッシュとアップロードを実現


需要
先に効果図をアップロードし、Material Designスタイルのドロップダウンリフレッシュとアップロードを追加します.
ソースアドレス(starへようこそ)https://github.com/studychen/SeeNewsV2
RecyclerViewについてまだ詳しくない場合は、ListViewの代わりにこのAndroid Material Designが学んだRecyclerViewを参照してください.
本リンクhttp://blog.csdn.net/never_cxb/article/details/50759109転載は出典を明記してください
ドロップダウン・リフレッシュ
効果図
プルアップ時に円形アニメーションがあり、ロードデータをリフレッシュします.
Android实现RecyclerView的下拉刷新和上拉加载更多_第1张图片
構想
Google公式のandroid.support.v4.widget.SwipeRefreshLayoutを使用
リストRecyclerViewのxmlレイアウト
元のRecyclerViewにSwipeRefreshLayoutの親レイアウトを追加

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="?attr/listBackground"
    android:orientation="vertical">
    <android.support.v4.widget.SwipeRefreshLayout
        android:id="@+id/swiperefreshlayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        
        <android.support.v7.widget.RecyclerView
            android:id="@+id/rcv_article_origin"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    android.support.v4.widget.SwipeRefreshLayout>
LinearLayout>

JAvaコード
ここにはいくつかの注意点があります.setColorSchemeColors()は円形アニメーションの色を制御し、最大4つ設定できます.setOnRefreshListenerドロップダウン・リフレッシュのコールバック・イベントを設定します.
ドロップダウン・リフレッシュ後、AsyncTaskを使用して、現在のRecyclerViewの最初のItemのidに基づいてより多くのデータをロードします.
データのロードが完了したら、setRefreshing(false);を使用してアニメーションをキャンセルします.
リフレッシュ後に0個のレコードが得られた場合、 を提示する.>0個のデータが得られたら、RecyclerViewにデータを加算
mSwipeRefreshLayout.setColorSchemeColors(Color.RED, Color.BLUE);
mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
    @Override
    public void onRefresh() {
        new MoreArticleTask().execute(mAdapter.getTopArticleId());
    }
});

// Integer      
//      id      
class MoreArticleTask extends AsyncTask<Integer, Void, List<SimpleArticleItem>> {
    @Override
    protected List doInBackground(Integer... params) {
        try {
            Thread.sleep(1500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return getMoreById(mColumn, params[0]);
    }

    @Override
    protected void onPostExecute(List simpleArticleItems) {
        super.onPostExecute(simpleArticleItems);

        if (mSwipeRefreshLayout != null) {
            mSwipeRefreshLayout.setRefreshing(false);
        }
        //      ,    
        if (simpleArticleItems == null || simpleArticleItems.size() == 0) {
            Snackbar.with(mActivity.getApplicationContext()) // context
                    .text(mActivity.getResources().getString(R.string.list_more_data)) // text to display
                    .duration(Snackbar.SnackbarDuration.LENGTH_SHORT) // make it shorter
                    .show(mActivity); // activity where it is displayed
        } else {
            mArticleList.addAll(simpleArticleItems);
            mAdapter.notifyDataSetChanged();
        }
    }

}


初めてページに入るとingをロードしたアニメーションが表示されます
効果は次のとおりです.
Android实现RecyclerView的下拉刷新和上拉加载更多_第2张图片 mSwipeRefreshLayout.setRefreshing(true);を直接使用してアニメーションの初期状態をロードしても表示されません.
見ましたhttp://stackoverflow.com/questions/26858692/swiperefreshlayout-setrefreshing-not-showing-indicator-initiallyの解答は、次のコードに変更して、初期状態でアニメーション表示をロードします.
mSwipeRefreshLayout.post(new Runnable() {
    @Override
    public void run() {
        mSwipeRefreshLayout.setRefreshing(true);
        new MoreArticleTask().execute(mAdapter.getTopArticleId());
    }
});

アップロード
RecyclerViewディスプレイリストは一般的なニーズですが、データが多い場合、どのようにページングロードを実現しますか?
例えば筆者の項目では,まず15のニュースをロードし,最後までスライドしたときに15のニュースをロードする.
効果図
Android实现RecyclerView的下拉刷新和上拉加载更多_第3张图片
構想
RecyclerViewの下部にFooterのViewHolderを追加し、データのロードが完了して下部のViewHolderを取り出します.
下部Footerのxmlレイアウトファイル
簡単です.ProgressBarです.本プロジェクトでは、Material DesignのためにオープンソースProgressBarを使用しています.https://github.com/Todd-Davies/ProgressWheelあ、オリジナルのProgressBarも使えます.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:wheel="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <com.pnikosis.materialishprogress.ProgressWheel
        android:id="@+id/rcv_load_more"
        android:layout_width="40dp"
        android:layout_height="40dp"
        android:layout_gravity="center_horizontal"
        wheel:matProg_barColor="@color/accent"
        wheel:matProg_progressIndeterminate="true" />
LinearLayout>

下部FooterのViewHolder
/**
 *       
 */
class FooterViewHolder extends RecyclerView.ViewHolder {
    @InjectView(R.id.rcv_load_more)
    ProgressWheel rcvLoadMore;

    public FooterViewHolder(View itemView) {
        super(itemView);
        ButterKnife.inject(this, itemView);
    }
}

FragmentでRecyclerViewにスライドリスニングを追加layoutManager.getItemCount()現在のRecyclerViewにおけるItemの総数を得ることができるlayoutManager.findLastVisibleItemPosition()最後に見えるItemの位置positionを得る
totalItemCount<(lastVisibleItem+Constant.VISIBLE_THRESHOLD)
例えば15個のItemが現在13個目に達していますVISIBLE_THRESHOLDは3総数が最後の+しきい値より小さいように設定し、より多くのニュースデータをロードし、同時にloadingをtrueとマークする.
private boolean loading = false;

@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);

    mRecyclerView.setLayoutManager(new LinearLayoutManager(mActivity));

    mAdapter = new OriginArticleAdapter(mActivity, mArticleList);

    mRecyclerView.setAdapter(mAdapter);

    mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {

        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {

            super.onScrolled(recyclerView, dx, dy);

            LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();

            int totalItemCount = layoutManager.getItemCount();

            int lastVisibleItem = layoutManager.findLastVisibleItemPosition();

            if (!loading && totalItemCount < (lastVisibleItem + Constant.VISIBLE_THRESHOLD)) {
                new ArticleTask(mActivity).execute(mAdapter.getBottomArticleId());
                loading = true;
            }
        }
    });
}

Fragmentで下部Footerを制御する
私たちは依然としてAsyncTaskを使用しています.
注意onPreExecute()はmArticleListにnullタグFooterを追加し、最初にページにアクセスした場合(mArticleListが空の場合)Footerを追加する必要はありません.
データのロードが完了したら、一番下のFooterをmArticleList.remove(mArticleList.size() - 1);で削除します.
さらにmArticleList.addAll(moreArticles);で新しいニュースデータを追加し、mAdapter.notifyDataSetChanged();でRecyclerViewに通知する.Adapterにはデータの変更があります.
private List mArticleList = new ArrayList();

class ArticleTask extends AsyncTask<Integer, Void, List<SimpleArticleItem>> {

    private Context mContext;

    public ArticleTask(Context context) {
        mContext = context;
    }

    /**
     * Runs on the UI thread before {@link #doInBackground}.
     */
    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        if (mArticleList != null && mArticleList.size() > 0) {
            mArticleList.add(null);

            // notifyItemInserted(int position),       position  
            //                      ,
            //                 ,           ,       。
            mAdapter.notifyItemInserted(mArticleList.size() - 1);
        }
    }

    /**
     * @param params     aid
     * @return
     */
    @Override
    protected List doInBackground(Integer... params) {
        try {
            Thread.sleep(1500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return getArticleList(mColumn, params[0]);
    }

    @Override
    protected void onPostExecute(final List moreArticles) {
        //       
        super.onPostExecute(moreArticles);
        if (mArticleList.size() == 0) {
            mArticleList.addAll(moreArticles);
            mAdapter.notifyDataSetChanged();
        } else {
            //   footer
            mArticleList.remove(mArticleList.size() - 1);
            mArticleList.addAll(moreArticles);
            mAdapter.notifyDataSetChanged();
            loading = false;
        }
    }
}

Override RecyclerView.AdapterのgetItemViewタイプextends RecyclerView.Adapter nullの場合、FooterのTypeに戻ります.そうでなければ、通常のニュースのTypeに戻ります.
本稿では,UIの美しさのために,ニュースを3枚以上,3枚未満の2種類に分け,それに応じて異なるTypeとViewHolderを返す.
public final static int TYPE_MULTI_IMAGES = 2; //        
public final static int TYPE_FOOTER = 3;//  --   loading_more
public final static int TYPE_NORMAL = 1; //        
@Override
public int getItemViewType(int position) {

    SimpleArticleItem article = articleList.get(position);
    if (article == null) {
        return TYPE_FOOTER;
    } else if (article.getImageUrls().length >= 3) {
        return TYPE_MULTI_IMAGES;
    } else {
        return TYPE_NORMAL;
    }

}

Override RecyclerView.AdapterのonCreateViewHolder
この方法では、switch (viewType)を使用して異なるxmlレイアウトファイルおよびViewHolderを返す
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

    RecyclerView.ViewHolder vh;
    View view;
    switch (viewType) {
        //           viewholder_article_simple
        default:
        case TYPE_NORMAL:
            view = mLayoutInflater.inflate(
                    R.layout.item_article_normal, parent, false);
            vh = new ItemArticleViewHolder(view);
            return vh;
        case TYPE_FOOTER:
            view = mLayoutInflater.inflate(
                    R.layout.recyclerview_footer, parent, false);
            vh = new FooterViewHolder(view);
            return vh;
        case TYPE_MULTI_IMAGES:
            view = mLayoutInflater.inflate(
                    R.layout.item_article_multi_images, parent, false);
            vh = new MultiImagesViewHolder(view);
            return vh;
    }
}

Override RecyclerView.AdapterのonBindViewHolder
どのタイプのViewHolderであるかをinstanceofで判断し、コントロールにデータを割り当て、バインドします.
注意:Footerはnullで表示されているので、NullPointerExceptionを防ぐために、まずifでFooterView Holderの状況を処理しました.
@Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {

    //    article  null,   footer    
    if (holder instanceof FooterViewHolder) {
        ((FooterViewHolder) holder).rcvLoadMore.spin();
        return;
    }

    SimpleArticleItem article = articleList.get(position);
    String[] imageUrls = article.getImageUrls();

    if (holder instanceof ItemArticleViewHolder) {
        ItemArticleViewHolder newHolder = (ItemArticleViewHolder) holder;
        newHolder.rcvArticleTitle.setText(article.getTitle());
        newHolder.rcvArticleDate.setText(article.getPublishDate());
        //     3       1   
        if (imageUrls.length > 0) {
            newHolder.rcvArticlePhoto.setImageURI(Uri.parse(Constant.BUCKET_HOST_NAME
                    + imageUrls[0]));
        } else {
            newHolder.rcvArticlePhoto.setImageURI(Uri.parse(ApiUrl.randomImageUrl(article.getId())));
        }
        //          int   ,      String   
        newHolder.rcvArticleReadtimes.setText("  : " + article.getReadTimes());

        newHolder.rcvArticleSummary.setText(article.getSummary());
    } else {
        MultiImagesViewHolder newHolder = (MultiImagesViewHolder) holder;
        newHolder.articleTitle.setText(article.getTitle());
        newHolder.articlePic1.setImageURI(Uri.parse(Constant.BUCKET_HOST_NAME + imageUrls[0]));
        newHolder.articlePic2.setImageURI(Uri.parse(Constant.BUCKET_HOST_NAME + imageUrls[1]));
        newHolder.articlePic3.setImageURI(Uri.parse(Constant.BUCKET_HOST_NAME + imageUrls[2]));
        newHolder.countPics.setText("  : " + imageUrls.length);
        newHolder.countRead.setText("  : " + article.getReadTimes());
    }
}

ドロップダウン・リフレッシュとアップロードのソース・アドレス(starを歓迎)https://github.com/studychen/SeeNewsV2
本リンクhttp://blog.csdn.net/never_cxb/article/details/50759109転載は出典を明記してください
いくつかの穴
RecyclerView setLayoutManagerに注意してください.そうしないと、RecyclerViewは表示されない可能性があります.
// 1. get a reference to recyclerView
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.list);

// 2. set layoutManger
recyclerView.setLayoutManager(new LinearLayoutManager(this));

参考記事
  • LoadMore RecyclerView with progress bar showing at bottom
  • Android Material Design学習のRecyclerView代替ListView
  • Swipe/Pull to Refresh for Android RecyclerView (or any other vertically scrolling view)