我正在开展一个项目,我想在其中添加View
转换,如下所示。我不知道从哪里开始,任何人都可以帮助我吗?
答案 0 :(得分:1)
有几种方法可以实现这种效果,不知道该词汇应用程序是如何处理它的,但是获得非常类似效果的一种非常简单的方法是使用多个RecyclerView.ViewHolder
类型,然后让{ {3}}负责动画工作。这是解决这个问题的唯一方法:
<强>模型强>
我们的模型将包含我们要显示的数据以及type
,以通知我们DefaultItemAnimator
哪个ReclerView.ViewHolder
要充气。所以,它可能看起来像RecyclerView.Adapter
:
@AutoValue
public abstract class ExpandableModel {
public static final int TYPE_STATIC = 0;
public static final int TYPE_EXPANDED = 1;
public static final int TYPE_COLLAPSED = 2;
@Nullable public abstract List<ExpandableModel> data();
public abstract String title();
public abstract int progress();
public abstract int max();
public abstract int type();
public static ExpandableModel createExpanded(List<ExpandableModel> data,
String title, int progress, int max) {
return new AutoValue_ExpandableModel(data, title, progress, max, TYPE_EXPANDED);
}
public static ExpandableModel createCollapsed(List<ExpandableModel> data,
String title, int progress, int max) {
return new AutoValue_ExpandableModel(data, title, progress, max, TYPE_COLLAPSED);
}
public static ExpandableModel createExpanded(ExpandableModel model) {
return new AutoValue_ExpandableModel(
model.data(), model.title(), model.progress(), model.max(), TYPE_EXPANDED);
}
public static ExpandableModel createCollapsed(ExpandableModel model) {
return new AutoValue_ExpandableModel(
model.data(), model.title(), model.progress(), model.max(), TYPE_COLLAPSED);
}
public static ExpandableModel createStatic(String title, int progress, int max) {
return new AutoValue_ExpandableModel(null, title, progress, max, TYPE_STATIC);
}
}
<强> ViewHolder 强>
我们可以定义一个基本的ReclerView.ViewHolder
,它会绑定一些ExpandableModel
数据,并为我们提供一个不错的OnClickListener
回调。
public abstract class ExpandableViewHolder extends RecyclerView.ViewHolder {
public ExpandableViewHolder(ViewGroup parent, int layout) {
super(LayoutInflater.from(parent.getContext()).inflate(layout, parent, false));
}
public void setItemClickListener(OnItemClickListener clickListener) {
itemView.setOnClickListener(v -> {
final int adapterPosition = getAdapterPosition();
if (adapterPosition != RecyclerView.NO_POSITION) {
clickListener.onItemClick(itemView, adapterPosition);
}
});
}
public abstract void bind(ExpandableModel model);
public interface OnItemClickListener {
void onItemClick(View itemView, int position);
}
}
<强> ExpandedViewHolder 强>
public class ExpandedViewHolder extends ExpandableViewHolder {
private final TextView title;
private final TextView completion;
private final ProgressBar progress;
private final RecyclerView recycler;
public ExpandedViewHolder(ViewGroup parent) {
super(parent, R.layout.adapter_view_expanded);
title = itemView.findViewById(R.id.expanded_category);
completion = itemView.findViewById(R.id.expanded_completion);
progress = itemView.findViewById(R.id.expanded_progress);
recycler = itemView.findViewById(R.id.expanded_recycler);
recycler.addItemDecoration(new SpaceItemDecoration(10));
}
@Override
public void bind(ExpandableModel model) {
title.setText(model.title());
completion.setText(model.progress() + "/" + model.max());
progress.setMax(model.max());
progress.setProgress(model.progress());
recycler.setAdapter(new ExpandableAdapter(model.data()));
}
}
ExpandedViewHolder布局
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="350dp"
android:background="#ffFFC857"
android:orientation="vertical">
<TextView
android:id="@+id/expanded_category"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:gravity="center"
android:textColor="#ffffffff"
android:textIsSelectable="false"
android:textSize="28sp"
tools:text="Basic Words" />
<TextView
android:id="@+id/expanded_completion"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:gravity="center"
android:textColor="#ffffffff"
android:textIsSelectable="false"
android:textSize="18sp"
tools:text="174/174 mastered" />
<ProgressBar
android:id="@+id/expanded_progress"
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
tools:progress="100" />
<android.support.v4.widget.Space
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<android.support.v7.widget.RecyclerView
android:id="@+id/expanded_recycler"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:layout_marginBottom="4dp"
android:orientation="horizontal"
app:layoutManager="android.support.v7.widget.LinearLayoutManager" />
</LinearLayout>
<强> CollapsedViewHolder 强>
public class CollapsedViewHolder extends ExpandableViewHolder {
private final TextView title;
private final TextView completion;
private final ProgressBar progress;
public CollapsedViewHolder(ViewGroup parent) {
super(parent, R.layout.adapter_view_collapsed);
title = itemView.findViewById(R.id.collapsed_category);
completion = itemView.findViewById(R.id.collapsed_completion);
progress = itemView.findViewById(R.id.collapsed_progress);
}
@Override
public void bind(ExpandableModel model) {
title.setText(model.title());
completion.setText(model.progress() + "/" + model.max());
progress.setMax(model.max());
progress.setProgress(model.progress());
}
}
CollapsedViewHolder布局
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="165dp"
android:layout_margin="4dp"
android:background="#ffffffff"
android:orientation="vertical">
<TextView
android:id="@+id/collapsed_category"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:gravity="center"
android:textColor="#ff066FA5"
android:textIsSelectable="false"
android:textSize="28sp"
tools:text="Basic Words" />
<TextView
android:id="@+id/collapsed_completion"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:gravity="center"
android:textColor="#ffAEB8C3"
android:textIsSelectable="false"
android:textSize="18sp"
tools:text="174/174 mastered" />
<ProgressBar
android:id="@+id/collapsed_progress"
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
tools:progress="100" />
</LinearLayout>
<强>适配器强>
现在我们可以创建RecyclerView.Adapter
了。基本上,无论何时点击某个项目,我们都会使用TYPE_EXPANDED
或TYPE_COLLAPSED
ExpandableModel
(AutoValue)替换它,调用and because DefaultItemAnimator
is already applied to RecyclerView
会很好地制作动画在两种RecyclerView.ViewHolder
之间。
public class ExpandableAdapter extends RecyclerView.Adapter<ExpandableViewHolder> {
private final List<ExpandableModel> data = new ArrayList<>(0);
private int expandedPosition;
public ExpandableAdapter(Collection<ExpandableModel> data) {
this.data.addAll(data);
}
@Override
public ExpandableViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
switch (viewType) {
case TYPE_EXPANDED:
final ExpandedViewHolder expandedHolder = new ExpandedViewHolder(parent);
expandedHolder.setItemClickListener((itemView, position) -> collapse(position));
return expandedHolder;
case TYPE_COLLAPSED:
final CollapsedViewHolder collapsedHolder = new CollapsedViewHolder(parent);
collapsedHolder.setItemClickListener((itemView, position) -> {
collapseCurrent();
expand(position);
});
return collapsedHolder;
case TYPE_STATIC:
final CollapsedViewHolder staticHolder = new CollapsedViewHolder(parent);
staticHolder.setItemClickListener((itemView, position) -> {
final ExpandableModel model = data.get(position);
Snackbar.make(itemView, model.title(), Snackbar.LENGTH_SHORT).show();
});
return staticHolder;
default:
throw new IllegalArgumentException("unknown type");
}
}
@Override
public void onBindViewHolder(ExpandableViewHolder holder, int position) {
holder.bind(data.get(holder.getAdapterPosition()));
}
@Override
public int getItemCount() {
return data.size();
}
@Override
public int getItemViewType(int position) {
return data.get(position).type();
}
private void collapseCurrent() {
final ExpandableModel curr = data.get(expandedPosition);
data.set(expandedPosition, ExpandableModel.createCollapsed(curr));
notifyItemChanged(expandedPosition);
}
private void collapse(int position) {
final ExpandableModel curr = data.get(position);
data.set(position, ExpandableModel.createCollapsed(curr));
notifyItemChanged(position);
}
private void expand(int position) {
final ExpandableModel curr = data.get(position);
data.set(position, ExpandableModel.createExpanded(curr));
notifyItemChanged(position);
expandedPosition = position;
}
}
虚拟数据
final Random ran = new SecureRandom();
final List<ExpandableModel> basic = new ArrayList<>(0);
for (int i = 0; i < 10; i++) {
final int max = 10;
final int progress = ran.nextInt(max + 1);
final String title = ("Basic Words: " + (i + 1));
basic.add(ExpandableModel.createStatic(title, progress, max));
}
final List<ExpandableModel> intermediate = new ArrayList<>(0);
for (int i = 0; i < 10; i++) {
final int max = 10;
final int progress = ran.nextInt(max + 1);
final String title = ("Intermediate Words: " + (i + 1));
intermediate.add(ExpandableModel.createStatic(title, progress, max));
}
final List<ExpandableModel> advanced = new ArrayList<>(0);
for (int i = 0; i < 10; i++) {
final int max = 10;
final int progress = ran.nextInt(max + 1);
final String title = ("Advanced Words: " + (i + 1));
advanced.add(ExpandableModel.createStatic(title, progress, max));
}
final List<ExpandableModel> data = new ArrayList<>(0);
data.add(ExpandableModel.createCollapsed(basic, "Basic Words", 7, 10));
data.add(ExpandableModel.createCollapsed(intermediate, "Intermediate Words", 5, 10));
data.add(ExpandableModel.createCollapsed(advanced, "Advanced Words", 3, 10));
final RecyclerView recycler = findViewById(android.R.id.list);
recycler.setAdapter(new ExpandableAdapter(data));
<强>附加强>
public class SpaceItemDecoration extends RecyclerView.ItemDecoration {
private final int space;
public SpaceItemDecoration(int space) {
this.space = space;
}
@Override
public void getItemOffsets(Rect outRect, View view,
RecyclerView parent, RecyclerView.State state) {
final int childPosition = parent.getChildLayoutPosition(view);
if (childPosition == RecyclerView.NO_POSITION) {
return;
}
if (childPosition < 1 || childPosition >= 1) {
outRect.left = space;
}
if (childPosition == getTotalItemCount(parent) - 1) {
outRect.right = space;
}
}
private static int getTotalItemCount(RecyclerView parent) {
return parent.getAdapter().getItemCount();
}
}
结果(RecyclerView.Adapter.notifyItemChanged
)