【问题标题】:OnItemClickListener not working in a DialogFragment when using a custom Adapter使用自定义适配器时 OnItemClickListener 在 DialogFragment 中不起作用
【发布时间】: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


【解决方案1】:

在通过互联网寻找更多想法之后,我偶然发现了解决此问题的方法。在我的适配器类的 getView(...) 方法中:

checkBox.setOnCheckedChangeListener(this);

并让我的适配器类实现:

implement CompoundButton.OnCheckedChangeListener

这似乎有效,无需更改行布局的 XML 或任何其他巧妙之处。

希望这可以帮助遇到这个问题的下一个可怜的草皮......

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多