为 ListView 的多行中的多个 TextView 设置 onClickListener

Posted

技术标签:

【中文标题】为 ListView 的多行中的多个 TextView 设置 onClickListener【英文标题】:Set onClickListener for multiple TextView's in multiple rows of a ListView 【发布时间】:2015-02-09 09:11:35 【问题描述】:

我从ArrayList<ArrayList<String>> 中设置了一个ListView,称为data of data,看起来像这样

data = "cat1","cat2","cat3","cat4",
                      "dog1","dog2","dog3",
                      "lion1",
                      "monkey1","monkey2";

我是这样设置的:

public static final String[] weekdayStringArray = "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday";

@Override
    public View getView(int position, View convertView, ViewGroup parent) 
         ArrayList<String> stringArrayList = data.get(position);
         String dayString = weekdayStringArray[dayNumber];

         switch(stringArrayList.size())
            case 4:
                convertView = mLayoutInflater.inflate(R.layout.four_meal_item_view, parent, false);
                TextView mealOne_Four = (TextView) convertView.findViewById(R.id.firstMealTextView);
                TextView mealTwo_Four = (TextView) convertView.findViewById(R.id.secondMealTextView);
                TextView mealThree_Four = (TextView) convertView.findViewById(R.id.thirdMealTextView);
                TextView mealFour_Four = (TextView) convertView.findViewById(R.id.fourthMealTextView);
                TextView dayText_Four = (TextView) convertView.findViewById(R.id.dayTextView);
                dayText_Four.setText(dayString);
                mealOne_Four.setText(stringArrayList.get(0).substring(0,1).toUpperCase() + stringArrayList.get(0).substring(1).toLowerCase());
                mealTwo_Four.setText(stringArrayList.get(1).substring(0,1).toUpperCase() + stringArrayList.get(1).substring(1).toLowerCase());
                mealThree_Four.setText(stringArrayList.get(2).substring(0,1).toUpperCase() + stringArrayList.get(2).substring(1).toLowerCase());
                mealFour_Four.setText(stringArrayList.get(3).substring(0,1).toUpperCase() + stringArrayList.get(3).substring(1).toLowerCase());
                break;
            case 3:
                convertView = mLayoutInflater.inflate(R.layout.three_meal_item_view, parent, false);
                TextView mealOne_Three = (TextView) convertView.findViewById(R.id.firstMealTextView_Three);
                TextView mealTwo_Three = (TextView) convertView.findViewById(R.id.secondMealTextView_Three);
                TextView mealThree_Three = (TextView) convertView.findViewById(R.id.thirdMealTextView_Three);
                TextView dayText_Three = (TextView) convertView.findViewById(R.id.dayTextView_Three);
                dayText_Three.setText(dayString);
                mealOne_Three.setText(stringArrayList.get(0).substring(0,1).toUpperCase() + stringArrayList.get(0).substring(1).toLowerCase());
                mealTwo_Three.setText(stringArrayList.get(1).substring(0,1).toUpperCase() + stringArrayList.get(1).substring(1).toLowerCase());
                mealThree_Three.setText(stringArrayList.get(2).substring(0,1).toUpperCase() + stringArrayList.get(2).substring(1).toLowerCase());
                break;
            case 2:
                convertView = mLayoutInflater.inflate(R.layout.two_meal_item_view, parent, false);
                TextView mealOne_Two = (TextView) convertView.findViewById(R.id.firstMealTextView_Two);
                TextView mealTwo_Two = (TextView) convertView.findViewById(R.id.secondMealTextView_Two);
                TextView dayText_Two = (TextView) convertView.findViewById(R.id.dayTextView_Two);
                dayText_Two.setText(dayString);
                mealOne_Two.setText(stringArrayList.get(0).substring(0,1).toUpperCase() + stringArrayList.get(0).substring(1).toLowerCase());
                mealTwo_Two.setText(stringArrayList.get(1).substring(0,1).toUpperCase() + stringArrayList.get(1).substring(1).toLowerCase());
                break;
            case 1:
                convertView = mLayoutInflater.inflate(R.layout.one_meal_item_view, parent, false);
                TextView mealOne_One = (TextView) convertView.findViewById(R.id.firstMealTextView_One);
                TextView dayText_One = (TextView) convertView.findViewById(R.id.dayTextView_One);
                dayText_One.setText(dayString);
                mealOne_One.setText(stringArrayList.get(0).substring(0,1).toUpperCase() + stringArrayList.get(0).substring(1).toLowerCase());
                break;
            case 0:
                convertView = mLayoutInflater.inflate(R.layout.zero_meal_item_view, parent, false);
                TextView dayText_Zero = (TextView) convertView.findViewById(R.id.dayTextView_Zero);
                dayText_Zero.setText(dayString + "(Closed)");
                break;
         
return convertView;

现在我想添加一个onClickListener,这样我就可以连续点击一个TextView。当单击此TextView 时,我将移动到一个新的Activity,传递单击的TextView 的文本以及与单​​击的TextView 位于同一行的dayTextView 的文本。

