Урок 54. Кастомизация списка. Создаем свой адаптер

Обсуждение уроков
Аватара пользователя
anber
Сообщения: 584
Зарегистрирован: 10 июн 2013, 15:05
Откуда: UA

Re: Урок 54. Кастомизация списка. Создаем свой адаптер

Сообщение anber » 17 июл 2014, 13:43

Ок, обьясню что этот параметр (android:descendantFocusability="blocksDescendants") делает.
1) Если его нет то onItemClick() вообще не вызовется если на item есть кнопки!
2) Если он есть то onItemClick() будет вызываться при клике на пустом месте в item (или элементах у которых clicable=false) , при клике не кнопку onItemClick() не вызовется
Личные сообщения с просьбой ответить на форуме или написать программу я просто удаляю, если я в хорошем настроении. Если в плохом добавляю автора в черный список. По любым другим вопросам feel free to write to me.

Аватара пользователя
altwin
Сообщения: 1951
Зарегистрирован: 13 ноя 2013, 14:46

Re: Урок 54. Кастомизация списка. Создаем свой адаптер

Сообщение altwin » 17 июл 2014, 13:51

anber писал(а):Ок, обьясню что этот параметр (android:descendantFocusability="blocksDescendants") делает.
1) Если его нет то onItemClick() вообще не вызовется если на item есть кнопки!
2) Если он есть то onItemClick() будет вызываться при клике на пустом месте в item (или элементах у которых clicable=false) , при клике не кнопку onItemClick() не вызовется
Или мы по разному это понимаем или у нас разный android, но конкретно результатом работы android:descendantFocusability="blocksDescendants" становться то, что всем элементам внутри этого layout содержащим в себе focusable или clickable, кнопка это или нет не важно, эти события запрещаются и они становятся простыми list items нажатие на которые и обрабатывает OnItemClickListener... как бы я так это понимаю и у меня именно в таком виде все работает... вопрос у нас разные android ? ;) Ну как бы да добавляя blocksDescendants, у кнопки focusable должен быть true и тогда проблем у системы отличить клик на пустой области или кнопке отличить не будет. Просто у меня все варрианты работают, я же говорю может я где то не там sdk скачал, но списки я разные делал и ну не было проблем... вообще не было :(

Опять таки пошел искать и в точности: http://stackoverflow.com/a/14372750/2611075

Но ок, пойдем другим путем... чем код показанный выше( собственная обработка клика отличается от этого: https://github.com/android/platform_pac ... .java#L381 ??? ), вопрос - почему кто то решил что работать он будет по другому???
Последний раз редактировалось altwin 17 июл 2014, 14:02, всего редактировалось 1 раз.
Изображение

Аватара пользователя
anber
Сообщения: 584
Зарегистрирован: 10 июн 2013, 15:05
Откуда: UA

Re: Урок 54. Кастомизация списка. Создаем свой адаптер

Сообщение anber » 17 июл 2014, 13:59

Андроид у меня 4.4.4.
Определимся:
1) у корневого елемента item установлено android:descendantFocusability="blocksDescendants"
2) на нем есть кнопка описанная так:

Код: Выделить всё

    <Button
            android:id="@+id/button1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button1"
            />
3) у listview установлено:

Код: Выделить всё

        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                // обрабочик onItemClick
            }
        });
4) у кнопки нет никаких обработчиков

У меня происходит следующее:
1) при клике на пустое место item он весь выделяется и срабатывает обработчик onItemClick
2) при клике на кнопку внутри item происходит анимация нажатия на кнопку, item НЕ выделяется, обработчик onItemClick НЕ срабатывает.


>>>Опять таки пошел искать и в точности: http://stackoverflow.com/a/14372750/2611075
это дословно повторяет ой предыдущий пост, разве нет?
Ок, обьясню что этот параметр (android:descendantFocusability="blocksDescendants") делает.
1) Если его нет то onItemClick() вообще не вызовется если на item есть кнопки!
2) Если он есть то onItemClick() будет вызываться при клике на пустом месте в item (или элементах у которых clicable=false) , при клике не кнопку onItemClick() не вызовется
Личные сообщения с просьбой ответить на форуме или написать программу я просто удаляю, если я в хорошем настроении. Если в плохом добавляю автора в черный список. По любым другим вопросам feel free to write to me.

Аватара пользователя
altwin
Сообщения: 1951
Зарегистрирован: 13 ноя 2013, 14:46

Re: Урок 54. Кастомизация списка. Создаем свой адаптер

Сообщение altwin » 17 июл 2014, 14:07

