Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/221.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 刷卡到喜爱的项目_Android_Animation_Android Recyclerview_Android Cardview - Fatal编程技术网

Android 刷卡到喜爱的项目

Android 刷卡到喜爱的项目,android,animation,android-recyclerview,android-cardview,Android,Animation,Android Recyclerview,Android Cardview,当我无意中发现的时候,我正在浏览谷歌的材料文档。它显示了一个卡片项目,可以向右滑动以收藏该项目 我想模仿这种行为,但失败了多次。我能找到的所有库和教程都是关于“滑动以删除”。我尝试将两个视图堆叠在一起,上面的视图应该被滑动,这样下面的视图就可以被看到。我试图用ItemTouchHelper实现这一点,但是这个类似乎只能帮助滑动以删除和移动以重新排序列表操作 如何实现此滑动操作?默认的ItemTouchHelper为onsweed提供回调,它可以包含您选择的任何逻辑,而不仅仅是删除。您肯定可以使用

当我无意中发现的时候,我正在浏览谷歌的材料文档。它显示了一个卡片项目,可以向右滑动以收藏该项目

我想模仿这种行为,但失败了多次。我能找到的所有库和教程都是关于“滑动以删除”。我尝试将两个视图堆叠在一起,上面的视图应该被滑动,这样下面的视图就可以被看到。我试图用
ItemTouchHelper
实现这一点,但是这个类似乎只能帮助
滑动以删除
移动以重新排序列表操作


如何实现此滑动操作?

默认的
ItemTouchHelper
onsweed
提供回调,它可以包含您选择的任何逻辑,而不仅仅是删除。您肯定可以使用代码将项目标记为收藏夹。但是,我认为这需要对物品进行完全的滑动,而不是像视频中显示的那样进行部分滑动

以下两种方法都使用Canvas和graphics类进行细粒度控制,您应该能够镜像行为

说明如何在滑动项目时显示操作按钮。它修改并删除不必要的滑动方向处理

要获得更详细、逐步的解释,您也可以查看。当它显示“编辑”和“删除”按钮时,这些按钮的onClick回调中的代码可以替换为将项目标记为收藏夹。

您需要使用

  • 这是一个实用程序类,用于将刷卡添加到
    disclose
    ,并将拖放支持添加到
    RecyclerView
  • 它与一个
    RecyclerView
    和一个回调类一起工作,该类配置启用的交互类型,并在用户执行这些操作时接收事件
下面是如何将
ItemTouchHelper
RecyclerView
一起使用的示例代码

堆栈活动

R.drawable.ic_最爱


可拉拔。ic_fav_白色


以上示例代码的输出

有关信息,请查看下面的文章

如果你想去任何一个图书馆,请检查这个


这是一个很好的效果,但目前还没有现成的标准方法。安卓确实提供了一套工具来创造这种效果,所以让我们看看它是如何实现的

