Android Recycler + CardView with Icon and Spinner - 排序问题

问题描述 投票:1回答:1

所以我现在用我当前的应用程序遇到了更大的问题。

首先让我总结整体设置:

我正在为我的数据库使用Room,我的实体被称为Sub - 一列是关于“numUsage”(使用次数)。 Activity的UI是带有CardView的RecyclerView - 更好的说是每行两张卡加一个心形图标。

  • 第一张卡片:显示Sub的名称
  • 第二张卡:显示Sub的使用次数
  • 心脏图标:如果点击了这个图标,它应该变成一个填充的心脏(如Instagram)并计算其Sub的使用点(这个想法也是为了让它每天只能点击一次,这是未来的问题)

最重要的是,我有一个微调器,让用户可以“排序”他得到的列表。他可以在“进入”之后(根据Subs如何进入DB),“top”(numUsage DESC)和“flop”(numUsage ASC)对其进行排序。

排序本身通过DAO直接从数据库中进行,然而微调器的选择是,Activity调用“拟合”DAO(在下面的代码中显示)。

分拣工作。事实上,无论何时我点击Sub的Heart图标,numUsage都会计算一个,并且实体会更新。

现在我们遇到了麻烦:当我点击心脏图标时它会改变(就像我想要的那样) - 但是当我现在将微调器设置为另一个“排序方式”(从“入口”到“顶部”)时,两个CardViews更新/排序,但心脏图标保持在相同的位置(但它应该移动,因为我想看看哪个Sub已经计数了)

我知道这是因为我实际上并没有对卡片进行排序,而只是将数据从数据库中取出并且我正在将卡片写入新的(因此心脏图标保持在其原始位置)。但我只是错过了正确的想法,我怎么能解决这个问题。

如果你可以帮助我,那会很棒!


这是一张小图片来说明我的问题:

enter image description here


sub DAO:

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

}

android sorting android-recyclerview android-room cardview
1个回答
1
投票

问题是您当前没有存储心脏图标的值。没有这些信息,你无法告诉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);
    }
});
© www.soinside.com 2019 - 2024. All rights reserved.