anber писал(а): У меня происходит следующее:
1) при клике на пустое место item он весь выделяется и срабатывает обработчик onItemClick
2) при клике на кнопку внутри item происходит анимация нажатия на кнопку, item НЕ выделяется, обработчик onItemClick НЕ срабатывает.
Пуcтое меcто - элемент списка такой же, как и другие, но не имеющий id по умолчанию, соответсвенно button элемент с id, которому не привязанно событие, switсh по id элементов списка?
Изображение

Аватара пользователя
anber
Сообщения: 584
Зарегистрирован: 10 июн 2013, 15:05
Откуда: UA

Re: Урок 54. Кастомизация списка. Создаем свой адаптер

Сообщение anber » 17 июл 2014, 14:11

altwin писал(а):Но ок, пойдем другим путем... чем код показанный выше( собственная обработка клика отличается от этого: https://github.com/android/platform_pac ... .java#L381 ??? ), вопрос - почему кто то решил что работать он будет по другому???
что это вообще и при чем оно тут?
altwin писал(а):Пуcтое меcто - элемент списка такой же, как и другие, но не имеющий id по умолчанию, соответсвенно button элемент с id, которому не привязанно событие, switсh по id элементов списка?
не понял мысль
Личные сообщения с просьбой ответить на форуме или написать программу я просто удаляю, если я в хорошем настроении. Если в плохом добавляю автора в черный список. По любым другим вопросам feel free to write to me.

Аватара пользователя
KamiSempai
Сообщения: 1339
Зарегистрирован: 17 фев 2012, 21:23
Откуда: Мордор

Re: Урок 54. Кастомизация списка. Создаем свой адаптер

Сообщение KamiSempai » 17 июл 2014, 14:17

Коллеги, кажется мы опять уходим от темы в бездну недопонимания.

Мне понравилась идея с вызовом метода performItemClick. Думаю, перепишу свой адаптер под него. Таким образом OnContextButtonClickListener будет совершенно не нужен.
R.id.team
Хватит таскать макулатуру на тренировку! Используй T Note.

Аватара пользователя
altwin
Сообщения: 1951
Зарегистрирован: 13 ноя 2013, 14:46

Re: Урок 54. Кастомизация списка. Создаем свой адаптер

Сообщение altwin » 17 июл 2014, 14:36

я не много уже сам в сути запутался, сейчас вот пытаюсь найти у себя где я использовал такой способ, к сожалению в основном поголовно android:onClick в ImageButton, но я найду и покажу... :)
Изображение

Аватара пользователя
anber
Сообщения: 584
Зарегистрирован: 10 июн 2013, 15:05
Откуда: UA

Re: Урок 54. Кастомизация списка. Создаем свой адаптер

Сообщение anber » 17 июл 2014, 14:57

KamiSempai писал(а):Коллеги, кажется мы опять уходим от темы в бездну недопонимания.

Мне понравилась идея с вызовом метода performItemClick. Думаю, перепишу свой адаптер под него. Таким образом OnContextButtonClickListener будет совершенно не нужен.
выложишь что получится, охота глянуть
Личные сообщения с просьбой ответить на форуме или написать программу я просто удаляю, если я в хорошем настроении. Если в плохом добавляю автора в черный список. По любым другим вопросам feel free to write to me.

Аватара пользователя
altwin
Сообщения: 1951
Зарегистрирован: 13 ноя 2013, 14:46

Re: Урок 54. Кастомизация списка. Создаем свой адаптер

Сообщение altwin » 17 июл 2014, 15:55

anber писал(а):
KamiSempai писал(а):Коллеги, кажется мы опять уходим от темы в бездну недопонимания.

Мне понравилась идея с вызовом метода performItemClick. Думаю, перепишу свой адаптер под него. Таким образом OnContextButtonClickListener будет совершенно не нужен.
выложишь что получится, охота глянуть
Получается я всех и себя обманул... у меня нет кнопок в listview вообще... :shock: есть только imageView.... :mrgreen:
Изображение

Аватара пользователя
KamiSempai
Сообщения: 1339
Зарегистрирован: 17 фев 2012, 21:23
Откуда: Мордор

Re: Урок 54. Кастомизация списка. Создаем свой адаптер

Сообщение KamiSempai » 17 июл 2014, 16:46

