페이지 매김을위한 ProgressBar가있는 Endless RecyclerView
나는 RecyclerView
API에서 객체를 10 개 단위로 사용하고있다. 페이지 매김에는 EndlessRecyclerOnScrollListener
.
모두 제대로 작동하고 있습니다. 이제 남은 것은 목록 맨 아래에 진행률 스피너를 추가하는 것입니다. 그러면 다음 개체 배치가 API에서 가져옵니다. 여기에 구글 플레이 스토어 앱의 스크린 샷은을 보여주는 것입니다 ProgressBar
확실히 무엇에 RecyclerView
:
문제는 다음 배치의 객체를 가져 오는 동안 맨 아래에 를 표시하기위한 지원 기능이 내장 되어 RecyclerView
있지 않다는 것 입니다.EndlessRecyclerOnScrollListener
ProgressBar
나는 이미 다음과 같은 답변을 보았습니다.
1. 미확정 ProgressBar
을 RecyclerView
그리드에 바닥 글로 넣습니다 .
2. 무한 스크롤에 항목을 추가 RecyclerView
로 ProgressBar
하단에 .
나는 그 대답에 만족하지 않습니다 (둘 다 같은 사람에 의해). 여기에는 null
사용자가 스크롤하는 동안 데이터 세트에 객체를 넣은 다음 다음 배치가 전달 된 후 꺼내는 작업이 포함됩니다. 제대로 작동하거나 작동하지 않을 수있는 주요 문제를 회피하는 해킹처럼 보입니다. 그리고 그것은 목록에 약간의 흔들림과 왜곡을 유발합니다.
사용 SwipeRefreshLayout
은 여기서 해결책이 아닙니다. 최신 항목 SwipeRefreshLayout
을 가져 오기 위해 맨 위에서 당기는 작업이 포함되며 어쨌든 진행률보기를 표시하지 않습니다.
누군가가 이것에 대한 좋은 해결책을 제공 할 수 있습니까? Google이 자체 앱에이를 구현 한 방법을 알고 싶습니다 (Gmail 앱에도 적용됨). 자세한 내용이 표시된 기사가 있습니까? 모든 답변과 의견을 주시면 감사하겠습니다. 감사합니다.
다른 참조 :
1. 와 매김RecyclerView
. (훌륭한 개요 ...)
2. RecyclerView
머리글 및 바닥 글 . (더 많이 ...)
3. 바닥에 끝 RecyclerView
이 ProgressBar
없습니다 .
여기에 더 간단하고 깔끔한 접근 방식이 있습니다.
이 코드 경로 가이드 에서 무한 스크롤링을 구현 한 후 다음 단계를 따르십시오.
1. RecyclerView 아래에 진행률 표시 줄을 추가합니다.
<android.support.v7.widget.RecyclerView
android:id="@+id/rv_movie_grid"
android:layout_width="0dp"
android:layout_height="0dp"
android:paddingBottom="50dp"
android:clipToPadding="false"
android:background="@android:color/black"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
</android.support.v7.widget.RecyclerView>
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="invisible"
android:background="@android:color/transparent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
여기서 android : paddingBottom = "50dp" 및 android : clipToPadding = "false" 는 매우 중요합니다.
2. 진행률 표시 줄에 대한 참조를 가져옵니다.
progressBar = findViewById(R.id.progressBar);
3. 진행률 표시 줄을 표시하고 숨기는 방법을 정의합니다.
void showProgressView() {
progressBar.setVisibility(View.VISIBLE);
}
void hideProgressView() {
progressBar.setVisibility(View.INVISIBLE);
}
이전 프로젝트에서 이것을 구현했으며 다음과 같이 수행했습니다.
나는 interface
당신의 예의 사람들이 한 것처럼 만들었습니다.
public interface LoadMoreItems {
void LoadItems();
}
그런 다음 addOnScrollListener()
내Adapter
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView,
int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
totalItemCount = linearLayoutManager.getItemCount();
lastVisibleItem = linearLayoutManager
.findLastVisibleItemPosition();
if (!loading
&& totalItemCount <= (lastVisibleItem + visibleThreshold)) {
//End of the items
if (onLoadMoreListener != null) {
onLoadMoreListener.LoadItems();
}
loading = true;
}
}
});
는 onCreateViewHolder()
내가 어디다입니다 ProgressBar
여부.
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
RecyclerView.ViewHolder vh;
if (viewType == VIEW_ITEM) {
View v = LayoutInflater.from(parent.getContext()).inflate(
R.layout.list_row, parent, false);
vh = new StudentViewHolder(v);
} else {
View v = LayoutInflater.from(parent.getContext()).inflate(
R.layout.progressbar_item, parent, false);
vh = new ProgressViewHolder(v);
}
return vh;
}
내 에서 다른 항목을 추가하기 위해 MainActivity
넣은 곳 LoadItems()
은 다음과 같습니다.
mAdapter.setOnLoadMoreListener(new LoadMoreItems() {
@Override
public void LoadItems() {
DataItemsList.add(null);
mAdapter.notifyItemInserted(DataItemsList.size() - 1);
handler.postDelayed(new Runnable() {
@Override
public void run() {
// remove progress item
DataItemsList.remove(DataItemsList.size() - 1);
mAdapter.notifyItemRemoved(DataItemsList.size());
//add items one by one
//When you've added the items call the setLoaded()
mAdapter.setLoaded();
//if you put all of the items at once call
// mAdapter.notifyDataSetChanged();
}
}, 2000); //time 2 seconds
}
});
자세한 내용은 그냥이 다음 Github repository
( 참고 :이 사용하고 AsyncTask
내가 그것을했다 수동으로하지의 데이터로부터, 내 답변으로 유용 어쩌면 API
하지만 잘으로 작동합니다 ) 또한이 게시물이 나에게 도움이되었다 무한 recyclerview-와 진행을 -바
또한 이름을 지 었는지 모르겠지만이 게시물 infinite_scrolling_recyclerview를 찾았습니다 . 어쩌면 도움이 될 수도 있습니다.
찾고있는 것이 아닌 경우이 코드의 문제점을 알려 주시면 원하는대로 수정하겠습니다.
도움이 되었기를 바랍니다.
편집하다
당신이 항목을 제거하고 싶지 않기 때문에 ... 나는 footer
이 게시물 에서 유일한 사람을 제거하는 한 사람을 발견 했습니다 : diseño-android-endless-recyclerview .
이것은입니다 ListView
하지만 난에 당신이 그것을 적용 할 수 있습니다 알고 RecyclerView
그가 단지 태우고 모든 항목 삭제 아니에요 Visible/Invisible
(가) ProgressBar
를 살펴를 :detecting-end-of-listview
또한보십시오 :이 질문 android-implementing-progressbar-and-loading-for-endless-list-like-android
이를 수행하는 다른 방법이 있습니다.
- 먼저 어댑터의 getItemCount가 반환합니다.
listItems.size() + 1
VIEW_TYPE_LOADING
에getItemViewType()
대한 반환position >= listItems.size()
. 이렇게하면 로더가 리사이클 러보기 목록의 끝에 만 표시됩니다. 이 솔루션의 유일한 문제는 마지막 페이지에 도달 한 후에도 로더가 표시되므로x-pagination-total-count
어댑터에 를 저장 하고그런 다음 뷰 유형을 반환하도록 조건을 변경합니다.
(position >= listItem.size())&&(listItem.size <= xPaginationTotalCount)
.
방금이 아이디어를 내놓았습니다. 어떻게 생각하십니까?
진행률보기 홀더를 어댑터에 추가하는 아이디어가 마음에 들지만 원하는 것을 얻기 위해 추악한 논리 조작으로 이어지는 경향이 있습니다. 당신의 반환 값으로 초조해로 추가 바닥 글 항목을 방지하기 위해 뷰 홀더 접근 힘은 getItemCount()
, getItemViewType()
, getItemId(position)
및 모든 종류의 getItem(position)
당신이 할 수 있다는 방법은 다음을 포함합니다.
다른 방법은 관리하는 ProgressBar
상기 시야 Fragment
또는 Activity
표시 또는 숨기기 의해 레벨 ProgressBar
아래 RecyclerView
로드 할 때 시작 및 종료를 각각. 이는 ProgressBar
뷰 레이아웃에 직접 포함 하거나 사용자 정의 RecyclerView
ViewGroup
클래스 에 추가하여 수행 할 수 있습니다. 이 솔루션은 일반적으로 유지 관리 및 버그 감소로 이어집니다.
업데이트 : 콘텐츠가로드되는 동안보기를 위로 스크롤 할 때 내 제안에 문제가 발생합니다. 는 ProgressBar
뷰 레이아웃의 하단에 충실 할 것이다. 이것은 아마도 당신이 원하는 행동이 아닐 것입니다. 이러한 이유로 어댑터에 진행률보기 홀더를 추가하는 것이 아마도 최상의 기능적 솔루션 일 것입니다. 항목 접근 자 메서드를 보호하는 것을 잊지 마십시오. :)
다음은 가짜 항목을 추가하지 않고 해결 방법입니다 (Kotlin에서는 간단하지만).
어댑터에 다음을 추가하십시오.
private var isLoading = false
private val VIEWTYPE_FORECAST = 1
private val VIEWTYPE_PROGRESS = 2
override fun getItemCount(): Int {
if (isLoading)
return items.size + 1
else
return items.size
}
override fun getItemViewType(position: Int): Int {
if (position == items.size - 1 && isLoading)
return VIEWTYPE_PROGRESS
else
return VIEWTYPE_FORECAST
}
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): RecyclerView.ViewHolder {
if (viewType == VIEWTYPE_FORECAST)
return ForecastHolder(LayoutInflater.from(context).inflate(R.layout.item_forecast, parent, false))
else
return ProgressHolder(LayoutInflater.from(context).inflate(R.layout.item_progress, parent, false))
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder?, position: Int) {
if (holder is ForecastHolder) {
//init your item
}
}
public fun showProgress() {
isLoading = true
}
public fun hideProgress() {
isLoading = false
}
이제 showProgress()
API 호출 전에 쉽게 호출 할 수 있습니다 . 그리고 hideProgress()
API 호출이 완료된 후.
이 솔루션은이 페이지의 Akshar Patels 솔루션에서 영감을 받았습니다. 나는 그것을 약간 수정했다.
첫 번째 항목을로드 할 때 ProgressBar를 중앙에 배치하는 것이 좋습니다.
더 이상로드 할 항목이 없을 때 하단에 남아있는 빈 패딩이 마음에 들지 않았습니다. 이 솔루션에서는 제거되었습니다.
먼저 XML :
<android.support.v7.widget.RecyclerView android:id="@+id/video_list" android:paddingBottom="60dp" android:clipToPadding="false" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"> </android.support.v7.widget.RecyclerView> <ProgressBar android:id="@+id/progressBar2" style="?android:attr/progressBarStyle" android:layout_marginTop="10dp" android:layout_width="wrap_content" android:layout_centerHorizontal="true" android:layout_height="wrap_content" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"/>
그런 다음 프로그래밍 방식으로 다음을 추가했습니다.
첫 번째 결과가로드되면이를 onScrollListener에 추가하십시오. ProgressBar를 중앙에서 아래쪽으로 이동합니다.
ConstraintLayout.LayoutParams layoutParams = (ConstraintLayout.LayoutParams) loadingVideos.getLayoutParams();
layoutParams.topToTop = ConstraintLayout.LayoutParams.UNSET;
loadingVideos.setLayoutParams(layoutParams);
더 이상 항목이 없으면 다음과 같이 하단의 패딩을 제거합니다.
recyclerView.setPadding(0,0,0,0);
평소처럼 ProgressBar를 숨기고 표시합니다.
recycleView에서 다음과 같이 layout_above 태그를 사용할 수 있습니다.
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:orientation="vertical">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv"
android:layout_below="@+id/tv2"
android:layout_width="match_parent"
android:focusable="false"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:layout_above="@+id/pb_pagination"/>
<ProgressBar
android:id="@+id/pb_pagination"
style="@style/Widget.AppCompat.ProgressBar"
android:layout_width="30dp"
android:layout_height="30dp"
android:indeterminate="true"
android:visibility="gone"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true" />
</RelativeLayout>
다른 접근 방식은 onBindViewHolder 내에서 API 호출을 시작하고 일부 진행률 표시기를 항목보기에 초기에 배치하는 것입니다. 통화가 완료된 후보기를 업데이트합니다 (진행률 숨기기 및 수신 된 데이터 표시). 예를 들어 이미지 로딩을위한 Picasso의 경우 onBindViewHolder 메서드는 다음과 같습니다.
@Override
public void onBindViewHolder(final MovieViewHolder holder, final int position) {
final Movie movie = items.get(position);
holder.imageProgress.setVisibility(View.VISIBLE);
Picasso.with(context)
.load(NetworkingUtils.getMovieImageUrl(movie.getPosterPath()))
.into(holder.movieThumbImage, new Callback() {
@Override
public void onSuccess() {
holder.imageProgress.setVisibility(View.GONE);
}
@Override
public void onError() {
}
});
}
내가보기에 나타날 수있는 두 가지 경우가 있습니다.
- 한 번의 호출로 모든 항목을 라이트 버전으로 다운로드하는 경우 (예 : 어댑터는 40 장의 사진을 처리해야한다는 것을 즉시 알고 있지만 요청시 다운로드 —> 이전에 피카소에서 보여준 사례)
- 실제 지연 로딩으로 작업하고 서버에 추가 데이터 청크를 요청하는 곳입니다. 이 경우 첫 번째 전제 조건은 필요한 정보와 함께 서버로부터 적절한 응답을받는 것입니다. 예 : { "offset": 0, "total": 100, "items": [{items}]}
응답은 총 100 개의 데이터 중 첫 번째 청크를 수신했음을 의미합니다. 내 접근 방식은 다음과 같습니다.
보기 첫 번째 데이터 청크 (예 : 10)를 가져온 후 어댑터에 추가합니다.
RecyclerView.Adapter.getItemCount 현재 사용 가능한 항목의 양이 총 수량 (예 : 사용 가능한 10, 총 100)보다 적 으면 getItemCount 메서드에서 items.size () + 1을 반환합니다.
RecyclerView.Adapter.getItemViewType 데이터의 총량이 어댑터에서 사용 가능한 항목의 양보다 많고 position = items.size () (즉, getItemCount 메서드에 항목을 가상으로 추가 한 경우), 뷰 유형으로 일부 진행 표시기를 반환합니다. . 그렇지 않으면 일반 레이아웃 유형을 반환합니다.
RecyclerView.Adapter.onCreateViewHolder 진행률 표시기보기 유형을 사용하라는 메시지가 표시되면 발표자에게 추가 항목 청크를 가져오고 어댑터를 업데이트하도록 요청하기 만하면됩니다.
따라서 기본적으로 이것은 목록에서 항목을 추가 / 제거 할 필요가없고 지연로드가 트리거되는 상황을 제어 할 수있는 접근 방식입니다.
다음은 코드 예입니다.
public class ForecastListAdapter extends RecyclerView.Adapter<ForecastListAdapter.ForecastVH> {
private final Context context;
private List<Forecast> items;
private ILazyLoading lazyLoadingListener;
public static final int VIEW_TYPE_FIRST = 0;
public static final int VIEW_TYPE_REST = 1;
public static final int VIEW_TYPE_PROGRESS = 2;
public static final int totalItemsCount = 14;
public ForecastListAdapter(List<Forecast> items, Context context, ILazyLoading lazyLoadingListener) {
this.items = items;
this.context = context;
this.lazyLoadingListener = lazyLoadingListener;
}
public void addItems(List<Forecast> additionalItems){
this.items.addAll(additionalItems);
notifyDataSetChanged();
}
@Override
public int getItemViewType(int position) {
if(totalItemsCount > items.size() && position == items.size()){
return VIEW_TYPE_PROGRESS;
}
switch (position){
case VIEW_TYPE_FIRST:
return VIEW_TYPE_FIRST;
default:
return VIEW_TYPE_REST;
}
}
@Override
public ForecastVH onCreateViewHolder(ViewGroup parent, int viewType) {
View v;
switch (viewType){
case VIEW_TYPE_PROGRESS:
v = LayoutInflater.from(parent.getContext()).inflate(R.layout.forecast_list_item_progress, parent, false);
if (lazyLoadingListener != null) {
lazyLoadingListener.getAdditionalItems();
}
break;
case VIEW_TYPE_FIRST:
v = LayoutInflater.from(parent.getContext()).inflate(R.layout.forecast_list_item_first, parent, false);
break;
default:
v = LayoutInflater.from(parent.getContext()).inflate(R.layout.forecast_list_item_rest, parent, false);
break;
}
return new ForecastVH(v);
}
@Override
public void onBindViewHolder(ForecastVH holder, int position) {
if(position < items.size()){
Forecast item = items.get(position);
holder.date.setText(FormattingUtils.formatTimeStamp(item.getDt()));
holder.minTemperature.setText(FormattingUtils.getRoundedTemperature(item.getTemp().getMin()));
holder.maxTemperature.setText(FormattingUtils.getRoundedTemperature(item.getTemp().getMax()));
}
}
@Override
public long getItemId(int position) {
long i = super.getItemId(position);
return i;
}
@Override
public int getItemCount() {
if (items == null) {
return 0;
}
if(items.size() < totalItemsCount){
return items.size() + 1;
}else{
return items.size();
}
}
public class ForecastVH extends RecyclerView.ViewHolder{
@BindView(R.id.forecast_date)TextView date;
@BindView(R.id.min_temperature)TextView minTemperature;
@BindView(R.id.max_temperature) TextView maxTemperature;
public ForecastVH(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
public interface ILazyLoading{
public void getAdditionalItems();
}}
아마도 이것은 당신이 당신의 필요에 맞는 것을 만들도록 영감을 줄 것입니다.
참조 URL : https://stackoverflow.com/questions/34431734/endless-recyclerview-with-progressbar-for-pagination
'Development Tip' 카테고리의 다른 글
PhoneGap 대 티타늄 (0) | 2020.12.31 |
---|---|
IntelliJ Idea 12 + Android + Scala 요즘 (0) | 2020.12.31 |
auto x {3}가 initializer_list를 추론하는 이유는 무엇입니까? (0) | 2020.12.31 |
AVPlayer 사용시 우수한 스크롤 성능 유지 (0) | 2020.12.31 |
AMP HTML은 무엇이며 프레임 워크 / 도구 X와 어떻게 어울리나요? (0) | 2020.12.31 |