Продолжение, первую часть читайте здесь.
Содержание
SimpleHierarchyAdapter
Похож на PresentationAdapter, простой адаптер для иерархических справочников. Несмотря на название, по сути выводит линейный список, просто подчиненные элементы выводятся с небольшим отступом.
1 2 3 4 5 6 | //Иерархический вывод групп справочника «Номенклатура» CatalogNomenklaturaDao daoSku = getHelper().getDao(CatalogNomenklatura.class); SimpleHierarchyAdapter<CatalogNomenklatura> adapter = new SimpleHierarchyAdapter<CatalogNomenklatura>(this, daoSku); Spinner spin = (Spinner) findViewById(R.id.spinner1); spin.setAdapter(adapter); |
//Иерархический вывод групп справочника «Номенклатура» CatalogNomenklaturaDao daoSku = getHelper().getDao(CatalogNomenklatura.class); SimpleHierarchyAdapter<CatalogNomenklatura> adapter = new SimpleHierarchyAdapter<CatalogNomenklatura>(this, daoSku); Spinner spin = (Spinner) findViewById(R.id.spinner1); spin.setAdapter(adapter);
Можно установить отбор по родителю и сортировку групп, подробнее см. в документации.
HierarchyAdapter
Еще один адаптер, предназначенный исключительно для иерархических справочников. Не смотря на то, что данные выводятся линейно, позволяет довольно легко реализовать навигацию по иерархическому справочнику. Пример:
Есть форма (Activity) со списком (ListView) отображающим элементы иерархического справочника. По клику на группе – “проваливаемся ниже” т.е устанавливаем отбор по этой группе. По кнопке “Up” возвращаемся назад, поднимаемся на уровень выше.
В примере дополнительно показана фильтрация по представлению, которая устанавливается / снимается по кнопке “Filter”.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | list = (ListView) findViewById(R.id.listView1); //Установить обработчик выбора элемент в списке list.setOnItemClickListener(onListItemClickListener); //…инициализация других контролов //Из всего справочника «Номенклатура» отбираются только дочерние группы и элементы по группе «Обувь». //Сортировка: группы сверху, по наименованию CatalogNomenklaturaDao dao = getHelper().getDao(CatalogNomenklatura.class); CatalogNomenklatura parent = dao.findByDescription("Обувь"); String order = Catalog.FIELD_NAME_PARENT + " DESC, " + Catalog.FIELD_NAME_DESCRIPTION; HierarchyAdapter<CatalogNomenklatura> adapter = new HierarchyAdapter<CatalogNomenklatura>(this, dao,parent,null,order); //Группы выделить жирным шифтом adapter.setSelectedFolderBold(true); list.setAdapter(adapter); |
list = (ListView) findViewById(R.id.listView1); //Установить обработчик выбора элемент в списке list.setOnItemClickListener(onListItemClickListener); //…инициализация других контролов //Из всего справочника «Номенклатура» отбираются только дочерние группы и элементы по группе «Обувь». //Сортировка: группы сверху, по наименованию CatalogNomenklaturaDao dao = getHelper().getDao(CatalogNomenklatura.class); CatalogNomenklatura parent = dao.findByDescription("Обувь"); String order = Catalog.FIELD_NAME_PARENT + " DESC, " + Catalog.FIELD_NAME_DESCRIPTION; HierarchyAdapter<CatalogNomenklatura> adapter = new HierarchyAdapter<CatalogNomenklatura>(this, dao,parent,null,order); //Группы выделить жирным шифтом adapter.setSelectedFolderBold(true); list.setAdapter(adapter);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | /* * Обработчик выбора элемент в списке. Если выбрана группа – проваливаемся ниже. */ private OnItemClickListener onListItemClickListener = new OnItemClickListener() { @SuppressWarnings("unchecked") @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { CatalogNomenklatura item = (CatalogNomenklatura) list.getItemAtPosition(position); if(item.isFolder()) try { ((HierarchyAdapter<CatalogNomenklatura>)list.getAdapter()).push(item); } catch (SQLException e) { e.printStackTrace(); } } }; /* * Обработчик нажатия на кнопку «UP» */ @SuppressWarnings("unchecked") private void onUpClick() { try { ((HierarchyAdapter<CatalogNomenklatura>) list.getAdapter()).pop(); } catch (SQLException e) { e.printStackTrace(); } } /* * Снять/установить дополнительный отбор по представлению */ @SuppressWarnings("unchecked") private void onFiltelClick() { String pattern = etFilter.getText().toString(); ((HierarchyAdapter<CatalogNomenklatura>) list.getAdapter()).getFilter().filter(pattern); } |
/* * Обработчик выбора элемент в списке. Если выбрана группа – проваливаемся ниже. */ private OnItemClickListener onListItemClickListener = new OnItemClickListener() { @SuppressWarnings("unchecked") @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { CatalogNomenklatura item = (CatalogNomenklatura) list.getItemAtPosition(position); if(item.isFolder()) try { ((HierarchyAdapter<CatalogNomenklatura>)list.getAdapter()).push(item); } catch (SQLException e) { e.printStackTrace(); } } }; /* * Обработчик нажатия на кнопку «UP» */ @SuppressWarnings("unchecked") private void onUpClick() { try { ((HierarchyAdapter<CatalogNomenklatura>) list.getAdapter()).pop(); } catch (SQLException e) { e.printStackTrace(); } } /* * Снять/установить дополнительный отбор по представлению */ @SuppressWarnings("unchecked") private void onFiltelClick() { String pattern = etFilter.getText().toString(); ((HierarchyAdapter<CatalogNomenklatura>) list.getAdapter()).getFilter().filter(pattern); }
MetaExpandableListAdapter
Адаптер двухуровневого списка. Функционально похож на MetaArrayAdapter, обладает теме же достоинствами и недостатками.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | //Инициализация данных для примера //Выбрать иерархически все элементы справочника CatalogNomenklaturaDao daoSku = getHelper().getDao(CatalogNomenklatura.class); GenericTree<CatalogNomenklatura> tree = daoSku.selectHierarchically(); //список групп верхнего уровня ArrayList<CatalogNomenklatura> groupData = new ArrayList<CatalogNomenklatura>(); //‘Соответствие’ группа -> список дочерних элементов HashMap<CatalogNomenklatura,List<CatalogNomenklatura>> childData = new HashMap<CatalogNomenklatura, List<CatalogNomenklatura>>(); //перебор только одного уровня GenericTreeNode<CatalogNomenklatura> root = tree.getRoot(); for (GenericTreeNode<CatalogNomenklatura> folder : root.getChildren()) { //пустой список дочерних элементов ArrayList<CatalogNomenklatura> lstChild = new ArrayList<CatalogNomenklatura>(0); if(folder.hasChildren()){ for (GenericTreeNode<CatalogNomenklatura> child : folder.getChildren()) { lstChild.add(child.getData()); } childData.put(folder.getData(), lstChild); groupData.add(folder.getData()); } } |
//Инициализация данных для примера //Выбрать иерархически все элементы справочника CatalogNomenklaturaDao daoSku = getHelper().getDao(CatalogNomenklatura.class); GenericTree<CatalogNomenklatura> tree = daoSku.selectHierarchically(); //список групп верхнего уровня ArrayList<CatalogNomenklatura> groupData = new ArrayList<CatalogNomenklatura>(); //‘Соответствие’ группа -> список дочерних элементов HashMap<CatalogNomenklatura,List<CatalogNomenklatura>> childData = new HashMap<CatalogNomenklatura, List<CatalogNomenklatura>>(); //перебор только одного уровня GenericTreeNode<CatalogNomenklatura> root = tree.getRoot(); for (GenericTreeNode<CatalogNomenklatura> folder : root.getChildren()) { //пустой список дочерних элементов ArrayList<CatalogNomenklatura> lstChild = new ArrayList<CatalogNomenklatura>(0); if(folder.hasChildren()){ for (GenericTreeNode<CatalogNomenklatura> child : folder.getChildren()) { lstChild.add(child.getData()); } childData.put(folder.getData(), lstChild); groupData.add(folder.getData()); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | /////////////////////////////////////////////////////////////////////////////////////// //1. Отображает только группы справочника верхнего уровня и подчинённые элементы по ним (только один уровень вниз). //Используется предопределенный макет и предопределённые идентификаторы для дочерних элементов MetaExpandableListAdapter<CatalogNomenklatura> mela = new MetaExpandableListAdapter<CatalogNomenklatura>( this, CatalogNomenklatura.class, groupData, android.R.layout.simple_expandable_list_item_1, new String[] { "Description" }, new int[] { android.R.id.text1 }, childData, android.R.layout.simple_expandable_list_item_2, new String[] { "Description" }, new int[] { android.R.id.text1 }); expandableList = (ExpandableListView) findViewById(R.id.expandableListView1); expandableList.setAdapter(mela); |
/////////////////////////////////////////////////////////////////////////////////////// //1. Отображает только группы справочника верхнего уровня и подчинённые элементы по ним (только один уровень вниз). //Используется предопределенный макет и предопределённые идентификаторы для дочерних элементов MetaExpandableListAdapter<CatalogNomenklatura> mela = new MetaExpandableListAdapter<CatalogNomenklatura>( this, CatalogNomenklatura.class, groupData, android.R.layout.simple_expandable_list_item_1, new String[] { "Description" }, new int[] { android.R.id.text1 }, childData, android.R.layout.simple_expandable_list_item_2, new String[] { "Description" }, new int[] { android.R.id.text1 }); expandableList = (ExpandableListView) findViewById(R.id.expandableListView1); expandableList.setAdapter(mela);
Описание параметров используемого конструктора см. в документации
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | //2. Верхний уровень групп как и в примере 1, но с форматированием, //для дочерних элементов кастомное оформление MetaAdapterViewBinder groupBinder = new MetaAdapterViewBinder( this, CatalogNomenklatura.class, new String[] { CatalogNomenklatura.FIELD_NAME_DESCRIPTION }, new int[] { android.R.id.text1 }); groupBinder.setFieldFormatter(new FieldFormatter.Builder() .setStringFormat(":%s").create()); MetaAdapterViewBinder childBinder = new MetaAdapterViewBinder( this, CatalogNomenklatura.class, new String[] { CatalogNomenklatura.FIELD_NAME_DESCRIPTION, CatalogNomenklatura.FIELD_NAME_VID_NOMENKLATURI, CatalogNomenklatura.FIELD_NAME_FOLDER}, new int[] { R.id.tvCaption, R.id.tvOther, R.id.checkBox1 }); childBinder.setViewBinder(skuViewBinder); childBinder.setFieldFormatter(new FieldFormatter.Builder().setNullFormat("<>").create()); MetaExpandableListAdapter<CatalogNomenklatura> mela = new MetaExpandableListAdapter<CatalogNomenklatura>( groupData, android.R.layout.simple_expandable_list_item_1, groupBinder, childData, R.layout.test_row_sku2, childBinder); expandableList = (ExpandableListView) findViewById(R.id.expandableListView1); expandableList.setAdapter(mela); |
//2. Верхний уровень групп как и в примере 1, но с форматированием, //для дочерних элементов кастомное оформление MetaAdapterViewBinder groupBinder = new MetaAdapterViewBinder( this, CatalogNomenklatura.class, new String[] { CatalogNomenklatura.FIELD_NAME_DESCRIPTION }, new int[] { android.R.id.text1 }); groupBinder.setFieldFormatter(new FieldFormatter.Builder() .setStringFormat(":%s").create()); MetaAdapterViewBinder childBinder = new MetaAdapterViewBinder( this, CatalogNomenklatura.class, new String[] { CatalogNomenklatura.FIELD_NAME_DESCRIPTION, CatalogNomenklatura.FIELD_NAME_VID_NOMENKLATURI, CatalogNomenklatura.FIELD_NAME_FOLDER}, new int[] { R.id.tvCaption, R.id.tvOther, R.id.checkBox1 }); childBinder.setViewBinder(skuViewBinder); childBinder.setFieldFormatter(new FieldFormatter.Builder().setNullFormat("<>").create()); MetaExpandableListAdapter<CatalogNomenklatura> mela = new MetaExpandableListAdapter<CatalogNomenklatura>( groupData, android.R.layout.simple_expandable_list_item_1, groupBinder, childData, R.layout.test_row_sku2, childBinder); expandableList = (ExpandableListView) findViewById(R.id.expandableListView1); expandableList.setAdapter(mela);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | /* * кастомное форматирование поля,связь элементов отображения с данными (обработчики событий изменения) */ private MetaAdapterViewBinder.ViewBinder skuViewBinder = new MetaAdapterViewBinder.ViewBinder() { @Override public boolean setViewValue(View v, Cursor cursor, Field field) { return false; } @Override public boolean setViewValue(View v, Object item, Field field) { CatalogNomenklatura ref = (CatalogNomenklatura) item; //Покажем код и в скобках наименование final String name = field.getName(); if(CatalogNomenklatura.FIELD_NAME_DESCRIPTION.equalsIgnoreCase(name)){ ((TextView)v).setText(ref.getCode() + " (" + ref.getDescription()+")"); return true; } return false; } @Override public BaseViewHolder createViewHolder(View root) { SkuViewHolder holder = new SkuViewHolder(root); holder.checkBox1.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { CheckBox cb = (CheckBox) v; int pos = (Integer) cb.getTag(); Dbg.log(TAG+"checkBox1.OnClick, pos = " +pos ); //добавить обработчик по клику } }); return holder; } @Override public void onBind(BaseViewHolder viewHolder, int position) { SkuViewHolder holder = (SkuViewHolder) viewHolder; holder.checkBox1.setTag(position); } }; /* * ViewHolder паттерн для эффективной работы со строками адаптеров */ private static class SkuViewHolder extends BaseViewHolder { private TextView tvCaption; private TextView tvOther; private CheckBox checkBox1; public SkuViewHolder(View root) { super(root); tvCaption = (TextView) root.findViewById(R.id.tvCaption); tvOther = (TextView) root.findViewById(R.id.tvOther); checkBox1 = (CheckBox) root.findViewById(R.id.checkBox1); } @Override public View getViewById(int id) { switch(id){ case R.id.tvCaption: return tvCaption; case R.id.tvOther: return tvOther; case R.id.checkBox1: return checkBox1; } return null; } } |
/* * кастомное форматирование поля,связь элементов отображения с данными (обработчики событий изменения) */ private MetaAdapterViewBinder.ViewBinder skuViewBinder = new MetaAdapterViewBinder.ViewBinder() { @Override public boolean setViewValue(View v, Cursor cursor, Field field) { return false; } @Override public boolean setViewValue(View v, Object item, Field field) { CatalogNomenklatura ref = (CatalogNomenklatura) item; //Покажем код и в скобках наименование final String name = field.getName(); if(CatalogNomenklatura.FIELD_NAME_DESCRIPTION.equalsIgnoreCase(name)){ ((TextView)v).setText(ref.getCode() + " (" + ref.getDescription()+")"); return true; } return false; } @Override public BaseViewHolder createViewHolder(View root) { SkuViewHolder holder = new SkuViewHolder(root); holder.checkBox1.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { CheckBox cb = (CheckBox) v; int pos = (Integer) cb.getTag(); Dbg.log(TAG+"checkBox1.OnClick, pos = " +pos ); //добавить обработчик по клику } }); return holder; } @Override public void onBind(BaseViewHolder viewHolder, int position) { SkuViewHolder holder = (SkuViewHolder) viewHolder; holder.checkBox1.setTag(position); } }; /* * ViewHolder паттерн для эффективной работы со строками адаптеров */ private static class SkuViewHolder extends BaseViewHolder { private TextView tvCaption; private TextView tvOther; private CheckBox checkBox1; public SkuViewHolder(View root) { super(root); tvCaption = (TextView) root.findViewById(R.id.tvCaption); tvOther = (TextView) root.findViewById(R.id.tvOther); checkBox1 = (CheckBox) root.findViewById(R.id.checkBox1); } @Override public View getViewById(int id) { switch(id){ case R.id.tvCaption: return tvCaption; case R.id.tvOther: return tvOther; case R.id.checkBox1: return checkBox1; } return null; } }
В примере для демонстрации возможностей форматирования на первом уровне перед наименованием выводим двоеточие, а на второй уровне дня незаполненных реквизитов выводим “<>”.
Если возможностей FieldFormatter недостаточно, можно вообще переопределить вывод данных для элемента – в примере выводится код и наименование вместе. Так же показана установка обработчика на элемент управления CheckBox.
ParentExpandableCursorAdapter
Адаптер двухуровневого списка на базе курсора, используется для иерархических справочников. В отличие от MetaExpandableListAdapter, где вы сами определяете состав дочерних элементов, здесь передается курсор с данными группировки только верхнего уровня, курсор для выбора дочерних элементов создается автоматически при «раскрытии группы».
Сортировка дочерних элементов может быть задана через метод setOrderChild.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | //Из справочника «Номенклатура» выбрать только группы верхнего уровня CatalogNomenklaturaDao daoSku = getHelper().getDao(CatalogNomenklatura.class); HashMap<String,Object> filter = new HashMap<String, Object>(); filter.put(Catalog.FIELD_NAME_LEVEL, 0); filter.put(Catalog.FIELD_NAME_FOLDER, true); //Курсор для групп верхнего уровня Cursor cursorParent = daoSku.selectCursor(filter, Catalog.FIELD_NAME_DESCRIPTION); startManagingCursor(cursorParent); //Выводим только наименование, макет стандартный для раскрывающихся списков MetaAdapterViewBinder groupBinder = new MetaAdapterViewBinder( this, CatalogNomenklatura.class, new String[] { CatalogNomenklatura.FIELD_NAME_DESCRIPTION }, new int[] { android.R.id.text1 }); ParentExpandableCursorAdapter<CatalogNomenklatura> peca = new ParentExpandableCursorAdapter<CatalogNomenklatura>( this, daoSku, cursorParent, android.R.layout.simple_expandable_list_item_1, groupBinder); peca.setOrderChild(Catalog.FIELD_NAME_DESCRIPTION); expandableList = (ExpandableListView) findViewById(R.id.expandableListView1); expandableList.setAdapter(peca); //обработчики выбора expandableList.setOnGroupClickListener(onGroupClickListener); expandableList.setOnChildClickListener(onChildClickListener); |
//Из справочника «Номенклатура» выбрать только группы верхнего уровня CatalogNomenklaturaDao daoSku = getHelper().getDao(CatalogNomenklatura.class); HashMap<String,Object> filter = new HashMap<String, Object>(); filter.put(Catalog.FIELD_NAME_LEVEL, 0); filter.put(Catalog.FIELD_NAME_FOLDER, true); //Курсор для групп верхнего уровня Cursor cursorParent = daoSku.selectCursor(filter, Catalog.FIELD_NAME_DESCRIPTION); startManagingCursor(cursorParent); //Выводим только наименование, макет стандартный для раскрывающихся списков MetaAdapterViewBinder groupBinder = new MetaAdapterViewBinder( this, CatalogNomenklatura.class, new String[] { CatalogNomenklatura.FIELD_NAME_DESCRIPTION }, new int[] { android.R.id.text1 }); ParentExpandableCursorAdapter<CatalogNomenklatura> peca = new ParentExpandableCursorAdapter<CatalogNomenklatura>( this, daoSku, cursorParent, android.R.layout.simple_expandable_list_item_1, groupBinder); peca.setOrderChild(Catalog.FIELD_NAME_DESCRIPTION); expandableList = (ExpandableListView) findViewById(R.id.expandableListView1); expandableList.setAdapter(peca); //обработчики выбора expandableList.setOnGroupClickListener(onGroupClickListener); expandableList.setOnChildClickListener(onChildClickListener);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | /* * Обработчик нажатия на группу верхнего уровня */ private OnGroupClickListener onGroupClickListener = new OnGroupClickListener() { @Override public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) { CursorTreeAdapter adapter = (CursorTreeAdapter) parent.getExpandableListAdapter(); Cursor c = adapter.getCursor(); handleItem(c,id); return false; } }; /*Обработчик нажатия на дочерний элемент */ private OnChildClickListener onChildClickListener = new OnChildClickListener() { @Override public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) { CursorTreeAdapter adapter = (CursorTreeAdapter) parent.getExpandableListAdapter(); Cursor c = adapter.getChild(groupPosition, childPosition); handleItem(c,id); return true; } }; protected void handleItem(Cursor c, long id) { int columnIndex = c.getColumnIndex(Catalog.FIELD_NAME_REF); if (columnIndex != -1) { String ref = c.getString(columnIndex); Dbg.log(TAG + " SKU ref = " + ref); // Теперь по идентификатору например можно найти элемент b выполнить // какие-либо действия с ним } } |
/* * Обработчик нажатия на группу верхнего уровня */ private OnGroupClickListener onGroupClickListener = new OnGroupClickListener() { @Override public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) { CursorTreeAdapter adapter = (CursorTreeAdapter) parent.getExpandableListAdapter(); Cursor c = adapter.getCursor(); handleItem(c,id); return false; } }; /*Обработчик нажатия на дочерний элемент */ private OnChildClickListener onChildClickListener = new OnChildClickListener() { @Override public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) { CursorTreeAdapter adapter = (CursorTreeAdapter) parent.getExpandableListAdapter(); Cursor c = adapter.getChild(groupPosition, childPosition); handleItem(c,id); return true; } }; protected void handleItem(Cursor c, long id) { int columnIndex = c.getColumnIndex(Catalog.FIELD_NAME_REF); if (columnIndex != -1) { String ref = c.getString(columnIndex); Dbg.log(TAG + " SKU ref = " + ref); // Теперь по идентификатору например можно найти элемент b выполнить // какие-либо действия с ним } }
Рассмотрены все адаптеры, входящие в состав FBA. Какой из них использовать зависит от конкретной задачи. Однако наиболее полно возможности этих адаптеров раскрываются при совместном использовании с контролами FieldCheckBox, FieldToggleButton, FieldPresentationSpinner и другими классами Field<> из пакета ru.profi1c.engine.widget. В одной из следующих статей покажем как с ними работать.