简体   繁体   English

使用 Recyclerview 中的 itemTouchHelper 在 cardview 上拖动高程平移z

[英]Android drag elevation translationz on cardview with itemTouchHelper in Recyclerview

i have a problem figuring out how to give cardViews temporarily elevation on drag.我在弄清楚如何在拖动时暂时提升 cardViews 时遇到问题。 I use a recycler view with cardViews and this is my itemtouchhelper:我使用带有 cardViews 的回收器视图,这是我的 itemtouchhelper:

class ListTouchHelper extends ItemTouchHelper.Callback {

    private final ActionCompletionContract contract;

    public ListTouchHelper(ActionCompletionContract contract) {
        this.contract = contract;
    }
    @Override
    public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
        int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
        int swipeFlags = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
        return makeMovementFlags(dragFlags, swipeFlags);
    }

    @Override
    public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
        contract.onViewMoved(viewHolder.getAdapterPosition(), target.getAdapterPosition());
        return true;
    }

    @Override
    public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
        if (direction == ItemTouchHelper.LEFT) {
            contract.onViewSwipedLeft(viewHolder.getAdapterPosition());
        } else if (direction == ItemTouchHelper.RIGHT) {
            contract.onViewSwipedRight(viewHolder.getAdapterPosition());
        }
    }

    public interface ActionCompletionContract {
        void onViewMoved(int oldPosition, int newPosition);
        void onViewSwipedLeft(int position);
        void onViewSwipedRight(int position);
    }
}


I have managed to give it temporarily elevation with:我设法通过以下方式暂时提升它:
在此处输入图片说明

Which resulted in: (the shadows are somehow clipped?)这导致:(阴影以某种方式被剪掉了?)
在此处输入图片说明

However, once the view is just slightly moved, the elevation disappears:但是,一旦视图稍微移动,高程就会消失:
在此处输入图片说明

My question is: how do i get the elevation (including shadows) when the cards are being dragged?我的问题是:拖动卡片时如何获得高度(包括阴影)?

Thanks in advance!提前致谢!

Ok so I solved it, kindof.好的,所以我解决了它,有点。 I think for some other reason its not working by default, however I managed to write a workaround.我认为由于其他一些原因它默认不起作用,但是我设法编写了一个解决方法。

private boolean first = true; //first draw of cardView?
private boolean last = false; //last draw of cardView?

@Override
public void onChildDraw(@NonNull Canvas c, @NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
    //add elevation on first draw
    if (first) {
        ViewPropertyAnimator animator = viewHolder.itemView.animate();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { //consider SDK version
            viewHolder.itemView.setTranslationZ(7);
            animator.start();
        }
        first = false;
    }
    //remove translationZ in last edit
    if (last) {
        ViewPropertyAnimator animator = viewHolder.itemView.animate();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { //consider SDK version
            viewHolder.itemView.setTranslationZ(0);
            animator.start();
        }
        //reset values
        last=false;
        first=true;
    }
    super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}

@Override
public void clearView(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
    super.clearView(recyclerView, viewHolder);
    last = true; //only one more OnChildDrawWillBeCalled
}

The above code is added to your ItemTouchHelper.Callback and all should work.上面的代码被添加到你的 ItemTouchHelper.Callback 中,一切都应该有效。 The basic idea is to manually control the drawing of the translationz.基本思想是手动控制translationz的绘制。 For that I figure out when is the first canvas drawn, and when the last, whereas the cancas will show the shadow.为此,我弄清楚何时绘制第一个画布,何时绘制最后一个,而 Cancas 将显示阴影。

Maxbe one more comment: the ViewPropertyAnimator in combination with the xml layout file is incredibly unintuitive and buggy, so if you can avoided I would reccomend to do so, and instead try programmatically animating the view changes and effects. Maxbe 的另一条评论:ViewPropertyAnimator 与 xml 布局文件的结合非常不直观且有缺陷,因此如果您可以避免,我会建议这样做,而是尝试以编程方式为视图更改和效果设置动画。

Hope this can help someone.希望这可以帮助某人。

@LivinTheNoobLife in your solution you are using the ViewPropertyAnimator, but you are not setting any translation to it, hence, no animations will be applied. @LivinTheNoobLife 在您的解决方案中,您使用的是 ViewPropertyAnimator,但您没有对其进行任何转换,因此不会应用任何动画。

This is my solution with a properly working floating animation:这是我的解决方案,具有正常工作的浮动动画:

class DragHelper extends ItemTouchHelper.Callback {    
private boolean cardPicked = true;
private boolean reset = false;

@Override
public void onChildDraw(@NonNull Canvas c, @NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {

    // elevate only when picked for the first time
    if (cardPicked) { 
        ViewPropertyAnimator animator = viewHolder.itemView.animate();
        animator.translationZ(16);
        animator.setDuration(200);
        animator.setInterpolator(new AccelerateDecelerateInterpolator());
        animator.start();

        cardPicked = false;
    }

    // when your item is not floating anymore
    if (reset){
        ViewPropertyAnimator animator = viewHolder.itemView.animate();

        animator.translationZ(0);
        animator.setDuration(200);
        animator.setInterpolator(new AccelerateInterpolator());
        animator.start();

        cardPicked = true;
        reset = false;
    }
    super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}

// As the doc says
// Called by the ItemTouchHelper when the user interaction with an element is over and it also completed its animation.
@Override
public void clearView(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
    super.clearView(recyclerView, viewHolder);

     // interaction is over, time to reset our elevation
     reset = true;
}
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM