2012-05-12 71 views
1

我在我的活动和每行Im有一个ListView使用我的自定义布局与TextView和两个按钮。当我点击这两个按钮中的任何一个时,我想要执行某个动作。在我的ArrayAdapter中,在getView方法中,我将onClickListeners设置为这两个按钮。Android ListView自定义布局

public View getView(int position, View convertView, ViewGroup parent) { 

    View v = convertView; 
    if (v == null) { 
     v = li.inflate(R.layout.process_row, null); 
    } 


    final Button processCheck = (Button) v.findViewById(R.id.processCheck); 
    processCheck.setOnClickListener(new View.OnClickListener() { 

     @Override 
     public void onClick(View v) { 
      if (process.isChecked() == false) { 
       process.setChecked(true); 
       processCheck.setBackgroundColor(Color.BLUE); 
      } 
      else { 
       process.setChecked(false); 
       processCheck.setBackgroundColor(Color.RED); 
      } 

     } 
    }); 

    return v; 
} 

ArrayList保存mz自定义类的对象进程和进程在代码中是这个类的一个实例。所以,现在当我在其中一个ListView行中单击这个按钮时,我希望改变给定Process实例中的布尔变量并更改按钮的颜色。发生这种情况,但不仅仅是这一行,还有3-4次。所以点击后,我有5个改变的按钮,而不是一个。你知道我在这里做错了什么吗?请注意,我不太了解ListActivity编码,大部分代码实际上是从示例文件中复制和编辑的。谢谢!

编辑:

该问题可能只与布局的地方。当我点击按钮时,它们中的更多颜色会改变,但只有我单击的过程的布尔值发生了变化。

+0

http:// w ww.android-ios-tutorials.com/770/create-custom-listview-in-android/ – Houcine

回答

0

编辑:找一个 “开箱即用” 的帖子的末尾例子!

因为你看到多行受到影响我猜它有些事情要做系统如何回收资源,也许对Button的引用是不明确的。

我不确定我在哪里选择了这种做法(Android教程或我们以前的开发人员通过这些教程学习了Android)。然而,建议是使用一个嵌套类ViewHolder

private static class ViewHolder { 

    public Button processCheck; 
} 

将此放在适配器或任何类的getView()在声明并修改它是这样:

public View getView(int position, View convertView, ViewGroup parent) { 

    View v = convertView; 
    $ViewHolder viewHolder; //wait for the magic! 
    if (v == null) { 
     v = li.inflate(R.layout.process_row, null); 
     $viewHolder = new ViewHolder(); 
     $viewHolder.processCheck = (Button) v.findViewById(R.id.processCheck); 
     $v.setTag(viewHolder); 
     //ok we somewhat stuffed an object with the Button into our View... so what? 
    } 

    $viewHolder = (ViewHolder) v.getTag(); 
    //see explanation below 

    $viewHolder.processCheck.setOnClickListener(new View.OnClickListener() { 
    //set the onClickListener for this and only this button. 
     @Override 
     public void onClick(View v) { 
      if (process.isChecked() == false) { 
       process.setChecked(true); 
       processCheck.setBackgroundColor(Color.BLUE); 
      } 
      else { 
       process.setChecked(false); 
       processCheck.setBackgroundColor(Color.RED); 
      } 

     } 
    }); 

    return v; 
} 

(我打上$变化。我认为这样他们应该很容易发现,如果我使用eclipse。否则查找+替换^^)

因此​​将返回一个与调用的视图关联的对象。对象是如此令人难以置信的泛型,您可以将其称为您创建的ViewHolder对象。因此,您可以引用按钮并将其存储在对象中。
现在,无论何时获得ListView,都可以检索对象并设置新鲜和新鲜的OnclickListener。这样你只有一个Listener被调用。

请注意,您不必再次致电v.setTag();来“保存”您的更改。

一个陷阱可能是如果你疯狂的东西,像在同一个列表中膨胀不同的布局,有什么理由。你也许会不同ViewHandlers分配给他们,如:

if (v == null) { 
    if(someCriteria) { 
     v = li.inflate(R.layout.process_row, null); 
     viewHolder = new ViewHolder(); 
    } 
     v = li.inflate(R.layout.process_another_row, null); 
     viewHolder = new AnotherViewHolder(); 
} 

随后的getView()一个ViewHolder或其他未经检查的通话可能会在运行时抛出一个错误!

+0

我急于尝试这个,但在onClickListener我得到“无法解决”为processCheck。我想可能应该有viewHolder。过程检查,而是当我这样做时,我得到“不能引用非最终变量viewHolder”。所以我改变了实例wHolder是最终的,但我在v.getTag()行得到“可能已被分配”。它可能只是一个愚蠢的问题,但我不能看到它... –

+0

