PinnedHeader Google плюс GridView?

Фон

Приложение Google plus (google +) имеет приятный просмотр изображений в категории "Основные моменты".

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

Вот как это выглядит:

enter image description here

Здесь еще одно обновленное изображение: ссылка.

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

Проблема

Мне нужно иметь аналогичный просмотр фотографий (включая кнопки /s в заголовках), но также сделать видимым верхний заголовок (AKA "закрепленный заголовок", например, на этот проект).

На самом деле мне все равно, будет ли оно закреплено (хотя это может быть приятной особенностью).

Что я пробовал

Я нашел только 2 библиотеки, которые привязали заголовок gridViews:

  • StickyGridHeaders - это казалось прекрасным. API и дизайн кода очень приятные. Тем не менее, я играл с ним на некоторых устройствах и обнаружил, что он сбой с очень странным исключением. я сообщил об этом здесь, но, глядя на другие проблемы, я думаю, что этот проект выиграл ' t будет исправлено в ближайшее время.

  • AStickyHeader - у этого нет никаких сбоев и ошибок, которые я могу найти, но ему не хватает хорошего дизайна кода, и он не так настраивается. заголовок не может быть нажат, и у него не может быть кнопки, например, в Google-плюсе. Я попытался добавить его, но по какой-то причине кнопка не отображается. Я сообщил о своих замечаниях по этому поводу здесь.

Вопрос

Есть ли кто-нибудь, кто пытался справиться с такой ситуацией?

Доступна любая библиотека или модификация библиотек, которые я пытался, чтобы иметь то, что я написал?

Ответ 1

так как я не могу найти какое-либо другое решение, я решил сделать свое собственное решение (код на основе другого кода, который я сделал, здесь)

он используется вместо ListView, но он работает очень хорошо. вы просто устанавливаете адаптер в listView, и вам хорошо идти. вы можете точно определить, как выглядят заголовки и как выглядит каждая ячейка.

он работает, имея 2 типа строк: header-rows и cells-rows.

это не лучшее решение, так как оно создает дополнительные представления вместо того, чтобы ListView/GridView (или что-то, что вы используете) правильно помещал ячейки, но он отлично работает и не разбивается

он также не имеет элементов, которые нажимают (так как это для listView), но его не должно быть сложно добавить для тех, кто использует этот код.

К сожалению, у него также нет заголовка в качестве закрепленного заголовка, но, возможно, его можно использовать с этой библиотеки (PinnedHeaderListView).

здесь код:

public abstract class HeaderGridedListViewAdapter<SectionData, ItemType> extends BaseAdapter {
    private static final int TYPE_HEADER_ROW = 0;
    private static final int TYPE_CELLS_ROW = 1;
    private final int mNumColumns;
    private final List<Row<SectionData, ItemType>> mRows = new ArrayList<Row<SectionData, ItemType>>();
    private final int mCellsRowHeight;
    private final Context mContext;

    public HeaderGridedListViewAdapter(final Context context, final List<Section<SectionData, ItemType>> sections,
            final int numColumns, final int cellsRowHeight) {
        this.mContext = context;
        this.mNumColumns = numColumns;
        this.mCellsRowHeight = cellsRowHeight;
        for (final Section<SectionData, ItemType> section : sections) {
            // add header
            Row<SectionData, ItemType> row = new Row<SectionData, ItemType>();
            row.section = section;
            row.type = TYPE_HEADER_ROW;
            mRows.add(row);
            int startIndex = 0;
            // add section rows
            for (int cellsLeft = section.getItemsCount(); cellsLeft > 0;) {
                row = new Row<SectionData, ItemType>();
                row.section = section;
                row.startIndex = startIndex;
                row.type = TYPE_CELLS_ROW;
                cellsLeft -= Math.min(mNumColumns, cellsLeft);
                startIndex += mNumColumns;
                mRows.add(row);
            }
        }
    }

    @Override
    public int getViewTypeCount() {
        return 2;
    }

