android - example - ListFragment OnListItemClick no se llama
android listfragment example (10)
Al igual que otros, tengo un CustomAdapter con mi ListFragment, que anula getView () para proporcionar la vista para cada fila. Configurar los oyentes en la vista que se devuelve funcionó para mí. Ejemplo:
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;
}
}
Tengo una clase que amplía ListFragment y anula el método OnListItemClick. También estoy haciendo esto en otro ListFragment de la misma manera (y se llama al método). Me pregunto por qué el método no se llama cuando hago clic en el elemento de la lista.
Aquí está el código:
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);
}
}
Cualquier ayuda sería muy apreciada. Puedo obtener el efecto deseado implementando algunos otros oyentes y asignándolos a cada elemento de la lista, pero creo que esta es la forma correcta de hacerlo y DEBERÍA funcionar. Simplemente no sé por qué no lo hace
Gracias por adelantado.
Aquí hay una solución elegante que permite a onListItemClick
disparar de la manera que usted cree que debería hacerlo, y también permite que las vistas secundarias reciban eventos (o no, dependiendo de cómo lo quiera configurar). Para la pregunta planteada, esto permitiría mantener la subvista de casilla de verificación. Por favor, tenga en cuenta si se trata de una experiencia intuitiva para los usuarios.
En la raíz ViewGroup de todos los elementos de la lista, establezca el atributo descendantFocusability
en XML:
android:descendantFocusability="blocksDescendants"
Documentación de Android SDK de descendienteFocusability . Ha sido parte del SDK desde Android 1.0. Otras configuraciones para android:descendantFocusability
incluye "beforeDescendants"
y "afterDescendants"
.
Ejemplo cluster_layout.xml que establece descenddantFocusability (Elementos de lista aplicados a cluster_list.xml a través de 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>
Ejemplo cluster_list.xml, que no tiene ninguna relación con esta solución que no sea para mostrar que está destinado para su uso en un ListFragment al tener un elemento ListView con el 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>
Descubrí que configurar la propiedad Android: enfocable a falso en cualquier vista secundaria de un elemento de la lista evita que se dispare el controlador de clic. La siguiente configuración funciona con un 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" />
Haciéndome eco de lo que dijo @auselen arriba, en mi caso tenía android:textIsSelectable="true"
en un TextView
, y estaba robando la devolución de llamada.
Establecer esto en false
resolvió el problema.
Llamé a listfragment.getListView (). SetOnItemClickListener () y también anulé onListItemClick () en ListFragment y eso provocó que no se llamara a onListItemClick. Eliminé el método setOnItemClickListener () y en su lugar se llamó al método listFragment onListItemClick.
Me encontré con el mismo problema después de convertir mi aplicación de una ListActivity a un ListFragment.
ListFragment era el único fragmento de la actividad (sin pestañas, etc.), pero ListFragment no veía ninguno de los clics.
El problema era que mi actividad todavía se definía como una actividad de lista. Lo cambió a una actividad que lo solucionó, y ahora ListFragment ve los clics.
public class MyActivity extends ListActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_layout);
}
debería haber sido:
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>
Pasé horas tratando de descubrir mi propio problema similar. Tenía una vista de texto compuesto bastante simple que contenía una casilla de verificación, dos vistas de texto y un adaptador personalizado simple. Después de probar varias cosas que se sugirieron, eliminé las vistas hasta que tuve una vista de texto. Aún no funcionó. ¿Sabes lo que hizo? Acabo de eliminar el archivo de diseño xml para la vista personalizada que estaba usando y lo hice de nuevo, pieza por pieza. Hecho exactamente lo mismo con el mismo nombre. Simplemente no le gustó ese archivo por alguna razón. Ahí vas. Algún error extraño en Eclipse, supongo.
Si tiene un elemento en su diseño que puede robar la entrada de otros componentes como un CheckBox, ese componente debe definirse como no enfocable.
Solo una solución hasta ahora, use un Fragment
y un ListView
luego use setOnItemClickListener()
que haría ListFragment
el ListFragment
, y toda su conveniencia ... Después de que creé una nueva clase que contiene exactamente el mismo código (solo cambió el nombre de clase) y construyó el proyecto en una máquina diferente que funcionó "mágicamente" (aún el mismo nivel de API). Debajo del código que funcionó. También probé project-> clean, que generalmente soluciona la mayoría de los problemas, pero no funcionó.
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);
}
}
También encontré el mismo problema. Usar ListFragment
que se infló como un contenido de pestaña de una pestaña dentro de un TabHost
.
Uno de mis TabHost
tiene 3 pestañas, el onListItemClick()
se llamó correctamente.
Pero el otro TabHost tiene solo 2 pestañas, el onListItemClick()
no fue llamado.
Así que decidí implementar el trabajo que Marcel y H9kDroid mencionaron anteriormente y funcionó bien. Gracias por tu respuesta.
Actualización: después de perder el tiempo durante unas horas, parece que el problema está relacionado con el diseño del elemento de la lista y el adaptador de ListView.
Dentro del diseño de mi elemento de lista, hay una casilla de verificación y el estado de la casilla de verificación se alterna dentro del adaptador. Creo que después de alternar, el ListView
onListItemClick()
un onListItemClick()
y no puede entregar la llamada a onListItemClick()
.
Acabo de cambiar el diseño, elimine la casilla de verificación y funciona bien.
Aclamaciones.