anber писал(а):выложишь что получится, охота глянуть
Выкладываю...
[syntax=java]public abstract class ContextualCursorAdapter<Holder> extends CursorAdapter {
private LayoutInflater mInflater;
private int mLayoutId;
private int[] mContextualButtons;
protected int mColumnIndexId;

public ContextualCursorAdapter(Context context, Cursor cursor, int layout,
int[] contextualButtons, int flags) {
super(context, cursor, flags);
mInflater = LayoutInflater.from(context);
mLayoutId = layout;
mContextualButtons = contextualButtons;
onCursorChanged(cursor);
}

abstract Holder newHolder(View view);

abstract void bindHolder(Holder holder, Cursor cursor);

@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
View view = mInflater.inflate(mLayoutId, parent, false);
ContextHolder<Holder> contextHolder = new ContextHolder<Holder>();
contextHolder.viewHolder = newHolder(view);
if (parent instanceof AdapterView<?>)
contextHolder.list = (AdapterView<?>) parent;
view.setTag(contextHolder);
if (mContextualButtons != null)
for (int id : mContextualButtons) {
View contextualButton = view.findViewById(id);
if (contextualButton != null) {
contextualButton
.setOnClickListener(mContextButtonClickListener);
contextualButton.setTag(contextHolder);
contextualButton.setSoundEffectsEnabled(false);
contextualButton.setFocusable(false);
}
}
return view;
}

@Override
public void bindView(View view, Context context, Cursor cursor) {
@SuppressWarnings("unchecked")
ContextHolder<Holder> contextHolder = (ContextHolder<Holder>) view
.getTag();
contextHolder.position = cursor.getPosition();
contextHolder.id = cursor.getLong(mColumnIndexId);

bindHolder(contextHolder.viewHolder, cursor);
}

@Override
public Cursor swapCursor(Cursor cursor) {
Cursor res = super.swapCursor(cursor);
onCursorChanged(cursor);
return res;
}

protected void onCursorChanged(Cursor newCursor) {
if(newCursor != null)
mColumnIndexId = newCursor.getColumnIndex(BaseColumns._ID);
}

protected void handleContextButtonClick(AdapterView<?> list, View view,
int position, long id) {
list.performItemClick(view, position, id);
}

private OnClickListener mContextButtonClickListener = new OnClickListener() {
@Override
public void onClick(View view) {
@SuppressWarnings("unchecked")
ContextHolder<Holder> contextHolder = (ContextHolder<Holder>) view
.getTag();
if (contextHolder != null && contextHolder.list != null)
handleContextButtonClick(contextHolder.list, view,
contextHolder.position, contextHolder.id);
}
};

private static class ContextHolder<T> {
int position;
long id;
AdapterView<?> list;
T viewHolder;
}
}[/syntax]
Перенес создание ContextHolder в newView так как доступ к parent-у только там есть. А еще отключил звук нажатия на кнопке, так как ListView этот звук воспроизведет после performItemClick (contextualButton.setSoundEffectsEnabled(false)). Плюс, переименовал класс на ContextualCursorAdapter, так вроде более правильно.
По сути ничего не поменялось, только теперь не нужно листенер ставить, будет вызываться onListItemClick. Как то так(Пример из ListFragment):[syntax=java] public void onListItemClick(ListView listView, View view, int position, final long id) {
if(view.getId() == View.NO_ID) {
// нажатие по строке
}
else {
// Нажатие по контекстной кнопке
}
}[/syntax]
R.id.team
Хватит таскать макулатуру на тренировку! Используй T Note.

Persik
Сообщения: 19
Зарегистрирован: 15 май 2014, 08:55

Re: Урок 54. Кастомизация списка. Создаем свой адаптер

Сообщение Persik » 24 сен 2014, 07:28

Добрый день! Я использ. ListFragment и простой TimeAdapter. У меня все получилось, но единственное проблемы что список вообще не отображается. У меня нет никаких ошибок Logcat. Не могу найти, в чем проблемы. Может, я что то не правильно написала.

dayfragment.xml

Код: Выделить всё

<?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" >
<ListView
        android:id="@android:id/list"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >
</ListView>
</LinearLayout>
text_fragment.xml

Код: Выделить всё

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:gravity="center"
    android:background="#5ba4e5"
    android:layout_height="match_parent">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="40px"
         android:textColor="#040404"
        android:layout_gravity="center"
        android:id="@+id/time"/>
 </LinearLayout>
TimeAdapter.java

Код: Выделить всё

public class TimeAdapter extends BaseAdapter {
    Context context;
    List<TimeRowItem> rowItem;
    TimeAdapter(Context context, List<TimeRowItem> rowItem) {
        this.context = context;
        this.rowItem = rowItem;    }

    @Override
    public int getCount() {
        return rowItem.size();}

    @Override
    public Object getItem(int position) {
        return rowItem.get(position); }