现在我不想为每个TextView 设置一堆onClickListners 那么对于我的行中的所有TextViews 执行此操作的有效方法是什么? ListView?

【问题讨论】:

【参考方案1】:

选项 1:

在每个 textView 的 xml 中将 onClick 设置为相同的方法

android:onClick= "itemtapped"

然后在您的活动中调用被点击的项目并让它获取文本视图名称和位置编号,以便您知道哪个被点击了。

选项 2:

在 Activity 中创建一个自定义函数来获取被点击的项目

类似的东西

       public void setOnClickListener(TextView... arrayOfView, int position)

     TextView[] ]textViewArray = textViewArray;

    for(int i = 0 ; i < textViewArray.length ; ++i)

        int index = i; 
        textViewArray[i].setOnClickListener(new OnClickListener()

                @Override
                public void onClick(View v)
                     Intent intent = new Intent(MainActivity.this, YourTargetActivity.class);
                     startActivity(intent);
                     int textViewNumber = position;

                
        );
    

然后传入位置,以便您知道它是什么以及该行中的 textview

快乐编码:)

【讨论】:

【参考方案2】:

您可以在您的 convertView 中查找 TextView 实例的任何子项。该方法使用广度优先搜索算法来搜索 TextView 实例。

private void setOnClickListenerOnTextViews(View contentViev, OnClickListener listener) 
            ArrayList<View> unvisited = new ArrayList<View>();
            unvisited.add(contentView);
            while (!unvisited.isEmpty()) 
                View child = unvisited.remove(0);
                if(child instanceof TextView) 
                    child.setOnClickListener(listener);
                    continue;
                
                if (!(child instanceof ViewGroup))
                    continue;
                
                ViewGroup group = (ViewGroup) child;
                final int childCount = group.getChildCount();
                for (int i=0; i< childCount; i++)
                    unvisited.add(group.getChildAt(i));
                
            
           

在您的 getView() 方法中调用此方法:

public View getView(.....)
//...
setOnClickListenerOnTextViews(convertView,mClickListener)
return convertView;

编辑:为了复制和粘贴解决方案,mClickListener 是您代码中某处的侦听器实例:

private View.OnClickListener mClickListener = new View.OnclickListerner()
 @Override
 public void onClick(View v)
   //do your thing here.
 
;

【讨论】:

我收到编译错误cannot resolve mClickListener 我在哪里设置它? 为什么人们总是选择复制粘贴解决方案? mClickListener 是在你的代码中实例化某处的接口实例。 我不知道你的意思,你能解释一下【参考方案3】:

最有效的方法是为每个TextView 手动设置点击监听器。为什么?因为您已经找到了它们(findViewById),所以再次遍历视图树真的很糟糕(Breadth First Search)。所以你所能做的就是创建一个函数,然后将你的TextViews 传递给它。不过,您可以进行一些重构以获得干净的代码。

       public void addClickListenerToTextView(TextView... textViewArray)

        final TextView[] finalTextViewArray = textViewArray;

        for(int i = 0 ; i < finalTextViewArray.length-1 ; ++i)

            final int index = i; 
            textViewArray[i].setOnClickListener(new OnClickListener()

                    @Override
                    public void onClick(View v)
                         Intent intent = new Intent(MainActivity.this, YourTargetActivity.class);
                         intent.putExtra("meal" + index ,finalTextViewArray[index].getText().toString());
                         intent.putExtra("dayText" , finalTextViewArray[finalTextViewArray.length-1].getText().toString());
                         startActivity(intent);

                    
            );
        
    

那么你可以像这样调用这个函数:

 addClickListenerToTextView(mealOne_Three,mealTwo_Three,mealThree_Three,dayText_Three);

因此,在每次中断之前,使用该行的所有文本视图调用上述函数。请注意,您必须始终将 day textview 作为最后一个 textview 传递。

【讨论】:

【参考方案4】:

您可以执行类似通用OnClickListener 之类的操作,其中包含新Activity 所需的所有信息:

public static final String[] weekdayStringArray = DateFormatSymbols.getInstance().getWeekdays();

