我有一个FragmentActivity,它可以包含用户想要的任意多个ListFragments。ListFragments在HorizontalScrollView中并排排列(在ActionBar中选择一个选项时)。每个ListFragment项都包含一个TextView和一个按钮。单击按钮可更改按钮的ViewParent(包含按钮和TextView的线性布局)的背景色。
现在,单击每个ListFragment中的按钮会更改其相应列表项的背景色,但是在滚动列表项中未单击的按钮时,其背景色也会更改。这种行为是意外的,因为只有被单击的项目需要通过相应的按钮来更改其背景颜色。
ListFragment的数据来自一个自定义SimpleAdapter,它覆盖了getView(int-position、View-convertView、ViewGroup-parent)方法,在该方法中,我将一个setOnClickListener附加到一个按钮,该按钮在单击时更改其ViewParent的背景色。
我在这个问题上花了很多时间,但我无法找到解决办法。有助于理解这种行为的根本原因的解释将非常有用。此外,欢迎提供任何指导,帮助您在单击时设置一个项目的背景色。
下面是扩展SimpleAdapter的自定义适配器MyCustomAdapter的代码:
package com.example.androidlistfragmenttest;
import java.util.List;
import java.util.Map;
import android.content.Context;
import android.graphics.Color;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.SimpleAdapter;
public class MyAdapter extends SimpleAdapter{
Context context;
public MyAdapter(Context context, List<? extends Map<String, ?>> data,
int resource, String[] from, int[] to) {
super(context, data, resource, from, to);
this.context = context;
}
@Override
public boolean areAllItemsEnabled() {
return false;
}
@Override
public boolean isEnabled(int position) {
return false;
}
@Override
public View getView(int position, View convertView, ViewGroup parent){
View view = convertView;
if(view == null){
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.fragment_layout, null);
Button button = (Button) view.findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
Log.v("GOJIRA","ATOMIC BREATH");
// Changes parent view's background color
View parent = (View) v.getParent();
parent.setBackgroundColor(Color.GREEN);
}
});
}
return view;
}
}
和列表片段:
package com.example.androidlistfragmenttest;
import java.util.ArrayList;
import java.util.HashMap;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class MyFragment extends ListFragment {
private ArrayList<HashMap<String,String>> arraylist;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_layout, container, false);
return view;
}
@Override
public void onActivityCreated(Bundle savedInstanceState){
super.onActivityCreated(savedInstanceState);
arraylist = dataGenerator();
MyAdapter adapter = new MyAdapter(getActivity().getApplicationContext(), arraylist, R.layout.fragment_layout,new String[]{"KEY"},new int[]{R.id.text_id});
setListAdapter(adapter);
}
/*
* Method to populate an adapter's data list.
*/
public ArrayList<HashMap<String,String>> dataGenerator(){
HashMap<String,String> hashMap1 = new HashMap<String,String>();
hashMap1.put("KEY", "A");
HashMap<String,String> hashMap2 = new HashMap<String,String>();
hashMap2.put("KEY", "B");
HashMap<String,String> hashMap3 = new HashMap<String,String>();
hashMap3.put("KEY", "C");
HashMap<String,String> hashMap4 = new HashMap<String,String>();
hashMap4.put("KEY", "D");
HashMap<String,String> hashMap5 = new HashMap<String,String>();
hashMap5.put("KEY", "E");
ArrayList<HashMap<String,String>> arraylist = new ArrayList<HashMap<String,String>>();
arraylist.add(hashMap1);
arraylist.add(hashMap2);
arraylist.add(hashMap3);
arraylist.add(hashMap4);
arraylist.add(hashMap5);
return arraylist;
}
}
以及ListActivity:
package com.example.androidlistfragmenttest;
import java.util.Stack;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.app.NavUtils;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
public class MainActivity extends FragmentActivity {
private Stack<String> tagStack;
private Integer last_tag_number;
public MainActivity(){
last_tag_number = new Integer("0");
tagStack = new Stack<String>();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.add_fragment:
addColumn();
return true;
case R.id.remove_column:
removeColumn();
return true;
case android.R.id.home:
// This ID represents the Home or Up button. In the case of this
// activity, the Up button is shown. Use NavUtils to allow users
// to navigate up one level in the application structure. For
// more details, see the Navigation pattern on Android Design:
//
// http://developer.android.com/design/patterns/navigation.html#up-vs-back
//
NavUtils.navigateUpFromSameTask(this);
return true;
}
return super.onOptionsItemSelected(item);
}
/*
* This function adds a column pane to the screen
*
*/
public void addColumn(){
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
MyFragment fragment = new MyFragment();
fragmentTransaction.add(R.id.fragment_activity, fragment,tagGenerator());
fragmentTransaction.commit();
}
/*This function removes a column pane from the screen
*
*
*/
public void removeColumn(){
if(tagStack.size() != 0){
FragmentManager fragmentManager = getSupportFragmentManager();
Fragment fragment = fragmentManager.findFragmentByTag(tagStack.pop());
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.remove(fragment);
fragmentTransaction.commit();
}
}
/*
* This function generates tags for each fragment that is displayed on the screen
* The tags pose as unique identifiers for each fragment
*/
public String tagGenerator(){
Integer tag_number;
if(last_tag_number.intValue() == 0){
tag_number = last_tag_number;
int temp = last_tag_number.intValue();
temp+=1;
last_tag_number = Integer.valueOf(temp);
}
else{
tag_number = new Integer(last_tag_number.intValue());
int temp = last_tag_number.intValue();
temp+=1;
last_tag_number = Integer.valueOf(temp);
}
String tag = tag_number.toString();
tagStack.push(tag);
return tag;
}
}
最后是布局。对于ListFragment:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="300dp"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_weight="1"
android:layout_margin="5dp" >
<ListView android:id="@id/android:list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/label"
android:layout_gravity="start"
/>
<TextView
android:id="@+id/text_id"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="end"
/>
<Button
android:id="@+id/button"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="@string/button"
android:layout_margin="2dp"
android:layout_marginLeft="2dp"
android:layout_marginRight="2dp"
android:clickable="true"
/>
</LinearLayout>
对于碎片活动:
<?xml version="1.0" encoding="utf-8"?>
<HorizontalScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:id="@+id/fragment_activity"
android:layout_width="fill_parent"
android:layout_height = "fill_parent"
android:orientation = "horizontal"
android:gravity="center"
>
</LinearLayout>
</HorizontalScrollView>
我们想更改ListView的项目背景颜色,当单击该行中的按钮时,此时这段代码是有帮助的。
@Override
public View getView(int position, View convertView, ViewGroup parent){
View view = convertView;
final int pos = position;
Button button = (Button) view.findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener(){
Log.d("CLICKED POSITION",Integer.valueOf(pos).toString());
View parent = (View) v.getParent();
parent.setBackgroundColor(Color.GREEN);
}
});
这是ListView
视图重用的常见陷阱。
当您在列表视图
或网格视图
上滚动时,退出屏幕的视图将放置在回收器中。每当需要创建新行时,如果有可用的视图,将使用循环视图。这是为了加快滚动速度,因为从头开始创建视图非常昂贵。然而,如果你不小心,它可能会导致微妙的错误。
如果您更改其中一行的状态(即背景颜色),并且该行被重复使用,它将保持该状态(即绿色背景)。此外,当原始行被重新绘制时,它可能会回收不同的视图,并且它也不会是绿色的。
您需要做的是存储关于哪些行应该和不应该有绿色背景的信息。为此,您可以使用ViewHolder
模式,也可以使用其他方法(例如HashSet
),
然后,您的getView()
方法应该是这样的:
@Override
public View getView(int position, View convertView, ViewGroup parent){
View view = convertView;
if(view == null)
{
<Initialize a new row, same as before>
button.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
<change background color>
<Store that row = position must have a green background>
}
});
}
if <this position should be green>
parent.setBackgroundColor(Color.GREEN);
else
parent.setBackgroundColor(Color.TRANSPARENT); // or whatever the original color was.
return view;
}
回答我的问题。
魔鬼在细节中。convertView是循环使用的视图。重写的getView(int位置、view convertView、ViewGroup父级)的if(view==null)块中的任何代码也将被循环使用。将按钮及其关联的侦听器移出此块将提供对绝对列表项位置的访问,而不是对循环位置的访问。然后可以存储这些位置,并保持相应的列表项背景色/状态。以下是我的自定义适配器的getView方法:
编辑:此解决方案基于@matiash的建议,他也提供了此问题的答案。
@Override
public View getView(int position, View convertView, ViewGroup parent){
//convertView is the recycled view.
View view = convertView;
final int pos = position;
/* Views are recycled within this block.
* Only recycled relative list item positions accessible here.
*/
if(view == null){
final View viewClick = view;
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.fragment_layout, null);
}
/*
* Button moved out of if(view == null) block.
* Views are not recycled here. Absolute list item positions accessible.
* Absolute list positions saved in an ArrayList (coloredItems).
*/
Button button = (Button) view.findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
//This is always a refreshed position and never an absolute list item position.
Log.d("CLICKED POSITION",Integer.valueOf(pos).toString());
View parent = (View) v.getParent();
parent.setBackgroundColor(Color.GREEN);
coloredItems.add(Integer.valueOf(pos));
}
});
/*
* This ensures that only list item positions saved
* in the ArrayList 'coloredItems' have a green background.
* All other list items have a transparent background.
*/
if(coloredItems.contains(Integer.valueOf(position)))
view.setBackgroundColor(Color.GREEN);
else
view.setBackgroundColor(Color.TRANSPARENT);
return view;
}
这是我的listview点击事件: 这是我的按钮点击事件: 现在,我需要获得单击的listview项的位置。我已经声明了全局位置,但这总是给我位置1。 有人能告诉我怎么得到这个职位吗?
我有一个列表视图。我想为listView项设置边框,所以我使用“Shape”XML。 shape_panel_drawable.xml文件 谢谢!
我想知道如何选择listview first item select并通过单击按钮自动单击。 使用下面的代码,我可以选择第一行,但无法选择。 这是我的listview点击事件: 非常感谢您的帮助!如果有人想了解更多信息,请务必告诉我,以便我更新我的问题。
我有一个带有自定义适配器的listview。listview中唯一的项目是TextView(目前)。当我点击文本视图时,背景颜色应变为蓝色,当我再次点击时,背景颜色应变为默认颜色(浅灰色)。我尝试使用ViewHolder模式来实现这一点。 现在的问题是,当我点击列表中的第一个项目时,一些随机项目的背景颜色会变成蓝色。 CustomAdapter类: 持证人类别: 如果您需要任何其他代码,请告诉我。
本文向大家介绍Android实现为ListView同时设置点击时的背景和点击松手之后的背景,包括了Android实现为ListView同时设置点击时的背景和点击松手之后的背景的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了Android实现为ListView同时设置点击时的背景和点击松手之后的背景。分享给大家供大家参考。具体分析如下: 这里要达到的效果是, (1)点击ListView的it
如何处理ListView中的每个按钮单击?活动课 如何管理ListView中每个项目的按钮单击?我尝试了许多方法…如何解决此问题?请任何人帮帮我...