RecyclerView有多个Custom View实例作为子项。自定义视图onClick动画显示在另一个动画中

时间:2016-08-29 15:19:52

标签: java android animation android-animation

我有一个填充了自定义视图的RecyclerView,其中包含各种信息和imageButton。 此ImageButton应在单击时触发显示动画,显示前一个视图。

当RecyclerView只包含一个项目时,它确实有效,但一旦视图开始被回收,它就会开始变得奇怪。 在这种情况下,当单击imageButton时,例如项目#4时,动画将出现在项目#2中(但它是随机的)。这是一个非常奇怪的行为,因为在自定义视图中引用了两个视图(第一个和要显示的视图),而不是其他任何地方。

显示动画的所有逻辑都在Custom视图中,由onBindViewHolder()中注入的ViewModel触发(每个onBindViewHolder都会生成一个新的ViewModel。)

我考虑过使用RecyclerView.ItemAnimator,但是我需要从视图中调用notifyItemChanged(),这将是非常hacky。

感谢您的任何建议。

更新

我会添加一些代码。

这是我的自定义视图。

public class CustomView extends RelativeLayout {

    @BindView(R.id.visible_view)
    View view1;
    @BindView(R.id.hidden_view)
    View view2;
    private ViewModel viewModel;


    public CustomView(Context context) {
        this(context, null);
    }

    public CustomView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CustomView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    private void init() {
        ButterKnife.bind(this, inflate(getContext(), R.layout.custom_layout, this));
    }


    public void setViewModel(HomeworkCardVM viewModel) {
        view1.setViewModel(viewModel.subViewModel1());
        view2.setViewModel(viewModel.subViewModel2());

        viewModel.observeRevealShow()
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(aBoolean -> {
            if (aBoolean) {
                circularRevealView(visibleView, insertGradeView);
            }
        },Throwable::printStackTrace,() -> {});

        viewModel.observeRevealHide()
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(aBoolean -> {
            circularHideView(insertGradeView, visibleView);
        },Throwable::printStackTrace, () -> {});
    }

    private void circularHideView(View visibleView, View invsisibleView) {

        // get the center for the clipping circle
        int cx = visibleView.getWidth() / 2;
        int cy = visibleView.getHeight() / 2;

        // get the initial radius for the clipping circle
        float initialRadius = (float) Math.hypot(cx, cy);

        // create the animation (the final radius is zero)
        Animator anim =
                ViewAnimationUtils.createCircularReveal(visibleView, cx, cy, initialRadius, 0);

        // make the view invisible when the animation is done
        anim.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                visibleView.setVisibility(View.INVISIBLE);
                invsisibleView.setVisibility(VISIBLE);
            }
        });

        // start the animation
        anim.start();

    }

    private void circularRevealView(View visibleView, View invisibleView) {

        // get the center for the clipping circle
        int cx = visibleView.getWidth() /2;
        int cy = visibleView.getHeight() /2;

        // get the final radius for the clipping circle
        float finalRadius = (float) Math.hypot(cx, cy);

        // create the animator for this view (the start radius is zero)
        Animator anim =
                ViewAnimationUtils.createCircularReveal(invisibleView, cx, cy, 0, finalRadius);

        visibleView.setVisibility(INVISIBLE);
        invisibleView.setVisibility(View.VISIBLE);

        // make the view visible and start the animation
        anim.start();
    }

}

这是最基本的适配器。

public class Adapter extends RecyclerView.Adapter<ViewHolder> {
    private List<Item> items = new ArrayList<>();
    private Context mContext;

    public Adapter(Context mContext) {
        this.mContext = mContext;
    }

    @Override
    public HomeworkViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View v = LayoutInflater.from(mContext).inflate(R.layout.view_holder, parent, false);
        return new ViewHolder(v);
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
         holder.bindItem(items.get(position));
    }

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

更基本的观点持有人。

public class ViewHolder extends RecyclerView.ViewHolder {
    @BindView(R.id.custom_view)
    CustomView customView;

    public ViewHolder(View itemView) {
        super(itemView);
        ButterKnife.bind(this, itemView);
    }

    public void bindItem(Item item){
        ViewModel viewModel = new ViewModel(item);
        customView.setViewModel(viewModel);
    }
}

我的直觉告诉我,circularRevealView(visibleView, insertGradeView);中引用的视图在回收时被分配给另一个RecyclerView项目,我将进行调查

1 个答案:

答案 0 :(得分:0)

这不是你怎么做的。唯一的好方法是:

  • 创建自定义itemanimator
  • 实施项目更改功能
  • 当您想要为特定视图设置动画时,请调用notifiyitemchanged

正如你所建议的那样制作像你这样的动画是一种失败的好方法,因为recycleview的工作原理。您应该使用itemanimator完成所有动画以保持所有内容同步。