    @Override
    public long getItemId(int position) {
        return rowItem.indexOf(getItem(position)); }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
    	    if (convertView == null) {
            LayoutInflater mInflater = (LayoutInflater) context
                    .getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
            convertView = mInflater.inflate(R.layout.list_item, parent, false);}
        TextView txtTitle = (TextView) convertView.findViewById(R.id.time);
        TimeRowItem row_pos = rowItem.get(position);
        txtTitle.setText(row_pos.getTitle());
        return convertView;  }
}

DayFragment.java

Код: Выделить всё

public class DayFragment extends ListFragment {
		String[] menutitles;
	    TimeAdapter adapter;
	    private List<TimeRowItem> rowItems;

	    @Override
	    public View onCreateView(LayoutInflater inflater, ViewGroup container,
	            Bundle savedInstanceState) {
	        return inflater.inflate(R.layout.dayfragment, container, false);	    }

	    @Override
	    public void onActivityCreated(Bundle savedInstanceState) {
	        super.onActivityCreated(savedInstanceState);
	        menutitles = getResources().getStringArray(R.array.titles);
	        rowItems = new ArrayList<TimeRowItem>();
	        for (int i = 0; i < menutitles.length; i++) {
	            TimeRowItem items = new TimeRowItem(menutitles[i]);
	            rowItems.add(items);}
        setListAdapter(adapter);}
}

Аватара пользователя
klblk
Сообщения: 1097
Зарегистрирован: 18 окт 2012, 11:17
Откуда: г. Красноярск

Re: Урок 54. Кастомизация списка. Создаем свой адаптер

Сообщение klblk » 24 сен 2014, 10:18

Persik писал(а):Добрый день! Я использ. ListFragment и простой TimeAdapter. У меня все получилось, но единственное проблемы что список вообще не отображается. У меня нет никаких ошибок Logcat. Не могу найти, в чем проблемы. Может, я что то не правильно написала.
DayFragment.java

Код: Выделить всё

	    public void onActivityCreated(Bundle savedInstanceState) {
	        super.onActivityCreated(savedInstanceState);
	        menutitles = getResources().getStringArray(R.array.titles);
	        rowItems = new ArrayList<TimeRowItem>();
	        for (int i = 0; i < menutitles.length; i++) {
	            TimeRowItem items = new TimeRowItem(menutitles[i]);
	            rowItems.add(items);}
        setListAdapter(adapter);}

TimeAdapter не инициализируется, во время присвоения он у вас null.

Sanek517s
Сообщения: 33
Зарегистрирован: 03 ноя 2014, 19:39

Re: Урок 54. Кастомизация списка. Создаем свой адаптер

Сообщение Sanek517s » 03 ноя 2014, 19:40

Может кто-то написать или кинуть ссылку на пример реализации самого простого BaseAdapter'a?


Sanek517s
Сообщения: 33
Зарегистрирован: 03 ноя 2014, 19:39

Re: Урок 54. Кастомизация списка. Создаем свой адаптер

Сообщение Sanek517s » 03 ноя 2014, 21:22

Распишите плиз про метод getView в Base Adapter

Feonix, спасибо

Аватара пользователя
mitra
Сообщения: 10
Зарегистрирован: 18 ноя 2014, 11:22

Re: Урок 54. Кастомизация списка. Создаем свой адаптер

Сообщение mitra » 06 янв 2015, 17:47

Artem писал(а):
Artem писал(а): ...Подскажите, как реализовать в таком списке с кастомным адаптером обработку нажатия на элемент списка. Простая установка обработчика для списка через setOnItemClickListener к результату не приводит...
Разобрался, нужно установить

Код: Выделить всё

android:focusable="false"
для чекбокса.
У меня похожая ситуация была. И установка android:focusable="false" не помогала. У меня в кастомном адаптере был обработчик OnClickListener для LinearLayout, и по клику на нем срабатывал этот обработчик, а не обработчик для списка setOnItemClickListener. Теперь я обработчик OnClickListener для LinearLayout убрал (изобретенный велосипед :) ), а установку android:focusable="false" оставил. Теперь работает, как надо! :)
Каждая незаконченная задача - это минус. Но каждый зачеркнутый минус - это плюс.

ppp_ppp
Сообщения: 7
Зарегистрирован: 04 янв 2015, 00:56

Re: Урок 54. Кастомизация списка. Создаем свой адаптер

Сообщение ppp_ppp » 17 мар 2015, 15:48

Здравствуйте!

