Подтвердить что ты не робот

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);
    }


}

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

Спасибо в Advance.

4b9b3361

Ответ 1

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

Ответ 2

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

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

android:descendantFocusability="blocksDescendants"

Документация SDK для descendantFocusability для 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 @idroid: 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>

Ответ 3

Я столкнулся с такой же проблемой после преобразования моего приложения из 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>

Ответ 4

Как и другие, у меня есть 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;
}
}

Ответ 5

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

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);
    }


}

Ответ 6

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

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

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

Итак, я решил реализовать работу над этим Marcel и H9kDroid, упомянутые выше, и все получилось отлично. Спасибо за ваш ответ.

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

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

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

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

Ответ 7

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

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

Ответ 8

Я выяснил, что установка свойства android: focusable to 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" />

Ответ 9

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

Ответ 10

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

Ответ 11

CheckBox является фокусируемым по умолчанию. Это означает, что нажатие на элемент списка будет интерпретироваться как переключение CheckBox и не достигнет вашего метода onListItemClick (…). Эта внутренняя особенность ListView означает, что любой фокусируемый виджет, который появляется в макете элемента списка (например, CheckBox или Button), должен быть не фокусируемым, чтобы гарантировать, что нажатие на элемент списка будет работать так, как вы ожидаете. Поскольку ваш CheckBox только сообщает информацию и не привязан к какой-либо логике приложения, существует простое решение. Вы можете определить CheckBox как не фокусируемый.

из путеводителя "Большой ботанический ранчо"