it-swarm.com.ru

ListFragment OnListItemClick не вызывается

У меня есть класс, который расширяет ListFragment, и он переопределяет метод OnListItemClick. Я также делаю это в другом ListFragment таким же образом (и метод вызывается). Мне интересно, почему метод не вызывается, когда я нажимаю на элемент списка?

Вот код:

package org.doraz.fdboard.activity;

import Java.sql.SQLException;
import Java.util.Collection;

import org.doraz.fdboard.FantasyDraftBoardApplication;
import org.doraz.fdboard.R;
import org.doraz.fdboard.activity.DraftBoardActivity.PlayerDetailsActivity;
import org.doraz.fdboard.domain.FantasyLeague;
import org.doraz.fdboard.domain.FantasyTeam;
import org.doraz.fdboard.domain.Player;
import org.doraz.fdboard.domain.Position;
import org.doraz.fdboard.repository.FantasyDraftBoardRepository;
import org.doraz.fdboard.view.PlayerAdapter;
import org.doraz.fdboard.view.PlayerCursorAdapter;

import Android.app.FragmentTransaction;
import Android.app.ListFragment;
import Android.app.ProgressDialog;
import Android.content.Intent;
import Android.database.Cursor;
import Android.os.AsyncTask;
import Android.os.Bundle;
import Android.util.Log;
import Android.view.View;
import Android.widget.Adapter;
import Android.widget.AdapterView;
import Android.widget.AdapterView.OnItemClickListener;
import Android.widget.ListView;

public class ListPlayersFragment extends ListFragment implements OnItemClickListener {

    private final static String TAG = "ListPlayersFragment";

    private boolean mDualPane;  
    private int curSelectedPlayerPosition = 0;
    private PlayerCursorAdapter playerAdapter;
    private QueryPlayersTask currentTask;

    private FantasyDraftBoardRepository repository;
    private FantasyLeague fantasyLeague;
    private FantasyTeam fantasyTeam;
    private Position position;
    private ProgressDialog progressDialog;


    /* (non-Javadoc)
     * @see Android.app.ListFragment#onActivityCreated(Android.os.Bundle)
     */
    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        //Check  for the view players view along with the pane
        View teamListFragment = getActivity().findViewById(R.id.team_list_fragment);
        mDualPane = teamListFragment != null && teamListFragment.getVisibility() == View.VISIBLE;

        if(mDualPane) {
            Log.i(TAG, "Setting list select mode to single");
            getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
        }

