Program Tip

RecyclerView 그리드에 불확실한 진행률 표시 줄을 바닥 글로 추가

programtip 2021. 1. 10. 19:30
반응형

RecyclerView 그리드에 불확실한 진행률 표시 줄을 바닥 글로 추가


그리드 RecycleView에서 "더로드하려면 위로 스크롤"에 대한 불확실한 원형 표시기를 얻는 방법은 무엇입니까?

패턴은 여기에 설명되어 있습니다. http://www.google.com/design/spec/components/progress-activity.html#progress-activity-behavior in "2 단계로드"및 "예 2 : 위로 스크롤하여 더로드 "예제 동영상.

새로운 RecyclerView를 사용하여이 작업을 수행하려고하는데, "너무 해킹이 아닌"방법을 찾을 수 없습니다. 첫째, 그리드의 전체 행을 덮는 바닥 글을 추가하는 방법이 없기 때문입니다. . 어떤 제안?


그렇게하는 것은 매우 간단합니다.

해결책은 LinearLayoutManagerwith a GridLayoutManager동일한 접근 방식 을 사용하고 다음 같은 방법 을 사용하는 것 setSpanSizeLookup입니다 LayoutManager.

mLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
        @Override
        public int getSpanSize(int position) {
            switch(myAdapter.getItemViewType(position)){
                case MyAdapter.VIEW_TYPES.Product:
                    return 1;
                case MyAdapter.VIEW_TYPES.Progress:
                    return 2; //number of columns of the grid
                default:
                    return -1;
            }
        }
    });

이렇게하면 항목이 그리드의 전체 행을 자동으로 덮게됩니다 (행이 완전히 비어 있지 않은 경우이 항목은 다음 행으로 이동합니다).


아래의 참고 솔루션에는 몇 가지 잠재적 인 문제와 제한 사항이 있습니다. 수정 된 솔루션의 경우 하단의 ProgressBar를 사용하여 Endless Scroll RecyclerView에 항목 추가 를 확인하십시오.

여기 내가 최근에 나온 해결책이 있습니다. 아이디어는 RecyclerView에 2 가지 유형의 항목이있는 것입니다. 하나는 일반적인 항목이고 두 번째는 진행률 표시 줄입니다. 그런 다음 스크롤 이벤트를 수신하고 더 많이로드하고 진행률 표시 줄을 표시할지 여부를 결정해야합니다. . 그래서 아이디어에서 예제 코드까지

progress_item.xml

<?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="match_parent">

    <ProgressBar
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/progressBar"
        android:indeterminate="true"
        style="@android:style/Widget.Holo.ProgressBar"
        android:layout_gravity="center_horizontal"/>
</LinearLayout>

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:tools="http://schemas.android.com/tools"
                xmlns:ring="http://schemas.android.com/apk/res-auto"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                tools:context=".MainActivity">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/my_recycler_view"
        android:scrollbars="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</RelativeLayout>

EndlessRecyclerOnScrollListener.java

public abstract class EndlessRecyclerOnScrollListener extends RecyclerView.OnScrollListener {
    public static String TAG = EndlessRecyclerOnScrollListener.class.getSimpleName();

    private int previousTotal = 0; // The total number of items in the dataset after the last load
    private boolean loading = true; // True if we are still waiting for the last set of data to load.
    private int visibleThreshold = 1; // The minimum amount of items to have below your current scroll position before loading more.
    int firstVisibleItem, visibleItemCount, totalItemCount;

    private int current_page = 1;

    private LinearLayoutManager mLinearLayoutManager;

    public EndlessRecyclerOnScrollListener(LinearLayoutManager linearLayoutManager) {
        this.mLinearLayoutManager = linearLayoutManager;
    }

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

        visibleItemCount = recyclerView.getChildCount();
        totalItemCount = mLinearLayoutManager.getItemCount();
        firstVisibleItem = mLinearLayoutManager.findFirstVisibleItemPosition();

        if (loading) {
            if (totalItemCount > previousTotal+1) {
                loading = false;
                previousTotal = totalItemCount;
            }
        }
        if (!loading && (totalItemCount - visibleItemCount) <= (firstVisibleItem + visibleThreshold)) {
        // End has been reached
        // Do something
            current_page++;
            onLoadMore(current_page);
            loading = true;
        }
    }

    public abstract void onLoadMore(int current_page);
}

MyAdapter.java

public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    private final int VIEW_ITEM = 1;
    private final int VIEW_PROG = 0;

    private List<String> mDataset;

    public static class TextViewHolder extends RecyclerView.ViewHolder {
        public TextView mTextView;
        public TextViewHolder(View v) {
            super(v);
            mTextView = (TextView)v.findViewById(android.R.id.text1);
        }
    }
    public static class ProgressViewHolder extends RecyclerView.ViewHolder {
        public ProgressBar progressBar;
        public ProgressViewHolder(View v) {
            super(v);
            progressBar = (ProgressBar)v.findViewById(R.id.progressBar);
        }
    }

    public MyAdapter(List<String> myDataset) {
        mDataset = myDataset;
    }

    @Override
    public int getItemViewType(int position) {
        return mDataset.get(position)!=null? VIEW_ITEM: VIEW_PROG;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        RecyclerView.ViewHolder vh;
        if(viewType==VIEW_ITEM) {
            View v = LayoutInflater.from(parent.getContext())
                    .inflate(android.R.layout.simple_list_item_1, parent, false);

            vh = new TextViewHolder(v);
        }else {
            View v = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.progress_item, parent, false);

            vh = new ProgressViewHolder(v);
        }
        return vh;
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        if(holder instanceof TextViewHolder){
            ((TextViewHolder)holder).mTextView.setText(mDataset.get(position));
        }else{
            ((ProgressViewHolder)holder).progressBar.setIndeterminate(true);
        }
    }

    @Override
    public int getItemCount() {
        return mDataset.size();
    }
}

