RecyclerView 簡介
基本使用方法:
Before:
@InjectView(R.id.icons)
RecyclerView icons;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final List<String> list = new ArrayList<>(Arrays.asList("http://example.com/a.png")));
RecyclerAdapter<IconViewHolder> listAdapter = new RecyclerAdapter<>() {
@Override
public IconViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new IconViewHolder(LayoutInflater.from(context).inflate(R.layout.item_icon, parent, false)));
}
@Override
public void onBindViewHolder(IconViewHolder viewHolder, int position) {
viewHolder.icon.setImageURI(Uri.parse(list.get(position)));
}
}
icons.setLayoutManager(new LinearLayoutManager(activity));
icons.setAdapter(listAdapter);
list.add("http://example.com/b.png");
listAdapter.notifyDataSetChanged();
}
public class IconViewHolder extends BindViewHolder<String> {
@InjectView(R.id.icon)
public SimpleDraweeView icon;
public IconViewHolder(View itemView) {
super(itemView);
ButterKnife.inject(this, itemView);
}
}
有資料外漏的情形。
改用筆者簡單寫的 ListRecyclerAdapter<T, VH>
(https://github.com/yongjhih/recyclerlist)
https://gist.github.com/yongjhih/d8db8c69190293098eec
After:
@InjectView(R.id.icons)
public RecyclerView icons;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ListRecyclerAdapter<String, IconViewHolder> listAdapter = ListRecyclerAdapter.create();
listAdapter.getList().add("http://example.com/a.png");
listAdapter.createViewHolder((parent, viewType) -> new IconViewHolder(LayoutInflater.from(context).inflate(R.layout.item_icon, parent, false)));
icons.setLayoutManager(new LinearLayoutManager(activity));
icons.setAdapter(listAdapter);
listAdapter.getList().add("http://example.com/b.png");
listAdapter.notifyDataSetChanged(); // TODO hook List.add(), List.addAll(), etc. modifitable operations
}
IconViewHolder:
public class IconViewHolder extends BindViewHolder<String> {
@InjectView(R.id.icon)
public SimpleDraweeView icon;
public IconViewHolder(View itemView) {
super(itemView);
ButterKnife.inject(this, itemView);
}
@Override
public void onBind(int position, String item) {
icon.setImageURI(Uri.parse(item));
}
}
以 Avatar 頭像為例:
// 1. listAdapter.createViewHolder(): 決定使用哪種 layout + viewHolder
// 2. ViewModel.builder(): 以及如何把原始資料降階至流通性資料格式
// 不需要瞭解具備 View 相關設定知識,如圖片顯示現在是用 SimpleDraweeView.setImageURI(Uri) 如何設定,還是用 ImageLoader.getInstance().displayImage(ImageView iv, String url) 該如何使用之類的知識。只要乖乖把資料按照流通資料介面填好就好。
// 如果畫面要微調,直接複製 layout 調整風格。
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
//ListRecyclerAdapter<String, IconViewHolder> listAdapter = ListRecyclerAdapter.create();
//listAdapter.getList().add("http://example.com/a.png");
ListRecyclerAdapter<AvatarViewModel, AvatarViewHolder> listAdapter = ListRecyclerAdapter.create();
listAdapter.createViewHolder((parent, viewType) -> new AvatarViewHolder(LayoutInflater.from(context).inflate(R.layout.item_icon, parent, false)));
listAdapter.getList().add(AvatarViewModel.builder().icon("http://example.com/a.png").name("Andrew Chen").updatedAt(new Date().getTime()).build());
for (User user : getUsers()) { // 新增其他使用者
listAdapter.getList().add(AvatarViewModel.builder().icon(user.getPicture()).name(user.getDisplayName()).updatedAt(user.getUpdatedAt().getTime()).build());
}
// via RxJava
// listAdapter.getList().addAll(Observable.from(getUsers()).map(user -> AvatarViewModel.builder().icon(user.getPicture()).name(user.getDisplayName()).build()).updatedAt(user.getUpdatedAt().getTime()).toList().toBlocking().single());
...
}
// 只需具備 View 相關知識,設定流通性資料
// 不需要瞭解原始資料來源格式(不管是從 Facebook/Parse 還是 local sqlite 或 local SharedPreferences) ,只瞭解流通性基本資料格式即可。
// 其中一個優點是當來源資料改變成其他格式,你依然可以沿用此 ViewHolder
public class AvatarViewHolder extends BindViewHolder<AvatarViewModel> {
@InjectView(R.id.icon)
public SimpleDraweeView icon;
@InjectView(R.id.text1)
public TextView name;
@InjectView(R.id.updatedAt)
public RelativeTimeTextView updatedAt;
public AvatarViewHolder(View view) {
super(view);
ButterKnife.inject(this, view);
}
@Override
public void onBind(int position, AvatarViewModel item) {
//icon.setImageURI(Uri.parse(item));
icon.setImageURI(Uri.parse(item.icon()));
name.setText(item.name());
updatedAt.setReferenceTime(item.updatedAt());
}
}
// 提供流通性基本資料的介面
@AutoParcel
public abstract class AvatarViewModel implements Parcelable {
public abstract String icon();
public abstract String name();
public abstract Long updatedAt();
public static Builder builder() {
return new AutoParcel_AvatarViewModel.Builder();
}
@AutoParcel.Builder
public interface Builder {
public Builder icon(String x);
public Builder name(String x);
public Builder updatedAt(Long x);
public AvatarViewModel build();
}
}