        getListView().setSmoothScrollbarEnabled(false);
    }

    /* (non-Javadoc)
     * @see Android.app.ListFragment#onListItemClick(Android.widget.ListView, Android.view.View, int, long)
     */
    @Override
    public void onListItemClick(ListView l, View v, int position, long id) {
        super.onListItemClick(l, v, position, id);
        Log.i(TAG, "[onListItemClick] Selected Position "+ position);
        selectPlayer(position);
    }

    /* (non-Javadoc)
     * @see Android.app.Fragment#onSaveInstanceState(Android.os.Bundle)
     */
    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt("curSelectedPlayerPosition", curSelectedPlayerPosition);
        outState.putInt("fantasyLeague", fantasyLeague.getLeaguePID());

        if(!Position.ALL.equals(position)) {
            outState.putInt("position", position.getPositionPID());
        }

        if(!(FantasyTeam.ALL_AVAILABLE_TEAM.equals(fantasyTeam) || FantasyTeam.ALL_TEAM.equals(fantasyTeam))) {
            outState.putInt("fantasyTeam", fantasyTeam.getTeamPID());
        }
    }

    /**
     * Selects the player at this position in the current list
     * @param listPosition
     */
    public void selectPlayer(int listPosition) {
        curSelectedPlayerPosition = listPosition;

        Player player = (Player) playerAdapter.getItem(listPosition);

        Log.i(TAG, "Select Player ("+ listPosition +", "+ player.getName() +") called");

        //Get the player url
        String mPlayerUrl = player.getPlayerUrl();
        Log.d(TAG, "Selected Player URL: "+mPlayerUrl);

        if(mDualPane) {
            if(getListView().getSelectedItemPosition() == listPosition) {
                //Remove the selected item
                return;
            }

            //Select the item
            getListView().setItemChecked(listPosition, true);

            Log.d(TAG, "Creating ViewPlayerFragment");
            ViewPlayerFragment vpf = ViewPlayerFragment.newInstance(mPlayerUrl);
            ListTeamsFragment ltf = (ListTeamsFragment) getFragmentManager().findFragmentById(R.id.team_list_fragment);

            FragmentTransaction ft = getFragmentManager().beginTransaction();
            ft.replace(R.id.player_web_view_fragment, vpf);

            if(ltf != null && !ltf.isHidden()) {
                //Hide the list of teams
                ft.hide(ltf);
                ft.addToBackStack(null);
            }

            ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
            ft.commit();
            Log.d(TAG, "Committed to ViewPlayerFragment");
        }
        else {
            Log.d(TAG, "Launching new activity to view player");
            Intent intent = new Intent();
            intent.setClass(getActivity(), PlayerDetailsActivity.class);
            intent.putExtra("playerURL", mPlayerUrl);
            startActivityForResult(intent, 0);
        }
    }

    public void clearSelectedPlayer() {
        Log.i(TAG, "Clearing selected player");

        curSelectedPlayerPosition = -1;

        //Clear the list view
        getListView().clearChoices();

        ViewPlayerFragment vpf = (ViewPlayerFragment) getFragmentManager().findFragmentById(R.id.player_web_view_fragment);
        if(vpf != null) {
            Log.d(TAG, "Closing ViewPlayerFragment");

            //Close the ViewPlayersFragment
            FragmentTransaction ft = getFragmentManager().beginTransaction();
            ft.remove(vpf);
            ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE);
            ft.commit();
            Log.d(TAG, "Closed ViewPlayerFragment");
        }
    }

    /**
     * Initializes the player adapter
     */
    private void initializePlayerAdapter(Cursor cursor) {
        if(playerAdapter != null)
            return;

        playerAdapter = new PlayerCursorAdapter(getActivity(), cursor, (DraftBoardActivity)getActivity(), repository);
        setListAdapter(playerAdapter);
        setEmptyText(getText(R.string.no_players_msg));
    }

    /**
     * Initializes the player adapter
     */
    public void setPlayersCursor(Cursor cursor) {
        if(playerAdapter == null) {
            initializePlayerAdapter(cursor);
        }
        else {
            playerAdapter.changeCursor(cursor);
        }
    }

    /**
     * Drafts a player
     * 
     * @param mPlayer       the player to draft
     * @param fantasyTeam   the fantasy team
     * @param value         the draft value
     */
    public void draftPlayer(Player mPlayer, FantasyTeam fantasyTeam, Double value) {

        mPlayer.setFantasyTeam(fantasyTeam);
        mPlayer.setDraftValue(value);
        mPlayer.setDrafted(true);
        fantasyTeam.draftPlayer(mPlayer);

        try {
            repository.savePlayer(mPlayer);
            repository.saveFantasyTeam(fantasyTeam);
        } catch (SQLException e) {
            Log.e(TAG, "Error drafting player", e);
        }

        //Refresh the query
        refresh();
    }

    /**
     * Refreshes the players list
     */
    public void refresh(){
        if(fantasyLeague == null) {
            fantasyLeague = ((FantasyDraftBoardApplication) (getActivity().getApplication())).getCurrentFantasyLeague();
        }

        if(fantasyTeam == null) {
            fantasyTeam = FantasyTeam.ALL_AVAILABLE_TEAM;
        }

        if(position == null) {
            position = Position.ALL;
        }

        if(currentTask != null) {
            currentTask.cancel(true);
        }

        if(progressDialog != null) {
            progressDialog.dismiss();
            progressDialog = null;
        }

        progressDialog = ProgressDialog.show(getActivity(), null, "Loading...");
        currentTask = new QueryPlayersTask(fantasyLeague, fantasyTeam, position, repository);
        currentTask.execute();
    }

    /**
     * Sets the fantasyLeague
     * @param fantasyLeague the fantasyLeague to set
     */
    public void setFantasyLeague(FantasyLeague fantasyLeague) {
        this.fantasyLeague = fantasyLeague;
    }

    /**
     * Sets the fantasyTeam
     * @param fantasyTeam the fantasyTeam to set
     */
    public void setFantasyTeam(FantasyTeam fantasyTeam) {
        this.fantasyTeam = fantasyTeam;
    }

    /**
     * Sets the position
     * @param position the position to set
     */
    public void setPosition(Position position) {
        this.position = position;
    }

    /**
     * Sets the repository
     * @param repository the repository to set
     */
    public void setRepository(FantasyDraftBoardRepository repository) {
        this.repository = repository;
    }

    private class QueryPlayersTask extends AsyncTask<Integer, Integer, Cursor> {

        private FantasyLeague fantasyLeague;
        private FantasyTeam fantasyTeam;
        private Position position;
        private FantasyDraftBoardRepository repository;

        public QueryPlayersTask(FantasyLeague fantasyLeague, FantasyTeam fantasyTeam, Position position, FantasyDraftBoardRepository repository) {
            this.fantasyLeague = fantasyLeague;
            this.fantasyTeam = fantasyTeam;
            this.position = position;
            this.repository = repository;
        }

        @Override
        protected Cursor doInBackground(Integer... params) {
            try {
                return repository.queryForPlayersCursor(position, fantasyLeague, fantasyTeam);
            } catch (SQLException e) {
                Log.e("QueryPlayersTask", "Unable to query for players", e);
            }

            return null;
        }

        /* (non-Javadoc)
         * @see Android.os.AsyncTask#onPostExecute(Java.lang.Object)
         */
        @Override
        protected void onPostExecute(Cursor result) {
            super.onPostExecute(result);

            if(!isCancelled()) {
                //Update the player cursor
                updatePlayerCursor(result);
            }
        }
    }

    /**
     * Updates the player cursor
     * @param c the player cursor
     */
    private final void updatePlayerCursor(Cursor c){
        Log.d(TAG, "Updating player cursor.");
        if(playerAdapter == null)
            initializePlayerAdapter(c);
        else
            playerAdapter.changeCursor(c);

        if(progressDialog != null) {
            progressDialog.dismiss();
            progressDialog = null;
        }

        //Clear the current task
        currentTask = null;
    }

    @Override
    public void onItemClick(AdapterView<?> adapter, View arg1, int listPosition, long id) {
        Log.d(TAG, "[onItemClick] Clicked item "+position);
        selectPlayer(listPosition);
    }


}

