무한스크롤, 즉 유튜브나 페이스북, 트위터 등에서 스크롤이 끊임없이 이어지는 것을 말한다.
브라우저 같은 경우 자바스크립트로 구현할 수 있겠고 안드로이드도 그런 식으로 만드는 것이 가능하겠으나 많이 사용되고 있으므로 여러가지 툴이 존재
// RecyclerViewAdapter.java
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final int VIEW_TYPE_ITEM = 0;
private final int VIEW_TYPE_LOADING = 1;
private List<String> items;
public RecyclerViewAdapter(List<String> items) {
this.items = items;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if (viewType == VIEW_TYPE_ITEM) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_row, parent, false);
return new ItemViewHolder(view);
} else {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_loading, parent, false);
return new LoadingViewHolder(view);
}
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
if (holder instanceof ItemViewHolder) {
populateItemRows((ItemViewHolder) holder, position);
} else if (holder instanceof LoadingViewHolder) {
showLoadingView((LoadingViewHolder) holder, position);
}
}
@Override
public int getItemViewType(int position) {
return items.get(position) == null ? VIEW_TYPE_LOADING : VIEW_TYPE_ITEM;
}
@Override
public int getItemCount() {
return items == null ? 0 : items.size();
}
private void showLoadingView(LoadingViewHolder holder, int position) {
}
private void populateItemRows(ItemViewHolder holder, int position) {
String item = items.get(position);
holder.setItem(item);
}
private class ItemViewHolder extends RecyclerView.ViewHolder {
private TextView textView;
public ItemViewHolder(@NonNull View itemView) {
super(itemView);
textView = itemView.findViewById(R.id.textView);
}
public void setItem(String item) {
textView.setText(item);
}
}
private class LoadingViewHolder extends RecyclerView.ViewHolder {
private ProgressBar progressBar;
public LoadingViewHolder(@NonNull View itemView) {
super(itemView);
progressBar = itemView.findViewById(R.id.progressBar);
}
}
}
// MainActivity.java
public class MainActivity extends AppCompatActivity {
//..
private void initScrollListener() {
recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
if (!isLoading) {
if (layoutManager != null && layoutManager.findLastCompletelyVisibleItemPosition() == items.size() - 1) {
//리스트 마지막
loadMore();
isLoading = true;
}
}
}
});
}
private void loadMore() {
items.add(null);
adapter.notifyItemInserted(items.size() - 1);
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
items.remove(items.size() - 1);
int scrollPosition = items.size();
adapter.notifyItemRemoved(scrollPosition);
int currentSize = scrollPosition;
int nextLimit = currentSize + 10;
while (currentSize - 1 < nextLimit) {
items.add("Item " + currentSize);
currentSize++;
}
adapter.notifyDataSetChanged();
isLoading = false;
}
}, 2000);
}
}
RecyclerViewAdapter에서 우리는 두 개의 ViewHolder를 사용한다.
RecyclerView의 ScrollListener에서 리스트의 마지막을 감지하고 NULL요소를 추가한다.
Adapter에 알리게 되면 LoadingViewHolder를 통해 로딩 아이템을 볼 수 있다.
그 후, 추가되는 데이터 요소 집합을 가져오고 NULL로 추가되었던 아이템 제거 한 후 추가한다.
Adapter에 알리게 되면 다음 스크롤이 진행된다.
ScrollView: 수직(위아래)로 스크롤하는 기능.
HorizontalScrollView: 수평(좌우)으로 스크롤하는 기능.
주의할점 : 스크롤뷰에는 단 하나의 위젯만 넣을 수 있다
그래서, 스크롤뷰 안에 리니어레이아웃(LinearLayout)을 1개 넣고(일반적으로 LinearLayout을 사용, 다른 layout도 가능), 그 안에 자신이 원하는 위젯을 여러 개 넣는 방법을 사용
만약 스크롤뷰 내부에 둘 이상의 위젯을 넣게 된다면 아래와 같은 로그를 확인하게 될것이다.
java.lang.IllegalStateException: ScrollView can host only one direct child