Android Recycler + CardView с иконкой и Spinner - проблема сортировки - PullRequest
0 голосов
/ 21 февраля 2019

Итак, у меня сейчас большая проблема с моим текущим приложением.

Сначала позвольте мне обернуть общие настройки:

Я использую Room для моей базы данных, и моя сущность называетсяПодколонный столбец о «numUsage» (количество использований).Пользовательский интерфейс действия представляет собой RecyclerView с CardView - лучше сказать, это две карты плюс один значок сердца в строке.

  • Первая карта: показывает имя Sub
  • Вторая карта:Показывает количество использований Sub
  • Значок сердца: если щелкнуть этот значок, он должен превратиться в заполненное сердце (например, в Instagram) и подсчитать точку использования его Sub (идея также состоит в том, чтобы сделать его активным только по клику).один раз в день это проблема будущего)

Вверху у меня есть счетчик, который дает пользователю возможность «сортировать» список, который он получает.Он может отсортировать его после «ввода» (в порядке того, как Subs были введены в БД), «top» (numUsage DESC) и «flop» (numUsage ASC)

Сама сортировка происходит через DAOпрямо из базы данных, и как бы ни был выбран спиннер, Activity требует «подходящего» DAO (показано в коде ниже).

Сортировка работает.Также работает тот факт, что всякий раз, когда я нажимаю на иконку сердца Sub, numUsage считает один, и сущность обновляется.

Теперь мы сталкиваемся с проблемой: когда я нажимаю иконку сердца, она меняется (как яхочу) - но когда я теперь установил счетчик на другой «способ сортировки» (например, от «входа» до «верха»), два CardViews обновляются / сортируются, но значок сердца остается в той же позиции (но он также должен двигатьсяпотому что я хочу увидеть, какой Sub уже получил счет)

Я знаю, что это потому, что я на самом деле не сортирую Карты, а просто способ, которым я беру Данные из Базы данных и пишу Карты новые (таким образом, значок сердца остается в своем первоначальном положении).Но я просто упускаю правильную идею, как я мог это исправить.

Было бы здорово, если бы вы мне помогли!


Вот небольшая картинка, иллюстрирующая мою проблему:

enter image description here


SubDAO :

//Get all subs
@Query("SELECT * FROM subscriptions")
LiveData<List<Sub>> getAllSubs();

//Get sub with less used points (=worst/flop Sub)
@Query("SELECT * FROM subscriptions ORDER BY numUsage ASC")
LiveData<List<Sub>> getAllFlopSubs();

//Get sub with most used points (=top Sub)
@Query("SELECT * FROM subscriptions ORDER BY numUsage DESC")
LiveData<List<Sub>> getAllTopSubs();

UsageActivity - что происходит с вращателем:

@Override
public void onItemSelected(AdapterView<?> parent, View v, int position, long id){
    switch (position){
        case 0:
            ((TextView) parent.getChildAt(0)).setTextColor(getResources().getColor(R.color.midBlue));
            setupListViewEntry();
            break;
        case 1:
            ((TextView) parent.getChildAt(0)).setTextColor(getResources().getColor(R.color.midBlue));
            setupListViewTop();
            break;
        case 2:
            ((TextView) parent.getChildAt(0)).setTextColor(getResources().getColor(R.color.midBlue));
            setupListViewFlop();
            break;

    }
}


@Override
public void onNothingSelected(AdapterView<?> arg0){
    setupListViewEntry();
}






private void setupListViewEntry() {
    mSubViewModel.getAllSubs().observe(this, new Observer<List<Sub>>() {
        @Override
        public void onChanged(@Nullable List<Sub> subs) {
            mAdapter.setSubs(subs);

        }
    });
}






private void setupListViewTop() {
    mSubViewModel.getAllTopSubs().observe(this, new Observer<List<Sub>>() {
        @Override
        public void onChanged(@Nullable List<Sub> subs) {
            mAdapter.setSubs(subs);

        }
    });
}






private void setupListViewFlop() {
    mSubViewModel.getAllFlopSubs().observe(this, new Observer<List<Sub>>() {
        @Override
        public void onChanged(@Nullable List<Sub> subs) {
            mAdapter.setSubs(subs);

        }
    });
}

UsageAdapter :