Любая помощь будет высоко ценится. Я могу получить желаемый эффект, реализовав несколько других слушателей и назначив его каждому элементу списка, но я думаю, что это правильный способ сделать это, и он ДОЛЖЕН работать. Я просто не знаю, почему это не так

Заранее спасибо.

32
Steve

Если у вас есть элемент в макете, который может украсть ввод от других компонентов, таких как CheckBox, этот компонент должен быть определен как не фокусируемый.

97
auselen

Вот элегантное решение, которое позволяет onListItemClick запускать так, как вы думаете, а также позволяет любым дочерним представлениям получать события (или нет, в зависимости от того, как вы хотите его установить.) Для поставленного вопроса это позволит сохранить флажок подпредставления. Пожалуйста, позаботьтесь о том, чтобы это было интуитивно понятным для пользователей.

В корневой ViewGroup всех элементов списка установите атрибут descendantFocusability в XML:

Android:descendantFocusability="blocksDescendants"

Документация Android SDK о потомстве Фокусируемость . Был частью SDK с Android 1.0. Другие настройки для Android:descendantFocusability включают "beforeDescendants" и "afterDescendants".

Пример cluster_layout.xml, который устанавливает descendantFocusability (элементы списка, примененные к cluster_list.xml через ArrayAdapter):

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:Android="http://schemas.Android.com/apk/res/Android"
    xmlns:tools="http://schemas.Android.com/tools"
    Android:id="@+id/cluster_layout"
    Android:layout_width="match_parent"
    Android:layout_height="wrap_content"
    Android:orientation="horizontal"
    Android:background="#e0e0e0"
    Android:clickable="false"
    Android:descendantFocusability="blocksDescendants" >

    <FrameLayout
        Android:id="@+id/cluster_sentiment_handle"
        Android:layout_width="40dp"
        Android:layout_height="match_parent"
        Android:background="@color/handle_red" />
    <!-- other elements -->
</LinearLayout>

Пример cluster_list.xml, который не имеет никакого отношения к этому решению, кроме как показывает, что он предназначен для использования в ListFragment, имея элемент ListView с id @ id/Android: list:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:orientation="vertical"
    Android:padding="8dp"
    Android:background="#f6f6f6" >
    <include layout="@layout/cluster_header" />
    <ListView
        Android:id="@id/Android:list"
        Android:layout_width="match_parent"
        Android:layout_height="match_parent"
        Android:layout_gravity="top|center_horizontal"
        Android:gravity="center_horizontal"
        Android:divider="@Android:color/transparent"
        Android:dividerHeight="8dp"
        Android:fastScrollEnabled="true" />
</LinearLayout>
14
joweeba

Я столкнулся с той же проблемой после преобразования моего приложения из ListActivity в ListFragment.

ListFragment был единственным фрагментом действия (без вкладок и т.д.), Но ListFragment не видел ни одного щелчка.

Проблема заключалась в том, что моя активность все еще определялась как ListActivity. Изменил его на исправленное действие, и теперь ListFragment видит щелчки.

    public class MyActivity extends ListActivity {
        @Override
        public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
            setContentView(R.layout.my_layout);
    }

должно было:

    public class MyActivity extends Activity {
        @Override
        public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
            setContentView(R.layout.my_layout);
    }



    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
        Android:layout_width="fill_parent"
        Android:layout_height="fill_parent"
        Android:orientation="vertical" >        
        <fragment class="com.davidmarkscott.myapp.MyFragment"
        Android:id="@+id/fragment"
        Android:layout_width="match_parent"
        Android:layout_height="match_parent" />
    </LinearLayout>
