【发布时间】:2015-08-04 15:30:51
【问题描述】:
我想显示一个标题为复选框的列表(本例中为行星),当我单击其中一个复选框(本例中为 Toast 和 Log)时会发生一些事情。但是,要显示复选框,我需要使用自定义适配器(当我使用 SimpleAdapter 时一切正常),但 OnItemClickListener 不再起作用。复选框选中/取消选中很好,但我无法让 DialogFragment 确认已单击任何内容。
还有一个搜索栏,它会在您键入时动态过滤列表,但我认为这不会产生影响,因为它与 SimpleAdapter 配合得很好。
这里有一些有趣的代码:
MainActivity.java
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity;
public class MainActivity extends FragmentActivity
{
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DialogFragment fragment = SearchDialogFragment.newInstance();
fragment.show(getSupportFragmentManager(), "SearchDialog");
}
}
SearchDialogFragment.java
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.SearchView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class SearchDialogFragment extends DialogFragment
{
private List<Map<String, Boolean>> planetsList;
private ListView listView;
private List<String> selectedPlanets;
public static SearchDialogFragment newInstance()
{
return new SearchDialogFragment();
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState)
{
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = getActivity().getLayoutInflater();
View view = inflater.inflate(R.layout.fragment_search_dialog, null);
builder.setTitle("List of planets");
builder.setView(view);
listView = (ListView) view.findViewById(R.id.fragment_list_view);
selectedPlanets = new ArrayList<>();
createPlanetsList("");
resetAdapter();
/**
* NOT WORKING
*/
listView.setOnItemClickListener(new AdapterView.OnItemClickListener()
{
public void onItemClick(AdapterView<?> parentAdapter, View view, int position, long id)
{
Toast.makeText(getActivity(), "CLICK!!!!", Toast.LENGTH_SHORT).show();
Log.e("SDF", "CLICK!!!!");
}
});
/**
* /NOT WORKING
*/
SearchView search = (SearchView) view.findViewById(R.id.fragment_search_view);
search.setQueryHint("Search list");
// Reacts to the search bar
search.setOnQueryTextListener(new SearchView.OnQueryTextListener()
{
@Override
public boolean onQueryTextSubmit(String query)
{
return false;
}
@Override
public boolean onQueryTextChange(String searchText)
{
updateDisplayList(searchText);
return false;
}
});
return builder.create();
}
@Override
public void onAttach(Activity activity)
{
super.onAttach(activity);
}
@Override
public void onDetach()
{
super.onDetach();
}
private void createPlanetsList(String searchText)
{
planetsList = new ArrayList<>();
addPlanet("Mercury", searchText);
addPlanet("Venus", searchText);
addPlanet("Earth", searchText);
addPlanet("Mars", searchText);
addPlanet("Jupiter", searchText);
addPlanet("Saturn", searchText);
addPlanet("Uranus", searchText);
addPlanet("Neptune", searchText);
}
private void addPlanet(String planetName, String searchText)
{
if (planetName.toLowerCase().contains(searchText.toLowerCase()))
{
HashMap<String, Boolean> planet = new HashMap<>(1);
boolean isSelected = selectedPlanets.contains(planetName);
planet.put(planetName, isSelected);
planetsList.add(planet);
}
}
private void resetAdapter()
{
// It worked when I used this instead of my custom adapter
/*
SimpleAdapter simpleAdapter = new SimpleAdapter(
getActivity(), // Context
planetsList, // Data list
android.R.layout.select_dialog_multichoice, // Row layout
new String[] {"planet"}, // Keys for list
new int[] {android.R.id.text1}); // View ID used to show the data
listView.setAdapter(simpleAdapter);
*/
MultiSelectAdapter adapter = MultiSelectAdapter.getAdapter(getActivity(), planetsList, selectedPlanets);
listView.setAdapter(adapter);
}
private void updateDisplayList(String searchText)
{
createPlanetsList(searchText);
resetAdapter();
}
}
MultiSelectAdapter.java
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import java.util.List;
import java.util.Map;
public class MultiSelectAdapter extends ArrayAdapter
{
private Context context;
private List<Map<String, Boolean>> planetsList;
private static List<String> selectedPlanets;
public static MultiSelectAdapter getAdapter(Context context, List<Map<String, Boolean>> objects, List<String> dialogSelectedPlanets)
{
selectedPlanets = dialogSelectedPlanets;
return new MultiSelectAdapter(context, android.R.id.text1, objects);
}
private MultiSelectAdapter(Context context, int resource, List<Map<String, Boolean>> objects)
{
super(context, resource, objects);
this.context = context;
this.planetsList = objects;
}
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = inflater.inflate(R.layout.fragment_row_layout, parent, false);
CheckBox checkBox = (CheckBox) rowView.findViewById(R.id.row_check_box);
String planetName = (String) planetsList.get(position).keySet().toArray()[0];
checkBox.setText(planetName);
if (selectedPlanets.contains(planetName))
{
checkBox.setChecked(true);
}
return rowView;
}
}
fragment_search_dialog.xml
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:context="lomax.mysearchinterface.SearchDialogFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<SearchView
android:id="@+id/fragment_search_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="30dp"
android:layout_marginRight="30dp"
android:iconifiedByDefault="false"/>
<ListView
android:id="@+id/fragment_list_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
</LinearLayout>
fragment_row_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<CheckBox
android:id="@+id/row_check_box"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textAllCaps="true"
android:text="Planet name"
android:focusable="false"/>
</LinearLayout>
【问题讨论】:
-
您说:“复选框选中/取消选中很好”。我不信。为什么?因为
if (selectedPlanets.contains(planetName)) { checkBox.setChecked(true); }没有别的。因此,当行视图被重用时,您可能会看到一些不应该检查的行被选中,反之亦然。解决方案?提供调用checkBox.setChecked(false);的 else 语句。 -
对于您面临的主要问题,请查看this question。
-
@khalafnt 您的第一条评论虽然完全正确,但没有实际意义,因为我需要某种形式的 clickListener 才能工作,然后才能填充 selectedPlanets。我还查看了您发布的链接,并且在适配器本身上创建 setOnClickListener() 也不起作用。在 XML 文件中也没有设置 focusable="false" 和 focusableInTouchMode="false"。
-
我已经更改了 textview 的复选框(几乎没有其他代码更改),一切正常。阻止 setOnClickListener() 在适配器上工作的复选框是什么?!?
-
android:layout_width="fill_parent"尝试使其成为wrap_content。我的意思当然是复选框。
标签: java android listview checkbox listadapter