    @Override
    public int getItemViewType(final int position) {
        return getItem(position).type;
    }

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

    @Override
    public Row<SectionData, ItemType> getItem(final int position) {
        return mRows.get(position);
    }

    @Override
    public long getItemId(final int position) {
        return position;
    }

    @Override
    public View getView(final int position, final View convertView, final ViewGroup parent) {
        final Row<SectionData, ItemType> item = getItem(position);
        switch (item.type) {
        case TYPE_CELLS_ROW:
            LinearLayout rowLayout = (LinearLayout) convertView;
            if (rowLayout == null) {
                rowLayout = new LinearLayout(mContext);
                rowLayout.setOrientation(LinearLayout.HORIZONTAL);
                rowLayout.setLayoutParams(new AbsListView.LayoutParams(LayoutParams.MATCH_PARENT, mCellsRowHeight));
                rowLayout.setWeightSum(mNumColumns);
            }
            final int childCount = rowLayout.getChildCount();
            // reuse previous views of the row if possible
            for (int i = 0; i < mNumColumns; ++i) {
                // reuse old views if possible
                final View cellConvertView = i < childCount ? rowLayout.getChildAt(i) : null;
                // fill cell with data
                final View cellView = getCellView(item.section, item.startIndex + i, cellConvertView, rowLayout);

                LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) cellView.getLayoutParams();
                if (layoutParams == null) {
                    layoutParams = new LinearLayout.LayoutParams(0, mCellsRowHeight, 1);
                    cellView.setLayoutParams(layoutParams);
                } else {
                    final boolean needSetting = layoutParams.weight != 1 || layoutParams.width != 0
                            || layoutParams.height != mCellsRowHeight;
                    if (needSetting) {
                        layoutParams.width = 0;
                        layoutParams.height = mCellsRowHeight;
                        layoutParams.weight = 1;
                        cellView.setLayoutParams(layoutParams);
                    }
                }
                if (cellConvertView == null)
                    rowLayout.addView(cellView);
            }
            return rowLayout;
        case TYPE_HEADER_ROW:
            return getHeaderView(item.section, convertView, parent);
        }
        throw new UnsupportedOperationException("cannot create this type of row view");
    }

    @Override
    public boolean areAllItemsEnabled() {
        return false;
    }

    @Override
    public boolean isEnabled(final int position) {
        return false;
    }

    /** should handle getting a single header view */
    public abstract View getHeaderView(Section<SectionData, ItemType> section, View convertView, ViewGroup parent);

    /**
     * should handle getting a single cell view. <br/>
     * NOTE:read the parameters description carefully !
     * 
     * @param section
     *            the section that this cell belongs to
     * @param positionWithinSection
     *            the position within the section that we need to fill the data with. note that if it larger than what
     *            the section can give you, it means we need an empty cell (same the the others, but shouldn't show
     *            anything, can be invisible if you wish)
     * @param convertView
     *            a recycled row cell. you must use it when it not null, and fill it with data
     * @param parent
     *            the parent of the view. you should use it for inflating the view (but don't attach the view to the
     *            parent)
     */
    public abstract View getCellView(Section<SectionData, ItemType> section, int positionWithinSection,
            View convertView, ViewGroup parent);

    // ////////////////////////////////////
    // Section//
    // /////////
    public static class Section<SectionData, ItemType> {
        private final List<ItemType> mItems;
        private final SectionData mSectionData;

        public Section(final SectionData sectionData, final List<ItemType> items) {
            this.mSectionData = sectionData;
            this.mItems = items;
        }

        public SectionData getSectionData() {
            return mSectionData;
        }

        public int getItemsCount() {
            return mItems.size();
        }

        public ItemType getItem(final int posInSection) {
            return mItems.get(posInSection);
        }

        @Override
        public String toString() {
            return mSectionData;
        }
    }

    // ////////////////////////////////////
    // Row//
    // /////
    private static class Row<SectionData, ItemType> {
        int type, startIndex;
        Section<SectionData, ItemType> section;
    }
}