Делаю кастомный список -если упростить, то в каждом элементе списка(строке) есть textview и button при нажатии на которую должен вызываться time-диалог.
После выбора времени textview должно изменяться на на это выбранное время.
Все бы ничего, но изменяется textview в ДРУГОЙ строке.
пробовал решить используя setTag и getTag, но не получилось, мб что-то делал не так и не правильно использовал эти замечательные функции.

подскажите пожалуйста в каком направлении копать, может получше изучить setTag и getTag(т.к. на первый взгляд это самое простое и верное решение)

Аватара пользователя
Foenix
Сообщения: 4201
Зарегистрирован: 20 окт 2012, 12:01

Re: Урок 54. Кастомизация списка. Создаем свой адаптер

Сообщение Foenix » 17 мар 2015, 15:57

Какие еще тэги? Менять нужно данные, которые в листвью отображаются. А потом обновлять список.
R.id.team

NullPointerException - что делать???
viewtopic.php?f=33&t=3899&p=28952#p28952
Где моя ошибка?
viewtopic.php?f=60&t=3198

ppp_ppp
Сообщения: 7
Зарегистрирован: 04 янв 2015, 00:56

Re: Урок 54. Кастомизация списка. Создаем свой адаптер

Сообщение ppp_ppp » 18 мар 2015, 00:59

Foenix писал(а):Какие еще тэги? Менять нужно данные, которые в листвью отображаются. А потом обновлять список.
Извините, не понял как обратиться именно к нужному мне textview. Думал, что автоматически кнопка в n-ой строке изменяет textview в n-ой строке. А выходит полностью рандомно.

посмотрите пожалуйста мой код, делал по аналогии с примером урока, только мне не понадобился дополнительный класс начальных значений, все строки изначально одинаковы
строка - это textview и button, которая изменяет textview

Код: Выделить всё

package com.example.wi_fitimerlistview;

import java.util.ArrayList;
import java.util.Calendar;

import android.app.TimePickerDialog;
import android.app.TimePickerDialog.OnTimeSetListener;
import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.TextView;
import android.widget.TimePicker;

public class BoxAdater extends BaseAdapter {

	private TimePickerDialog mTimePickerDialogOn, mTimePickerDialogOff;
	Context ctx;
	LayoutInflater lInflater;
	ArrayList<Period> objects;
	TextView t_start_time, t_end_time;

	public BoxAdater(Context context, ArrayList<Period> period) {
		ctx = context;
		objects = period;
		lInflater = (LayoutInflater) ctx
				.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
	}

	@Override
	public int getCount() {
		// TODO Auto-generated method stub
		return objects.size();
	}

	@Override
	public Object getItem(int position) {
		// TODO Auto-generated method stub
		return objects.get(position);
	}

	@Override
	public long getItemId(int position) {
		// TODO Auto-generated method stub
		return position;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		// TODO Auto-generated method stub

		View view = convertView;
		if (view == null) {
			view = lInflater.inflate(R.layout.item, parent, false);
		}

		t_start_time = (TextView) view.findViewById(R.id.textview_start_time);

		initTimePickerDialogOn();

		Button b_change_start_time = (Button) view
				.findViewById(R.id.button_change_start_time);
		b_change_start_time.setTag(position);
		b_change_start_time.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				Log.d("MY_TAG", v.getTag().toString());
				mTimePickerDialogOn.show();

			}
		});

		return view;
	}

	Period getPeriod(int position) {
		return ((Period) getItem(position));
	}

	private void initTimePickerDialogOn() {

		Calendar c = Calendar.getInstance();
		int hour = c.get(Calendar.HOUR);
		int min = c.get(Calendar.MINUTE);
		mTimePickerDialogOn = new TimePickerDialog(ctx,
				new OnTimeSetListener() {

					@Override
					public void onTimeSet(TimePicker view, int hourOfDay,
							int minute) {
						// SampleService.HOUR_WORK = hourOfDay;
						// SampleService.MIN_WORK = minute;
						t_start_time.setText(hourOfDay + "------" + minute);
					}
				}, hour, min, true);
		mTimePickerDialogOn.setTitle("Начало");
	}

	
}

Аватара пользователя
Foenix
Сообщения: 4201
Зарегистрирован: 20 окт 2012, 12:01

Re: Урок 54. Кастомизация списка. Создаем свой адаптер

Сообщение Foenix » 18 мар 2015, 08:18

Обязательно нужен начальный массив значений, пусть даже заполненеый одинак. Значениями. Его и надо потом менять.
R.id.team

NullPointerException - что делать???
viewtopic.php?f=33&t=3899&p=28952#p28952
Где моя ошибка?
viewtopic.php?f=60&t=3198

Ответить