方法

  • 定义一个包含两层的布局:底层包含一个容纳心形的容器。这是将被激活的心脏。顶层将是向右滑动以显示底层的层

  • 为心脏创建动画。下面我将介绍一种基于azizbekian对堆栈溢出问题的回答创建“心跳”动画的方法

  • 创建一个扩展类:在该类中,您需要覆盖
    onchildraw()
    ,以处理在上述1)布局中设置的滑动面板的移动
    onchildraw()
    也是执行动画的好地方。当滑动视图滑动到您将定义的“触发点”时,将触发动画。此类还有其他需要重写的方法。见下文

  • item_card.xml

    这是针对
    RecyclerVIew
    项的两层布局。这里我使用的是
    框架布局
    ,但也可以使用其他视图组。这就是它看起来的样子。你看到的心脏在顶层。跳动的心脏在下面。根据项目是否为收藏夹,可以将顶部心形设置为可见/不可见。下面是它的外观:

    并打开(我手动设置
    translationX

    onchildraw()
    请参阅
    onchildraw()
    的文档

    要在
    ItemTouchHelper.SimpleCallback中重写的其他方法

    • onSelectedChanged()
      clearView
    • onMove()
      onsweed()
      -在这些方法中不执行任何操作
    • IsItemViewSwipEnabled()
    • isLongPressDragEnabled()

    还有很多细节,但这只是重要部分的概述。

    感谢您的详细评论。在某种程度上,这似乎是我所需要的,但不是全部。问题是,我包含的视频来自谷歌的官方材料文档,所以我希望有一些简单的东西来实现这一点。你知道当用户向左滑动时如何添加回调,以从视频中的背景创建动画吗?根据我的搜索,没有任何直接的内置方法来实现该行为,尽管它来自官方文档。它需要手动处理触摸事件并绘制触摸区域,或者在具有可单击按钮的行下显示布局。因为这需要大量的工作,所以使用现有的库是最好的。你可能会从其他答案中得到更好的库建议。至于动画本身,它很可能应用于最初隐藏的紫色背景视图。同时,心形按钮从黑色切换到白色。一旦实现了部分刷卡行为,它的实现应该相对简单。由于这是自定义行为,因此不会有任何标准回调,并且在满足条件(部分滑动)后必须触发动画。
    import android.os.Bundle;
    import android.support.annotation.NonNull;
    import android.support.v7.app.AppCompatActivity;
    import android.support.v7.widget.LinearLayoutManager;
    import android.support.v7.widget.RecyclerView;
    import android.support.v7.widget.helper.ItemTouchHelper;
    import java.util.ArrayList;
    
    public class StackActivity extends AppCompatActivity {
    
    
        RecyclerView myRecyclerView;
        private ArrayList<ItemModel> arrayList = new ArrayList<>();
        FavAdapter favAdapter;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_stack);
    
            myRecyclerView = findViewById(R.id.myRecyclerView);
            myRecyclerView.setLayoutManager(new LinearLayoutManager(this));
            myRecyclerView.setHasFixedSize(true);
    
            // here i'm adding dummy data inside list
            addDataInList();
    
            // setting adapter to RecyclerView
            favAdapter = new FavAdapter(this, arrayList);
            myRecyclerView.setAdapter(favAdapter);
    
            new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
                @Override
                public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
                    return false;
                }
    
                @Override
                public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
    
                    // when user swipe thr recyclerview item to right remove item from avorite list
                    if (direction == ItemTouchHelper.RIGHT) {
                        favAdapter.addToFav(viewHolder.getAdapterPosition(), false);
                    }
                    // when user swipe thr recyclerview item to left remove item from avorite list
                    else if (direction == ItemTouchHelper.LEFT) {
                        favAdapter.addToFav(viewHolder.getAdapterPosition(), true);
                    }
    
                }
            }).attachToRecyclerView(myRecyclerView);
    
    
        }
    
    
        //method to add dummy data inside ourlist
        private void addDataInList() {
    
            arrayList.add(new ItemModel("Item 1", "https://i.stack.imgur.com/1dWdI.jpg", false));
            arrayList.add(new ItemModel("Item 2", "https://i.stack.imgur.com/1dWdI.jpg", false));
            arrayList.add(new ItemModel("Item 3", "https://i.stack.imgur.com/1dWdI.jpg", false));
            arrayList.add(new ItemModel("Item 4", "https://i.stack.imgur.com/1dWdI.jpg", false));
            arrayList.add(new ItemModel("Item 5", "https://i.stack.imgur.com/1dWdI.jpg", false));
            arrayList.add(new ItemModel("Item 6", "https://i.stack.imgur.com/1dWdI.jpg", false));
            arrayList.add(new ItemModel("Item 7", "https://i.stack.imgur.com/1dWdI.jpg", false));
            arrayList.add(new ItemModel("Item 8", "https://i.stack.imgur.com/1dWdI.jpg", false));
            arrayList.add(new ItemModel("Item 9", "https://i.stack.imgur.com/1dWdI.jpg", false));
            arrayList.add(new ItemModel("Item 10", "https://i.stack.imgur.com/1dWdI.jpg", false));
            arrayList.add(new ItemModel("Item 11", "https://i.stack.imgur.com/1dWdI.jpg", false));
            arrayList.add(new ItemModel("Item 12", "https://i.stack.imgur.com/1dWdI.jpg", false));
            arrayList.add(new ItemModel("Item 13", "https://i.stack.imgur.com/1dWdI.jpg", false));
            arrayList.add(new ItemModel("Item 14", "https://i.stack.imgur.com/1dWdI.jpg", false));
            arrayList.add(new ItemModel("Item 15", "https://i.stack.imgur.com/1dWdI.jpg", false));
            arrayList.add(new ItemModel("Item 16", "https://i.stack.imgur.com/1dWdI.jpg", false));
            arrayList.add(new ItemModel("Item 17", "https://i.stack.imgur.com/1dWdI.jpg", false));
            arrayList.add(new ItemModel("Item 18", "https://i.stack.imgur.com/1dWdI.jpg", false));
            arrayList.add(new ItemModel("Item 19", "https://i.stack.imgur.com/1dWdI.jpg", false));
            arrayList.add(new ItemModel("Item 20", "https://i.stack.imgur.com/1dWdI.jpg", false));
        }
    
    }
    
    <?xml version="1.0" encoding="utf-8"?>
    <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="match_parent"
        android:orientation="vertical">
    
        <android.support.v7.widget.RecyclerView
            android:id="@+id/myRecyclerView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>
    
    </LinearLayout>
    
    import android.content.Context;
    import android.support.annotation.NonNull;
    import android.support.v7.widget.RecyclerView;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.ImageView;
    import android.widget.TextView;
    import com.bumptech.glide.Glide;
    import com.bumptech.glide.request.RequestOptions;
    
    import java.util.ArrayList;
    
    public class FavAdapter extends RecyclerView.Adapter<FavAdapter.ViewHolder> {
        private Context context;
        private ArrayList<ItemModel> arrayList = new ArrayList<>();
    
        public FavAdapter(Context context, ArrayList<ItemModel> arrayList) {
            this.context = context;
            this.arrayList = arrayList;
        }
    
        @NonNull
        @Override
        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(context).inflate(R.layout.custom_fav_layout, parent, false);
            return new ViewHolder(view);
        }
    
        @Override
        public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
    
    
            // here i'm check that if item is already added in favorite  or not
            //based on boolean flag i'm managed to set weather the item is in favorite or not
            // this flag is also use full to keep state of out favorite when we scroll our recyclerview
            holder.ivFavImage.setImageResource(arrayList.get(position).isFavorite()
                    ? R.drawable.ic_favorite : R.drawable.ic_fav_white);
    
    
            holder.tvProductName.setText(arrayList.get(position).getItemName());
    
            Glide.with(context)
                    .load(arrayList.get(position).getImageUrl())
                    .apply(new RequestOptions().
                            placeholder(R.drawable.ic_placeholder)
                            .error(R.drawable.ic_error))
                    .into(holder.ivProductImage);
        }
    
        // this method is used to add or remove item from favorite list when use swipe the recyclerview item using ItemTouchHelper
        public void addToFav(int position, boolean flag) {
            arrayList.get(position).setFavorite(flag);
            notifyDataSetChanged();
        }
    
    
        @Override
        public int getItemCount() {
            return arrayList.size();
        }
    
        public class ViewHolder extends RecyclerView.ViewHolder {
    
            ImageView ivProductImage, ivFavImage;
            TextView tvProductName;
    
            public ViewHolder(View itemView) {
                super(itemView);
    
                ivProductImage = itemView.findViewById(R.id.ivProductImage);
                ivFavImage = itemView.findViewById(R.id.ivFavImage);
                tvProductName = itemView.findViewById(R.id.tvProductName);
    
    
                ivFavImage.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        if (arrayList.get(getAdapterPosition()).isFavorite()) {
                            arrayList.get(getAdapterPosition()).setFavorite(false);
                        } else {
                            arrayList.get(getAdapterPosition()).setFavorite(true);
                        }
                        notifyDataSetChanged();
                    }
                });
            }
        }
    }
    
    <?xml version="1.0" encoding="utf-8"?>
    <android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:cardElevation="5dp"
        app:cardUseCompatPadding="true">
    
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
    
            <ImageView
                android:id="@+id/ivProductImage"
                android:layout_width="match_parent"
                android:layout_height="150dp"
                android:scaleType="fitXY"
                android:adjustViewBounds="true"
                android:src="@color/colorNavBar" />
    
    
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:orientation="horizontal">
    
                <TextView
                    android:id="@+id/tvProductName"
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:text="@string/app_name"
                    android:paddingStart="5dp"
                    android:textColor="#FFFFFF"
                    android:textStyle="bold" />
    
                <ImageView
                    android:id="@+id/ivFavImage"
                    android:layout_width="50dp"
                    android:layout_height="50dp"
                    android:src="@drawable/ic_favorite" />
    
            </LinearLayout>
    
    
        </RelativeLayout>
    
    </android.support.v7.widget.CardView>
    
    public class ItemModel {
    
    
       boolean isFavorite;
       String ItemName,imageUrl;
    
        public ItemModel( String itemName, String imageUrl,boolean isFavorite) {
            this.isFavorite = isFavorite;
            ItemName = itemName;
            this.imageUrl = imageUrl;
        }
    
        public boolean isFavorite() {
            return isFavorite;
        }
    
        public void setFavorite(boolean favorite) {
            isFavorite = favorite;
        }
    
        public String getItemName() {
            return ItemName;
        }
    
        public void setItemName(String itemName) {
            ItemName = itemName;
        }
    
        public String getImageUrl() {
            return imageUrl;
        }
    
        public void setImageUrl(String imageUrl) {
            this.imageUrl = imageUrl;
        }
    }
    
    <vector xmlns:android="http://schemas.android.com/apk/res/android"
            android:width="24dp"
            android:height="24dp"
            android:viewportWidth="24.0"
            android:viewportHeight="24.0">
        <path
            android:fillColor="#FF00"
            android:pathData="M12,21.35l-1.45,-1.32C5.4,15.36 2,12.28 2,8.5 2,5.42 4.42,3 7.5,3c1.74,0 3.41,0.81 4.5,2.09C13.09,3.81 14.76,3 16.5,3 19.58,3 22,5.42 22,8.5c0,3.78 -3.4,6.86 -8.55,11.54L12,21.35z"/>
    </vector>
    
    <vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="24dp"
        android:height="24dp"
        android:viewportWidth="24.0"
        android:viewportHeight="24.0">
        <path
            android:fillColor="#FFFFFF"
            android:pathData="M12,21.35l-1.45,-1.32C5.4,15.36 2,12.28 2,8.5 2,5.42 4.42,3 7.5,3c1.74,0 3.41,0.81 4.5,2.09C13.09,3.81 14.76,3 16.5,3 19.58,3 22,5.42 22,8.5c0,3.78 -3.4,6.86 -8.55,11.54L12,21.35z"/>
    </vector>
    
    <FrameLayout android:layout_width="match_parent"
        android:layout_height="wrap_content">
    
        <FrameLayout
            android:id="@+id/heartFrame"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_gravity="start"
            android:visibility="gone">
    
            <ImageView
                android:id="@+id/heart"
                android:layout_width="50dp"
                android:layout_height="50dp"
                android:layout_gravity="top|center_horizontal"
                android:padding="8dp"
                card_view:srcCompat="@drawable/heart" />
        </FrameLayout>
    
        <androidx.cardview.widget.CardView
            android:id="@+id/slidingPanel"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:visibility="visible"
            card_view:cardBackgroundColor="@android:color/background_light"
            card_view:cardElevation="5dp"
            card_view:cardUseCompatPadding="true">
    
            <ImageView
                android:id="@+id/imageView"
                android:layout_width="100dp"
                android:layout_height="100dp"
                android:layout_gravity="center_horizontal"
                android:layout_marginBottom="35dp"
                android:paddingTop="8dp"
                card_view:srcCompat="@drawable/ic_android_green_24dp" />
    
            <TextView
                android:id="@+id/textView"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="bottom|start"
                android:paddingStart="8dp"
                android:paddingBottom="8dp"
                android:text="This is some text"
                android:textSize="20sp" />
    
            <ImageView
                android:id="@+id/favorite"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="top|start"
                android:padding="8dp"
                android:tint="@android:color/holo_red_dark"
                card_view:srcCompat="@drawable/heart" />
    
        </androidx.cardview.widget.CardView>
    </FrameLayout>
    
    private AnimatorSet getHeartBeatAnimation(View target) {
        final float from = 1.0f;
        final float to = 1.3f;
    
        ObjectAnimator scaleX = ObjectAnimator.ofFloat(target, View.SCALE_X, from, to);
        ObjectAnimator scaleY = ObjectAnimator.ofFloat(target, View.SCALE_Y, from, to);
        ObjectAnimator translationZ = ObjectAnimator.ofFloat(target, View.TRANSLATION_Z, from, to);
    
        AnimatorSet set1 = new AnimatorSet();
        set1.playTogether(scaleX, scaleY, translationZ);
        set1.setDuration(100);
        set1.setInterpolator(new AccelerateInterpolator());
    
        ObjectAnimator scaleXBack = ObjectAnimator.ofFloat(target, View.SCALE_X, to, from);
        ObjectAnimator scaleYBack = ObjectAnimator.ofFloat(target, View.SCALE_Y, to, from);
        ObjectAnimator translationZBack = ObjectAnimator.ofFloat(target, View.TRANSLATION_Z, to, from);
    
        Path path = new Path();
        path.moveTo(0.0f, 0.0f);
        path.lineTo(0.5f, 1.3f);
        path.lineTo(0.75f, 0.8f);
        path.lineTo(1.0f, 1.0f);
        PathInterpolator pathInterpolator = new PathInterpolator(path);
    
        AnimatorSet set2 = new AnimatorSet();
        set2.playTogether(scaleXBack, scaleYBack, translationZBack);
        set2.setDuration(300);
        set2.setInterpolator(pathInterpolator);
    
        AnimatorSet animSet = new AnimatorSet();
        animSet.playSequentially(set1, set2);
        return animSet;
    }
    
    int maxRightShift = 400; // Example only. This should not be hard-coded and should be set elsewhere.
    
    @Override
    public void onChildDraw(@NonNull Canvas c, @NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder,
                            float dX, float dY, int actionState, boolean isCurrentlyActive) {
        MyRecyclerViewAdapter.ItemViewHolder vh = (MyRecyclerViewAdapter.ItemViewHolder) viewHolder;
    
        // Don't let the sliding view slide more than maxRightShift amount.
        if (dX >= maxRightShift && mFavoriteChangedPosition == RecyclerView.NO_POSITION) {
            // Capture the position that has changed. Only on change per sliding event.
            mFavoriteChangedPosition = vh.getAdapterPosition();
            // Trigger the animation and do, potentially, some housekeeping.
            // setFavoriteActivation will have the animation set and triggered.
            vh.setFavoriteActivation(!vh.isFavorite());
        }
    
        // Shift just the CardView and leave underlying views.
        vh.mCardView.setTranslationX(dX);
    }