마지막으로 MainActivity.java

package virtoos.com.testapps;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;

import java.util.ArrayList;
import java.util.List;


public class MainActivity extends Activity {
    private RecyclerView mRecyclerView;
    private LinearLayoutManager mLayoutManager;
    private MyAdapter mAdapter;
    private final List<String> myDataset = new ArrayList<>();
    private Handler handler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        handler = new Handler();
        addItems(20);
        mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);

        // use this setting to improve performance if you know that changes
        // in content do not change the layout size of the RecyclerView
        mRecyclerView.setHasFixedSize(true);

        mLayoutManager = new LinearLayoutManager(this);
        mRecyclerView.setLayoutManager(mLayoutManager);

        mAdapter = new MyAdapter(myDataset);
        mRecyclerView.setAdapter(mAdapter);

        //mRecyclerView.setItemAnimator(new DefaultItemAnimator());

        mRecyclerView.setOnScrollListener(new EndlessRecyclerOnScrollListener(mLayoutManager) {
            @Override
            public void onLoadMore(int current_page) {
                //add progress item
                myDataset.add(null);
                mAdapter.notifyItemInserted(myDataset.size());
                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        //remove progress item
                        myDataset.remove(myDataset.size() - 1);
                        mAdapter.notifyItemRemoved(myDataset.size());
                        //add items one by one
                        for (int i = 0; i < 15; i++) {
                            myDataset.add("Item"+(myDataset.size()+1));
                            mAdapter.notifyItemInserted(myDataset.size());
                        }
                        //or you can add all at once but do not forget to call mAdapter.notifyDataSetChanged();
                    }
                }, 2000);
                System.out.println("load");
            }
        });

    }
}

Here is a small modification to @Vilen Melkumyan answer on the RecyclerView.Adapter which worked better for me. And you can use your EndlessRecyclerOnScrollListener in any way you want for loading the data, also enabling or disabling the footer at any time.

PS: It worked with GridLayoutManager.

public class MyRecyclerViewAdapter  extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

private final int VIEW_TYPE_ITEM = 1;
private final int VIEW_TYPE_PROGRESSBAR = 0;
private boolean isFooterEnabled = true;

private List<String> items;

public static class TextViewHolder extends RecyclerView.ViewHolder {
    public TextView mTextView;
    public TextViewHolder(View v) {
        super(v);
        mTextView = (TextView)v.findViewById(android.R.id.text1);
    }
}
public static class ProgressViewHolder extends RecyclerView.ViewHolder {
    public ProgressBar progressBar;
    public ProgressViewHolder(View v) {
        super(v);
        progressBar = (ProgressBar)v.findViewById(R.id.progressBar);
    }
}

public MyRecyclerViewAdapter(List<String> myDataset) {
    items = myDataset;
}

@Override
public int getItemCount() {
    return  (isFooterEnabled) ? items.size() + 1 : items.size();
}

@Override
public int getItemViewType(int position) {
    return (isFooterEnabled && position >= items.size() ) ? VIEW_TYPE_PROGRESSBAR : VIEW_TYPE_ITEM;
}

/**
 * Enable or disable footer (Default is true)
 *
 * @param isEnabled boolean to turn on or off footer.
 */
public void enableFooter(boolean isEnabled){
    this.isFooterEnabled = isEnabled;
}

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    RecyclerView.ViewHolder vh;
    if(viewType== VIEW_TYPE_ITEM) {
        View v = LayoutInflater.from(parent.getContext())
                .inflate(android.R.layout.simple_list_item_1, parent, false);
        vh = new TextViewHolder(v);
    }else {
        View v = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.progressbar, parent, false);

        vh = new ProgressViewHolder(v);
    }
    return vh;
}

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    if(holder instanceof ProgressViewHolder){
        ((ProgressViewHolder)holder).progressBar.setIndeterminate(true);
    } else if(items.size() > 0 && position < items.size()) {
        ((TextViewHolder)holder).mTextView.setText(items.get(position));            
    }
}
}

My 2 cents, peace!!


Check out my solution in https://github.com/ramirodo/endless-recycler-view-adapter or https://bintray.com/ramiro/android/endless-recycler-view-adapter. There is an example there and also the steps to set up the library in your project.

You just need to extend your recycler view adapter by implementing the required methods. Also you can set up the layout of the progress footer.


You can simplify Bronx's answer with inserting the code inside an adapter.

public class ArticleGridAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    private final int VIEW_ITEM = 0;
    private final int VIEW_LOADING = 1;

    private Context mContext;
    private List<Article> mArticles = new ArrayList<>();
    private RecyclerView mRecyclerView;
    private GridLayoutManager mManager;

    public ArticleGridAdapter(Context context, List<Article> articles, RecyclerView recyclerView) {
        this.mContext = context;
        this.mArticles = articles;
        this.mRecyclerView = recyclerView;
        this.mManager = (GridLayoutManager) recyclerView.getLayoutManager();

        mManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
            @Override
            public int getSpanSize(int position) {
                return getItemViewType(position) == VIEW_LOADING ? mManager.getSpanCount() : 1;
            }
        });
    }
}

ReferenceURL : https://stackoverflow.com/questions/27044449/put-an-indeterminate-progressbar-as-footer-in-a-recyclerview-grid

반응형