открытый класс UsageSubAdapter расширяет RecyclerView.Adapter {

List<Sub> subList;
Context context;
private final LayoutInflater mInflater;

UsageSubAdapter (Context context) {
    mInflater = LayoutInflater.from(context);
}


public class ViewHolder extends  RecyclerView.ViewHolder {
    public TextView subUsage_name_cv_dummy;
    public TextView subUsage_times_cv_dummy;
    public View clickable;
    public ImageView plus_usage;
    public ViewHolder(View itemView) {
        super(itemView);
        subUsage_name_cv_dummy = itemView.findViewById(R.id.usage_name_dummy);
        subUsage_times_cv_dummy = itemView.findViewById(R.id.usage_times_dummy);
        clickable = itemView.findViewById(R.id.usage_cv_left);
        plus_usage = itemView.findViewById(R.id.usage_like_btn);
    }
}

@Override
public UsageSubAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType){
    View subview = mInflater.inflate(R.layout.cv_usage, parent, false);

    return new UsageSubAdapter.ViewHolder(subview);
}


@Override
public void onBindViewHolder (final UsageSubAdapter.ViewHolder holder, int position) {

    //Set Texts for CardViews
    if (subList!= null){
        final Sub current = subList.get(position);

        holder.subUsage_name_cv_dummy.setText(current.getSubName());
        holder.subUsage_times_cv_dummy.setText(Integer.toString(current.getNumUsage()));

        holder.clickable.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //Click on left CV to open up InfoFragment
                ShowInfoFragment currentFrag = ShowInfoFragment.newInstance(current);
                UsageActivity.fragmentManager.beginTransaction().replace(R.id.compLayout, currentFrag).addToBackStack(null).commit();
                Log.d("Clicking: ", current.getSubName() + " was clicked - Listener worked");
            }
        });

        holder.plus_usage.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //Count up usage point
                int currentUsage = current.getNumUsage();
                int newUsage = currentUsage + 1;
                current.setNumUsage(newUsage);
                updateNumUsage(current);

                //change icon so the user knows it was clicked (for today)
                holder.plus_usage.setImageResource(R.drawable.ic_usage_point_given);
                //make it only clickable once a day

            }
        });
    }
    else {
        holder.subUsage_name_cv_dummy.setText("Create a new Sub!");
        holder.subUsage_times_cv_dummy.setText("00");
    }

}



//Updating the number of Usages
private void updateNumUsage (final Sub sub){
    new Thread(new Runnable() {
        @Override
        public void run() {
            Looper.prepare();
            SubDatabase.getInstance(context)
                    .getsubDAO()
                    .updateSub(sub);
        }
    }).start();
}




public void setSubs(List<Sub> subs){
    this.subList = subs;
    notifyDataSetChanged();
}



@Override
public int getItemCount(){
    if(subList!=null){
        return subList.size();
    } else
    {
        return 0;
    }
}

}

1 Ответ

0 голосов
/ 21 февраля 2019

Проблема в том, что в данный момент вы не сохраняете значение значка сердца.А без этой информации вы не можете сказать RecyclerView, как ее отобразить.

Глядя на свой onBindViewHolder, вы обновляете значение для имени и счетчика, но не для сердца.Вы активируете сердце только тогда, когда щелкаете по нему.

final Sub current = subList.get(position);

holder.subUsage_name_cv_dummy.setText(current.getSubName());
holder.subUsage_times_cv_dummy.setText(Integer.toString(current.getNumUsage()));

// TODO - Set the current state of the heart icon.

holder.clickable.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
       // ...
    }
});
holder.plus_usage.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        holder.plus_usage.setImageResource(R.drawable.ic_usage_point_given);
    }
});

Вам нужно только сохранить значение и использовать его при рендеринге.Для этого примера предположим, что вы добавили boolean isActive = false; в свой класс Sub.

Во-первых, поскольку нам нужно обновить значок в двух местах (рендеринг и onClick), я бы создалмаленькая функция, как это.

void updateUsageIcon(UsageSubAdapter.ViewHolder holder, Sub sub) {
    if( sub.isActive ) {
        holder.plus_usage.setImageResource(R.drawable.ic_usage_point_given);
    } else {
        // TODO show inactive state
    }
}

А затем, в вашем ViewHolder, вы можете сделать что-то вроде этого.

final Sub current = subList.get(position);

holder.subUsage_name_cv_dummy.setText(current.getSubName());
holder.subUsage_times_cv_dummy.setText(Integer.toString(current.getNumUsage()));

// Set the current value.
updateUsageIcon(holder, sub);

holder.plus_usage.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {

        // Add logic to check if the user is allowed to set this to true today.
        sub.isActive = true;

        // Update the current value.
        updateUsageIcon(holder, sub);
    }
});
...