Проведите карту к любимому предмету - PullRequest
0 голосов
/ 08 октября 2018

Я просматривал документацию по материалам от Google, когда наткнулся на это видео .Он показывает элемент карты, который можно провести вправо, чтобы добавить элемент в избранное.

Я хочу отразить это поведение, но потерпел неудачу несколько раз.Все библиотеки и учебники, которые я могу найти, примерно swipe-to-delete.Я попытался наложить два вида друг на друга, где один сверху должен быть проведен так, чтобы нижний стал видимым.Я пытался добиться этого с помощью ItemTouchHelper, но, похоже, этот класс может только облегчить swipe-to-delete и move переупорядочение действий списка.

Как можно выполнить это действие смахивания?

Ответы [ 3 ]

0 голосов
/ 12 октября 2018

Вам необходимо использовать ItemTouchHelper

  • Это служебный класс для добавления свайпа в dismiss и поддержки перетаскивания в RecyclerView.
  • Он работает с RecyclerView и классом обратного вызова, который определяет, какой тип взаимодействия разрешен, а также получает события, когда пользователь выполняет эти действия.

ЗдесьПример кода как использовать ItemTouchHelper с RecyclerView

StackActivity

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>

класс FavAdapter

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();
                }
            });
        }
    }
}

макет custom_fav_layout

<?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>

ItemModel damodel class

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;
    }
}

R.drawable.ic_favorite

<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>

drawable.ic_fav_white

<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>

ВЫХОД вышеуказанного кода образца

https://www.youtube.com/watch?v=GKD-SDPWD3k&feature=youtu.be

Для получения информации вы можете проверить эту статью ниже

И если вы хотите пойти слюбая библиотека, чем проверить это

0 голосов
/ 18 октября 2018

Это хороший эффект, но не существует стандартного готового способа сделать это AFAIK.Android предоставляет набор инструментов для создания эффекта, поэтому давайте посмотрим, как это можно сделать.

Подход

  1. Определите макет, который имеет два слоя: Нижний слой содержит контейнер, который содержит форму сердца.Это сердце, которое будет оживлено.Верхним слоем будет слой, который скользит вправо для отображения нижележащего слоя.

  2. Создание анимации для сердца. Ниже я представляю метод, который создаетанимация "сердцебиения", основанная на ответе азизбекяна на вопрос переполнения стека здесь .

  3. Создание класса, расширяющего ItemTouchHelper.SimpleCallback : В этом классе вам нужно переопределить onChildDraw(), чтобы позаботиться о перемещении скользящей панели, установленной в схеме 1) выше.onChildDraw() также является хорошим местом для выполнения анимации.Анимация запускается, когда скользящее представление скользит к «точке запуска», которую вы определите.Этот класс имеет другие методы, которые необходимо переопределить.См. Ниже.

item_card.xml

Это двухслойный макет для элементов RecyclerVIew.Здесь я использую FrameLayouts, но можно использовать и другие группы представлений.Вот как это выглядит.Сердце, которое вы видите, находится на верхнем слое.Бьющееся сердце внизу.Верхнее сердце может быть установлено видимым / невидимым в зависимости от того, является ли элемент любимым или нет.Вот как это выглядит:

enter image description here

И открыть (я вручную установил translationX.)

enter image description here

<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>

Анимация сердцебиения
Вот инкапсулированная версия анимации Азизбекяна.Целевым представлением будет представление с id = heart.Чтобы закрасить фон, вы можете использовать круговое раскрытие анимацию с центром в сердце.

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;
}

onChildDraw ()
См. Документацию по onChildDraw() здесь .

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);
}

Другие методы, которые необходимо переопределить в ItemTouchHelper.SimpleCallback

  • onSelectedChanged() и clearView
  • onMove() и onSwiped() - ничего не делать в этих методах
  • isItemViewSwipeEnabled()
  • isLongPressDragEnabled()

Есть еще много деталей, но это общий план значимых частей.

0 голосов
/ 11 октября 2018

По умолчанию ItemTouchHelper обеспечивает обратный вызов для onSwiped, который может содержать любую логику по вашему выбору, а не только удаление.Вы можете определенно иметь код, который помечает элемент как любимый.Тем не менее, я считаю, что для этого требуется полное сведение элемента, а не частичное, как показано в вашем видео.

Оба подхода, приведенных ниже, используют классы Canvas и graphics для детального управления, и вам следуетвозможность отражать поведение.

В этой статье объясняется, как отображать кнопки действий при перелистывании элемента.Он изменяет библиотеку SwipeRevealLayout и удаляет ненужную обработку направления пролистывания.

Для более подробного пошагового объяснения вы также можете проверить эту статью .Хотя он отображает кнопки «Редактировать» и «Удалить», код в обратных вызовах onClick для этих кнопок можно заменить, чтобы вместо этого отметить элемент как избранный.

...