@Override
public View getView(int position, View convertView, ViewGroup parent) 
    ArrayList<String> stringArrayList = getItem(position);
    String dayString = weekdayStringArray[dayNumber];

    MyClickListener myClicker = new MyClickListener(dayString);

    switch (stringArrayList.size()) 
    case 4:
        convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.four_meal_item_view, parent, false);
        TextView mealOne_Four = (TextView) convertView.findViewById(R.id.firstMealTextView);
        TextView mealTwo_Four = (TextView) convertView.findViewById(R.id.secondMealTextView);
        TextView mealThree_Four = (TextView) convertView.findViewById(R.id.thirdMealTextView);
        TextView mealFour_Four = (TextView) convertView.findViewById(R.id.fourthMealTextView);
        TextView dayText_Four = (TextView) convertView.findViewById(R.id.dayTextView);
        dayText_Four.setText(dayString);
        mealOne_Four.setText(stringArrayList.get(0).substring(0, 1).toUpperCase() + stringArrayList.get(0).substring(1).toLowerCase());
        mealTwo_Four.setText(stringArrayList.get(1).substring(0, 1).toUpperCase() + stringArrayList.get(1).substring(1).toLowerCase());
        mealThree_Four
                .setText(stringArrayList.get(2).substring(0, 1).toUpperCase() + stringArrayList.get(2).substring(1).toLowerCase());
        mealFour_Four.setText(stringArrayList.get(3).substring(0, 1).toUpperCase() + stringArrayList.get(3).substring(1).toLowerCase());
        applyClickListeners(myClicker, mealOne_Four, mealTwo_Four, mealThree_Four, mealFour_Four, dayText_Four);
        break;
    case 3:
        convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.three_meal_item_view, parent, false);
        TextView mealOne_Three = (TextView) convertView.findViewById(R.id.firstMealTextView_Three);
        TextView mealTwo_Three = (TextView) convertView.findViewById(R.id.secondMealTextView_Three);
        TextView mealThree_Three = (TextView) convertView.findViewById(R.id.thirdMealTextView_Three);
        TextView dayText_Three = (TextView) convertView.findViewById(R.id.dayTextView_Three);
        dayText_Three.setText(dayString);
        mealOne_Three.setText(stringArrayList.get(0).substring(0, 1).toUpperCase() + stringArrayList.get(0).substring(1).toLowerCase());
        mealTwo_Three.setText(stringArrayList.get(1).substring(0, 1).toUpperCase() + stringArrayList.get(1).substring(1).toLowerCase());
        mealThree_Three.setText(stringArrayList.get(2).substring(0, 1).toUpperCase()
                + stringArrayList.get(2).substring(1).toLowerCase());
        applyClickListeners(myClicker, mealOne_Three, mealTwo_Three, mealThree_Three, dayText_Three);
        break;
    case 2:
        convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.two_meal_item_view, parent, false);
        TextView mealOne_Two = (TextView) convertView.findViewById(R.id.firstMealTextView_Two);
        TextView mealTwo_Two = (TextView) convertView.findViewById(R.id.secondMealTextView_Two);
        TextView dayText_Two = (TextView) convertView.findViewById(R.id.dayTextView_Two);
        dayText_Two.setText(dayString);
        mealOne_Two.setText(stringArrayList.get(0).substring(0, 1).toUpperCase() + stringArrayList.get(0).substring(1).toLowerCase());
        mealTwo_Two.setText(stringArrayList.get(1).substring(0, 1).toUpperCase() + stringArrayList.get(1).substring(1).toLowerCase());
        applyClickListeners(myClicker, mealOne_Two, mealTwo_Two, dayText_Two);
        break;
    case 1:
        convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.one_meal_item_view, parent, false);
        TextView mealOne_One = (TextView) convertView.findViewById(R.id.firstMealTextView_One);
        TextView dayText_One = (TextView) convertView.findViewById(R.id.dayTextView_One);
        dayText_One.setText(dayString);
        mealOne_One.setText(stringArrayList.get(0).substring(0, 1).toUpperCase() + stringArrayList.get(0).substring(1).toLowerCase());
        applyClickListeners(myClicker, mealOne_One, dayText_One);
        break;
    case 0:
        convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.zero_meal_item_view, parent, false);
        TextView dayText_Zero = (TextView) convertView.findViewById(R.id.dayTextView_Zero);
        dayText_Zero.setText(dayString + "(Closed)");
        applyClickListeners(myClicker, dayText_Zero);
        break;
    
    return convertView;


private void applyClickListeners(MyClickListener clicker, View... toApply) 
    for (View view : toApply) 
        view.setOnClickListener(clicker);
    


class MyClickListener implements View.OnClickListener 

    private String dayText;

    public MyClickListener(String dayText) 
        this.dayText = dayText;
    

    @Override
    public void onClick(View v) 
        // do your thing
    


【讨论】:

【参考方案5】:

在您的 Activity 上实现侦听器,然后将 Activity 作为侦听器传递给每个可点击项。这样您只需要创建一个侦听器,它不会泄漏内存,并且如果您必须更改项目的显示方式,您不必更改每个侦听器。

    在适配器中创建一个 SoftReference 以安全地存储活动 将活动作为侦听器传递给每个文本视图 在活动中实现 View.OnClickListener 将传递回的视图转换为 TextView 创建新意图 获取文本,将其附加到意图 开始新活动

【讨论】:

以上是关于为 ListView 的多行中的多个 TextView 设置 onClickListener的主要内容,如果未能解决你的问题,请参考以下文章

具有多行文本的 Scrollview 中的 Listview

动态给listview的item添加样式?

ListView 包含一个多行文本字段,后跟 Flutter 中的 ListTiles

将多行中的多个文本字段分组为一列[重复]

如何将单个工作表中的多行(在 excel 中)转换为多个 CSV 文件

MatrixCursor 的问题