14
davidmarkscott

Подобно другим, у меня есть CustomAdapter с моим ListFragment, который переопределяет getView (), чтобы обеспечить представление для каждой строки. Установка слушателей на вид, который возвращается, работал для меня. Пример:

public class MyAdapter extends ArrayAdapter<SomeType> {

private Context context;
private List<SomeType> objects;

public MyAdapter(Context context, int resource, List<SomeType> objects) {
    super(context, resource, objects);
    this.context = context;
    this.objects = 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.list_subscription_item, null);

    TextView subTo = (TextView)rowView.findViewById(R.id.itemName);

    SomeType sub = objects.get(position);

    subTo.setText(sub.getName() + sub.getId());

    rowView.setOnLongClickListener(new View.OnLongClickListener() {
        @Override
        public boolean onLongClick(View v) {
            Toast.makeText(context, "from long click", Toast.LENGTH_SHORT).show();
            return false;
        }
    });

    rowView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Toast.makeText(context, "from click", Toast.LENGTH_SHORT).show();
        }
    });
    return rowView;
}
}
4
Todd DeLand

Я также столкнулся с той же проблемой. Использование ListFragment, который был раздут как содержимое вкладки внутри TabHost

Одна из моих TabHost имеет 3 вкладки, onListItemClick() была вызвана правильно. 

Но другой TabHost имеет только 2 вкладки, функция onListItemClick() не была вызвана.

Поэтому я решил реализовать работу, о которой упоминали выше Марсель и H9kDroid, и она работала нормально. Спасибо за Ваш ответ.

Обновление: После нескольких часов возни кажется, что проблема связана с компоновкой элемента списка и адаптера ListView.

Внутри моего макета элемента списка есть один флажок, и состояние переключателя переключается внутри адаптера. Я думаю, что после переключения ListView испортился и не может доставить вызов onListItemClick().

Я просто изменил макет, снимите флажок, и он работает нормально.

Приветствия.

3
ck1910

Пока только обходной путь, используйте Fragment и ListView, затем используйте setOnItemClickListener(), что сделает ListFragment и все его удобства устаревшими ... После того как я создал новый класс, содержащий точно такой же код (изменилось только имя класса) и построил проект на другой машине, он «волшебным образом» работал (все тот же API-уровень). Ниже код, который работал. Я также попробовал project-> clean, который обычно исправляет большинство проблем, но это не сработало.

public class ContainerFragment extends ListFragment {

    private ContainerFragmentListener listener;

    public ContainerFragment(ContainerFragmentListener listener) {
        super();
        this.listener = listener;
    }
    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        setListAdapter(new ContainerAdapter(getActivity()));
    }

     @Override
    public void onListItemClick(ListView l, View v, int position, long id) {
        super.onListItemClick(l, v, position, id);
        Container container = (Container) getListAdapter().getItem(position);
        listener.containerSelected(container.id);
    }


}
3
Marcel

Повторяя сказанное @auselen выше, в моем случае я установил Android:textIsSelectable="true" в TextView, и он крал обратный вызов. 

Установка этого параметра в false решила проблему.

2
Jonathan Lin

Я обнаружил, что установка свойства Android: focusable в false в любом дочернем представлении элемента списка предотвращает запуск обработчика щелчков. Следующая настройка работает с ListFragment.

navigation_fragment.xml:

<ListView xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:id="@+id/navigationEntries"
    Android:layout_height="wrap_content"
    Android:layout_width="fill_parent" />

navigation_entry.xml:

    <LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
            Android:id="@+id/navigationEntry"
            Android:orientation="vertical"
            Android:layout_height="wrap_content"
            Android:layout_width="fill_parent"
            <!-- enhance this -->
            <ImageView
                    Android:layout_width="fill_parent"
                    Android:layout_height="1dp"
                    Android:background="@Android:color/darker_gray" />

1
s.froehlich

Я часами пытался выяснить мою собственную подобную проблему. У меня было довольно простое составное текстовое представление, которое содержало флажок и два текстовых представления и простой настраиваемый адаптер. Перепробовав разные вещи, которые мне предлагали, я вынимал представления, пока у меня не было только одного просмотра текста. Все еще не работал. Ты знаешь что сделал? Я просто удалил файл макета xml для пользовательского представления и использовал его снова, по частям. Сделано одно и то же точно с тем же именем. Ему просто не понравился этот файл по какой-то причине. Итак, поехали. Какой-то странный сбой в Eclipse, я думаю.

1
slida

Я вызвал listfragment.getListView (). SetOnItemClickListener (), а также переопределил onListItemClick () в ListFragment, в результате чего onListItemClick не вызывался. Я удалил метод setOnItemClickListener (), и вместо этого был вызван метод onListItemClick для listFragment.

0
flobacca