Лучший способ реализовать эффект прокрутки на основе положения

#android

#Android

Вопрос:

Я написал пользовательский View , давайте назовем его CustomListView который расширяет LinearLayout . CustomListView Использует Adapter для создания своих дочерних элементов. Я также реализовал поведение, при котором дочерний элемент отображается по-другому, когда он расположен определенным образом — например, когда вы прокручиваете список, фон дочернего элемента, который в данный момент виден вверху списка, становится прозрачным. Так, например:

Запуск:

  ----------------------------- 
| child 1 (transparent bg)    |
 ----------------------------- 
| child 2 (visible)           |
 ----------------------------- 
| child 3 (visible)           |
 ----------------------------- 
| child 4 (visible)           |
 ----------------------------- 
| child 5 (visible)           |
 ----------------------------- 
| child 6 (visible)           |
 ----------------------------- 
  

После прокрутки вниз до того места, где дочерний элемент 3 находится вверху списка:

  ----------------------------- 
| child 3 (transparent bg)    |
 ----------------------------- 
| child 4 (visible)           |
 ----------------------------- 
| child 5 (visible)           |
 ----------------------------- 
| child 6 (visible)           |
 ----------------------------- 
| child 7 (visible)           |
 ----------------------------- 
| child 8 (visible)           |
 ----------------------------- 
  

Проблема в том, что я не очень доволен тем, как я этого добился. На данный момент я делаю это, создавая пользовательский View , CustomListViewChild который наследуется от RelativeLayout и который я использую в качестве корневого представления для каждого дочернего элемента. Это важная часть реализации CustomListViewChild :

 public final class CustomListViewChild extends RelativeLayout {

    private OnScrolledToListener onScrolledToListener;
    private OnScrolledFromListener onScrolledFromListener;

    /**
     * Called when this {@link CustomListViewChild} has been scrolled to (i.e. it is now at the top of the
     * {@link CustomListView})
     */
    public void scrollTo() {
        if (onScrolledToListener != null) {
            onScrolledToListener.onScrolledTo();
        }
    }

    /**
     * Called when this {@link CustomListViewChild} has been scrolled from (i.e. it is no longer at the
     * top of the {@link CustomListView})
     */
    public void scrollFrom() {
        if (onScrolledFromListener != null) {
            onScrolledFromListener.onScrolledFrom();
        }
    }

    /**
     * @param onScrolledToCallback a listener to be called when this {@link CustomListViewChild} is
     *            scrolled to (i.e. the scroll of the {@link CustomListView} has come to an end with this
     *            {@link CustomListViewChild} at the top).
     */
    public void setOnScrolledToListener(OnScrolledToListener onScrolledToCallback) {
        this.onScrolledToListener = onScrolledToCallback;
    }

    /**
     * @param onScrolledFromCallback a listener to be called when this view is scrolled away from
     *            (i.e. this was previously the top {@link CustomListViewChild} in the {@link CustomListView}
     *            but now the user has scrolled away from it.)
     */
    public void setOnScrolledFromListener(OnScrolledFromListener onScrolledFromCallback) {
        this.onScrolledFromListener = onScrolledFromCallback;
    }

    /**
     * An interface used to listen for when this {@link CustomListViewChild} has been scrolled to.
     */
    public interface OnScrolledToListener {
        /**
         * Method called when this {@link CustomListViewChild} has been scrolled to.
         */
        void onScrolledTo();
    }

    /**
     * An interface used to listen for when this {@link CustomListViewChild} has been scrolled from.
     */
    public interface OnScrolledFromListener {
        /**
         * Method called when this {@link CustomListViewChild} has been scrolled from.
         */
        void onScrolledFrom();
    }
}
  

Затем, в моем Adapter :

 if (convertView instanceof CustomListViewChild) {
    ((CustomListViewChild) convertView).setOnScrolledFromListener(new OnScrolledFromListener() {

        @Override
        public void onScrolledFrom() {
            viewHolder.screenshot.setVisibility(View.VISIBLE);
        }
    });
    ((CustomListViewChild) convertView).setOnScrolledToListener(new OnScrolledToListener() {

        @Override
        public void onScrolledTo() {
            viewHolder.screenshot.setVisibility(View.GONE);
        }
    });
}
  

Хотя это кажется хакерским и не расширяемым. Если я когда-нибудь решу завести дочерний элемент с другим типом макета (скажем, LinearLayout ), мне пришлось бы предоставить другой пользовательский класс или, в идеале, придумать способ сделать это с помощью интерфейса… давайте просто скажем, что это не идеально.

Другой подход, о котором я буквально только что подумал, заключается в том, что я CustomListViewAdapter предоставляю обратные вызовы для CustomListView , которые будут вызываться при View прокрутке к или от. На самом деле это уже кажется немного лучше, но я не уверен, нарушает ли это Adapter s абстракцию. Мне любопытно, есть ли какие-либо другие подходы, которые я не рассматривал.