我会深入研究它:)给我一些分钟虽然=) – yoshi

+0

还有一件事,我不得不声明ViewHandler只是作为一个类,而不是私有的静态的。它只会允许公共抽象和最终:) –

0

问题是在这里

View v = convertView; 
    if (v == null) { 
     v = li.inflate(R.layout.process_row, null); 
    } 

这是因为只有创造了可见的项目视图V,然后它再利用。所以只要删除IFV == NULL),所以你的代码会

public View getView(int position, View convertView, ViewGroup parent) { 

    View v = convertView; 

     v = li.inflate(R.layout.process_row, null); 



    final Button processCheck = (Button) v.findViewById(R.id.processCheck); 
    processCheck.setOnClickListener(new View.OnClickListener() { 

     @Override 
     public void onClick(View v) { 
      if (process.isChecked() == false) { 
       process.setChecked(true); 
       processCheck.setBackgroundColor(Color.BLUE); 
      } 
      else { 
       process.setChecked(false); 
       processCheck.setBackgroundColor(Color.RED); 
      } 

     } 
    }); 

    return v; 
} 
+0

这样做:)只有一个按钮改变它的颜色,但现在当我点击它,看到它改变,比向下滚动向上再次,它的颜色和之前的点击一样:) –

+0

每当列表呈现时,都会调用getView。所以你应该加入你的gerview – vandzi

+0

我想知道当你通过一个列表快速滚动时这将如何执行。充气所有这些布局会让机器人哭泣,而不是?:C – yoshi

0

getView被称为每当列表呈现时间。所以,你应该加入到设置颜色的gerview条件:公共查看getView(INT位置,查看convertView,ViewGroup以及母公司){

View v = convertView; 

    v = li.inflate(R.layout.process_row, null); 

//添加这些行娄

如果(process.isChecked() == FALSE){

 processCheck.setBackgroundColor(Color.BLUE); 
    } 
    else { 

     processCheck.setBackgroundColor(Color.RED); 
    } 

final Button processCheck = (Button) v.findViewById(R.id.processCheck); 
processCheck.setOnClickListener(new View.OnClickListener() { 

    @Override 
    public void onClick(View v) { 
     if (process.isChecked() == false) { 
      process.setChecked(true); 
      processCheck.setBackgroundColor(Color.BLUE); 
     } 
     else { 
      process.setChecked(false); 
      processCheck.setBackgroundColor(Color.RED); 
     } 

    } 
}); 

return v; 

}

+0

我编辑了代码。所有的按钮现在都是蓝色的,应该是bu,当我按下按钮时,它会变红,但是在向下滚动之后,我不能再看到它,并且再次返回,它又变为蓝色: –

+0

我写错了。像这样:final Button processCheck =(Button)v.findViewById(R.id.processCheck); if(process.isChecked()== false)processCheck.setBackgroundColor(Color.BLUE); } } else { processCheck.setBackgroundColor(Color.RED); } – vandzi

+0

我想过程是你的适配器 – vandzi

0

这是我如何解决它:

在我的适配器,我创建的类:

private static class ViewHolder { 
    public Button  processCheck; 
    public Process  process; 
    public TextView  name; 
} 

比我创建了一个自定义的监听我的按钮:

private class CustomListener implements View.OnClickListener { 

    public ViewHolder viewHolder; 

    public CustomListener(ViewHolder holder) { 
     this.viewHolder = holder; 
    } 

    @Override 
    public void onClick(View v) { 
     if (viewHolder.process.isChecked()) { 
      viewHolder.name.setText("not checked"); 
      viewHolder.process.setChecked(false);    
     } 
     else { 
      viewHolder.name.setText("checked"); 
      viewHolder.process.setChecked(true);     
     }   
    } 
} 

而且我getView功能:

public View getView(int position, View convertView, ViewGroup parent) { 
    ViewHolder viewHolder; 

    if (convertView == null) { 
     convertView = mInflater.inflate(R.layout.process_row, null); 

     viewHolder = new ViewHolder(); 
     viewHolder.processCheck = (Button) convertView.findViewById(R.id.processCheck); 
     viewHolder.name = (TextView) convertView.findViewById(R.id.processName);    
     convertView.setTag(viewHolder); 
    } 


    viewHolder = (ViewHolder) convertView.getTag(); 
    viewHolder.process = list.get(position); 

    if (viewHolder.process.isChecked()) { 
     viewHolder.name.setText("checked");   
    } 
    else { 
     viewHolder.name.setText("not checked");   
    }  

    CustomListener listener = new CustomListener(viewHolder); 
    viewHolder.processCheck.setOnClickListener(listener); 

    return convertView; 
} 
+0

问题是在getView中的if-else条件。添加它们并正确执行后,代码工作。再次感谢,家伙:) –