如何在主要活动中使用按钮 onclicklistener 进行回收视图项目

Posted

技术标签:

【中文标题】如何在主要活动中使用按钮 onclicklistener 进行回收视图项目【英文标题】:How to use button onclicklistener for recycleview item inside main activity 【发布时间】:2019-07-25 00:41:03 【问题描述】:

我在使用 android 应用程序时遇到了这个问题:我有一个 recycleview,每个项目都有一个删除按钮。我知道我可以在适配器的onBindViewHolder 内添加每个行项目的按钮onclicklistener,但我希望它专门用于 MainActivity 内部,而不是适配器。这是我的 recycleview 的简要草图:

sketch

这是我的适配器的代码:

public class EntryAdapter extends RecyclerView.Adapter<EntryAdapter.MyViewHolder> 

    private Context context;
    private CRUD db;
    private List<Entry> entryList;

    public class MyViewHolder extends RecyclerView.ViewHolder 

        ImageView type;
        ImageView person;
        TextView amount;
        TextView amount_ron;
        ImageButton deleteB, editB, payB;
        TextView description;
        TextView timestamp;
        TextView positionTxt, noHolderPositionTxt;
        LinearLayout containter;
        Typeface SR, SB, SL;

        MyViewHolder(View view) 
            super(view);

            this.SB = Typeface.createFromAsset(context.getAssets(), "fonts/sansation_bold.ttf");
            this.SR = Typeface.createFromAsset(context.getAssets(), "fonts/sansation_regular.ttf");
            this.SL = Typeface.createFromAsset(context.getAssets(), "fonts/sansation_light.ttf");
            containter = view.findViewById(R.id.item_container);
            type = view.findViewById(R.id.debt_type);
            person = view.findViewById(R.id.debt_person);
            amount = view.findViewById(R.id.entry_cost);
            amount.setTypeface(SR);
            amount_ron = view.findViewById(R.id.entry_cost_ron);
            amount_ron.setTypeface(SR);
            deleteB = view.findViewById(R.id.delete_button);
            editB = view.findViewById(R.id.edit_button);
            payB = view.findViewById(R.id.pay_button);
            description = view.findViewById(R.id.descriptionTxt);
            description.setTypeface(SL);
            timestamp = view.findViewById(R.id.timestamp);
            timestamp.setTypeface(SR);
            positionTxt = view.findViewById(R.id.position);
            noHolderPositionTxt = view.findViewById(R.id.positionnotwithholder);

            db = new CRUD(context);
        
    

    public EntryAdapter(Context context, List<Entry> entryList) 
        this.context = context;
        this.entryList = entryList;
    

    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) 
        View itemView = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.item_entry, parent, false);
        return new MyViewHolder(itemView);
    

    @Override
    public void onBindViewHolder(@NonNull final MyViewHolder holder, final int position) 

        Entry entry = entryList.get(holder.getAdapterPosition());
        holder.positionTxt.setText(String.valueOf(holder.getAdapterPosition()));
        holder.noHolderPositionTxt.setText(String.valueOf(position));

        switch(entry.getType())
            case "FOOD": holder.type.setImageResource(R.drawable.food);
                break;
            case "FLOWERS": holder.type.setImageResource(R.drawable.flowers);
                break;
            case "GROCERIES": holder.type.setImageResource(R.drawable.groceries);
                break;
            case "HOLIDAY": holder.type.setImageResource(R.drawable.holiday);
                break;
            case "PHARMACY": holder.type.setImageResource(R.drawable.pharmacy);
                break;
            case "BILLS": holder.type.setImageResource(R.drawable.bills);
                break;
            case "CLOTHES": holder.type.setImageResource(R.drawable.clothes);
                break;
            case "TRANSPORT": holder.type.setImageResource(R.drawable.transport);
                break;
            case "ITEMS": holder.type.setImageResource(R.drawable.items);
                break;
            case "OTHERS": holder.type.setImageResource(R.drawable.others);
                break;
        
        switch (entry.getPerson())
            case "ew": holder.person.setImageResource(R.drawable.crisu_to_radu_small);
                break;
            case "wr": holder.person.setImageResource(R.drawable.radu_to_crisu_big);
                break;
        
        switch (entry.getIsPaid())
            case "YES": holder.containter.setAlpha((float) 0.3);
                        holder.payB.setVisibility(View.GONE);
                        holder.deleteB.setVisibility(View.GONE);
                        holder.editB.setVisibility(View.GONE);
                break;
            case "NO":  holder.containter.setAlpha((float) 1);
                        holder.payB.setVisibility(View.VISIBLE);
                        holder.deleteB.setVisibility(View.VISIBLE);
                        holder.editB.setVisibility(View.VISIBLE);
                break;
        
        holder.amount.setText(entry.getAmount());
        holder.description.setText(entry.getDescription());
        holder.timestamp.setText(formatDate(entry.getTimestamp()));
//                deleteEntry(holder.getAdapterPosition());
    

    @Override
    public int getItemCount() 
        return entryList.size();
    

    private void deleteEntry(int position) 
        db.deleteEntry(entryList.get(position));
        entryList.remove(position);
        notifyItemRemoved(position);
        notifyDataSetChanged();
        notifyItemRangeChanged(position, entryList.size());
    

    private String formatDate(String dateStr) 
        try 
            @SuppressLint("SimpleDateFormat") SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date date = fmt.parse(dateStr);
            @SuppressLint("SimpleDateFormat") SimpleDateFormat fmtOut = new SimpleDateFormat("MMM d, HH:mm");
            return fmtOut.format(date);
         catch (ParseException ignored) 

        return "";
    

这是我的 MainActivity:

@Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        fonts();


        recyclerView = findViewById(R.id.recycler_view);
        no_entry_message = findViewById(R.id.no_entry_message);
        no_entry_message.setTypeface(SL);
        title = findViewById(R.id.finance_title);
        title.setTypeface(SB);
        subtitle = findViewById(R.id.finance_subtitle);
        subtitle.setTypeface(SL);
        card_title = findViewById(R.id.total_title);
        card_title.setTypeface(SR);
        money_amount = findViewById(R.id.total_money);
        money_amount.setTypeface(SB);
        money_rom = findViewById(R.id.total_ron);
        money_rom.setTypeface(SB);
        total_calculation = findViewById(R.id.total_button);
        total_calculation.setTypeface(SR);
        total_container = findViewById(R.id.total_card_container);

        db = new CRUD(this);
        entryList.addAll(db.getAllEntries());

        fab = findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View view) 
                isUpdateDilog = false;
                addEntryDialog(null, -1);
            
        );

        mAdapter = new EntryAdapter(this, entryList);
        RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext());
        recyclerView.setLayoutManager(mLayoutManager);
        recyclerView.setItemAnimator(new DefaultItemAnimator());
        recyclerView.setAdapter(mAdapter);
        emptyList();
    
//    private void deleteEntry(int position) 
//
//        db.deleteEntry(entryList.get(position));
//        entryList.remove(position);
//        mAdapter.notifyItemRemoved(position);
//        emptyList();
//    

所以基本上,每次我点击 recyclerview 项目内的删除按钮时,我都希望在 MainActivity 中发生 onclick 事件并使用方法 deleteEntry(position) 以便我可以从本地 sqlite 数据库中删除特定项目。

另外,如果我想在我的适配器的 onBindViewHolder 中添加一个条件,我该如何更改(例如)来自 MainActivity 的 textview 的颜色?

更新 - H.sanati 的回答

再次感谢您的回答,H.sanati。这是我所做的全部更改:

创建了这个界面

public interface OnClickListener 
    void onClick(int position, String button_pressed);

整数位置将我的项目位置存储在列表中,字符串将告诉我按下了 3 个按钮中的哪一个。

然后在我的Recyclview Adapter中:

@Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) 
        View itemView = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.item_entry, parent, false);

        final MyViewHolder holder = new MyViewHolder(itemView);
        holder.deleteB.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View v) 
                ((MainActivity)context).onClick(holder.getAdapterPosition(), "DELETE_B");
            
        );

        holder.editB.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View v) 
                ((MainActivity)context).onClick(holder.getAdapterPosition(), "EDIT_B");
            
        );

        holder.payB.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View v) 
                ((MainActivity)context).onClick(holder.getAdapterPosition(), "PAY_B");
            
        );

        return holder;
    

请注意,deleteB、editB 和 payB 都是出现在每个列表项中的按钮。上面界面中的字符串告诉你按下了哪一个。

然后在我的MainActivity中:

public class MainActivity extends AppCompatActivity implements OnClickListener 
@Override
    public void onClick(int item_position, String which_button_was_pressed) 
        switch (which_button_was_pressed)
        
            case "DELETE_B":
                deleteEntry(item_position);
                Toast.makeText(this, "Delete button at position:" + item_position + "was pressed", Toast.LENGTH_SHORT).show();
                    break;
            case "EDIT_B":
                Toast.makeText(this, "Edit button at position:" + item_position + "was pressed", Toast.LENGTH_SHORT).show();
                break;
            case "PAY_B":
                Toast.makeText(this, "Pay button at position:" + item_position + "was pressed", Toast.LENGTH_SHORT).show();
                break;
        

    

这里有一个 Toast 按摩,以确认按下了正确的按钮,接下来,我将为每种情况添加我的方法。另外我建议在 MainActivity 的方法中(比如说 delete 方法,您可以查看它),您应该添加以下标有 @@@ 的行,以获得准确的列表大小和位置更新:

 private void deleteEntry(int position) 

            db.deleteEntry(entryList.get(position));
            entryList.remove(position);
      @@@   mAdapter.notifyItemRemoved(position);
      @@@   mAdapter.notifyDataSetChanged();
      @@@   mAdapter.notifyItemRangeChanged(position, entryList.size());
            emptyList();
        

希望这会有所帮助。谢谢!

【问题讨论】:

RecyclerView onClick的可能重复 【参考方案1】:

首先,创建一个接口:

public interface OnClickListener 
    void onClick();

然后在你的活动中实现这个接口:

class MainActivity extends AppCompatActivity implements OnClickListener 
    @Override
    public void onClick() 
        //code
    

在 onClick 方法中做任何你想做的事,然后在你的 recyclerview 中调用它:

((MainActivity)context).onClick();

最好在onCreateViewHolder 中设置您的听众,以便在 recyclerview 中平滑滚动,如下所示:

 @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) 
        View view = LayoutInflater.from(context).inflate(R.layout.item_entry, parent, false);

        MyViewHolder holder = new MyViewHolder(view);

        holder.itemView.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View v) 
                ((MainActivity)context).onClick();
            
        );

        return holder;
    

【讨论】:

非常感谢,我对接口和回收视图有点陌生,这很有帮助! 很高兴它对您有所帮助。 @RFM

以上是关于如何在主要活动中使用按钮 onclicklistener 进行回收视图项目的主要内容,如果未能解决你的问题,请参考以下文章

离开活动并返回时保持设置按钮颜色

如何知道哪个按钮调用了某个活动?

如何从适配器刷新主要活动中的视图?

如何从片段返回主要活动

onActivityResult 方法调用按钮单击[重复]

带有 2 个按钮的 Android 主要活动可在 webview 中打开第二个活动