Визуальная индикация над прокруткой в ​​android

Я пытаюсь добавить визуальную индикацию, что в ViewPager больше нет страниц в желаемом направлении fling. Однако я изо всех сил пытаюсь найти место, куда поместить соответствующий код.

Я попытался расширить класс ViewPager со следующим кодом, но Toast не отображается (ev.getOrientation() всегда возвращает 0). Я также пробовал то же самое с историческими точками, но ev.getHistorySize() возвращает также 0.

Что мне не хватает?

Пример класса:

public class CustomViewPager extends ViewPager {

    public CustomViewPager(Context context) {
        super(context);
    }

    public CustomViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    /**
     * @see android.support.v4.view.ViewPager#onTouchEvent(android.view.MotionEvent)
     */
    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        boolean result = super.onTouchEvent(ev);

        switch (ev.getAction() & MotionEventCompat.ACTION_MASK) {
            case MotionEvent.ACTION_MOVE:
                if (ev.getOrientation() > 0) {
                    Toast.makeText(getContext(), "left", 0).show();
                }
        }

        return result;
    }
}

Ответ 1

Если вы посмотрите на библиотеку поддержки v4, вы увидите там класс, используемый ViewPager под названием EdgeEffectCompat (это обеспечивает эффект свечения, когда вы достигаете начала или конец представления пейджера в ICS +). Если вы посмотрите на реализацию в библиотеке сопоставлений, вы увидите, что у нее есть if-statement, чтобы увидеть, является ли версия сборки 14+ (ICS) или нет. Если это так, то это заканчивается (если вы достаточно долго тратите), используя обычный класс EdgeEffect, который был введен в ICS. В противном случае он использует BaseEdgeEffectImpl, который в основном ничего не имеет.

Если вы хотите, вы можете создать свой собственный ViewPager, который использует собственный EdgeEffect. Вы можете посмотреть исходный код Android, чтобы увидеть, как они реализовали EdgeEffect здесь, который вы можете копировать довольно просто (просто убедитесь, что вы скопировали overscroll_edge и overscroll_glow в каталогах AOSP/res/drawable в ваш собственный проект, поскольку они являются внутренними для Android) или идти вперед и создайте свою собственную версию.

Удачи.

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

Ответ 2

Я пытался получить тот же эффект, который был задан в этом вопросе. Я борюсь с этим, а затем я прочитал ответ @wnafee (я не мог этого сделать).

Но потом я изо всех сил пытаюсь реализовать то, что было довольно просто от ответа. У меня было так много проблем с его внедрением, что я мог неправильно понять ответ, но было слишком много проблем с недоступными API, так как я не работал в одном пакете библиотеки совместимости.

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

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

Чтобы выполнить эту задачу, вы должны просто следовать моему решению по трем частям. (Возьмет вас между 3-10 минутами)

Часть I:

Как сказал Wnafee, я просто создал свой собственный класс EdgeEffect, скопировав его исходный код здесь,

(просто убедитесь, что вы скопировали overscroll_edge и overscroll_glow чертежи в каталогах AOSP/res/drawable для вашего собственного проекта поскольку они являются внутренними для android)

Я сделал только 2 очень небольших изменения:

  • Объявляю, что класс расширяет EdgeEffectCompat (я назвал свой класс EdgeEffectForEarlyVersions). public class EdgeEffectForEarlyVersions extends EdgeEffectCompat. Причина этого изменения заключается в том, что mLeftEdge и mRightEdge имеют тип EdgeEffectCompat.
  • В первой строке конструктора "моего" нового класса я добавил вызов родительскому конструктору super(context);. Поскольку конструктор по умолчанию для EdgeEffectCompat отсутствует, вам нужно явно вызвать конструктор.

Часть II

Кроме того, я написал другую функцию. Цель этой функции заключается в том, что в случае ранней версии (до ICS) мы хотели бы использовать EdgeEffectForEarlyVersions, который мы только что скопировали. Для достижения этой цели я использовал отражение.

Это функция:

private static void changeEdgeEffectCompactOnEarlyVersions(ViewPager viewPager, Context context)
{
    /* In case that the version is earlier than 14 there is only empty implementation for the edge effect, therefore we change it.
     * for more information look on the following links:
     * 1. http://stackoverflow.com/questions/10773565/visual-indication-of-over-scroll-in-android
     * 2. http://grepcode.com/file/repo1.maven.org/maven2/com.google.android/support-v4/r7/android/support/v4/view/ViewPager.java#ViewPager.0mLeftEdge
     * 3. http://grepcode.com/file/repo1.maven.org/maven2/com.google.android/support-v4/r7/android/support/v4/widget/EdgeEffectCompat.java#EdgeEffectCompat
     */

    if (Build.VERSION.SDK_INT < 14)
    {
        try
        {
            Class<ViewPager> viewPagerClass = ViewPager.class;
            //Get the left edge field, since it is private we used getDeclaredField and not getDeclared 
            Field leftEdge = viewPagerClass.getDeclaredField("mLeftEdge");
            leftEdge.setAccessible(true);
            //Get the right edge field, since it is private we used getDeclaredField and not getDeclared
            Field rightEdge = viewPagerClass.getDeclaredField("mRightEdge");
            rightEdge.setAccessible(true);

            EdgeEffectForEarlyVersions leftEdgeEffect = new EdgeEffectForEarlyVersions(context);
            EdgeEffectForEarlyVersions rightEdgeEffect = new EdgeEffectForEarlyVersions(context);

            //Set the mLeftEdge memeber of viewPager not to be the default one, but to be "our" edgeEffect  
            leftEdge.set(viewPager, leftEdgeEffect);
            //Set the mRightEdge memeber of viewPager not to be the default one, but to be "our" edgeEffect
            rightEdge.set(viewPager, rightEdgeEffect);              
        }
        catch (Exception ex)
        {
            Log.e("refelection", ex.getMessage());
        }

    }
}

Часть III

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

Надеюсь, это поможет кому-то.

Ответ 4

У вас есть много вариантов, вы можете показать Toast, отобразить диалоговое окно, сделать TextView или изображение появляться над вашим пользовательским интерфейсом и т.д. Или, поскольку вы знаете количество элементов View в ViewPager, вы можете добавить разные Просмотрите в позициях 0 и/или n + 1 сообщение и сделайте его отскоком к последнему виду, которое фактически содержит ваши данные.

Вы можете реализовать:

viewPager.setOnPageChangeListener(new OnPageChangeListener() {
    public void onPageSelected(int position) {
        //TODO If position is the 0 or n item, add a view at 0 or at n+1 to indicate there is no more pages with data.
    }

    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        // TODO Show a Toast, View or do anything you want when position = your first/last  item;
    }

    public void onPageScrollStateChanged(int state) {
    }
});

Ответ 5

просто для дополнения ответа @goBeepit dev, когда вы создаете свой собственный класс edgeffect, и вы расширяетесь от EdgeEffectCompat, некоторые методы требуют булевых. вы можете изменить эти методы на boolean type и make, а затем вернуть true в любом случае, таким образом, все работает отлично

Ответ 6

Вы можете перегрузить функцию setUserVisibleHint (boolean) в своих фрагментах. Псевдокод:

    void setUserVisibleHint(boolean isVisibleToUser) {
        // If this fragment is becoming visible
        if (isVisibleToUser == true) {
             // Check if it is the last fragment in the viewpager
             if (indexOfThis == getActivity().indexOfLast) {
                // Display right limit reached
                Toast(..., "No more Frags to right",...)
                }
             // Check if it is the first fragment in the viewpager
             else if (indexOfThis == getActivity().indexOfFirst) {
                // Display Left Limit reached
                Toast(..., "No more Frags to left",...)
             }
        }
    }

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

Ответ 8

Обычно с ViewPager используется PagerAdapter, например FragmentPagerAdapter или FragmentStatePagerAdapter, чтобы наполнить ViewPager содержимым (ваш контент будет отображаться).

Теперь, когда вы используете PagerAdapter, у вас есть один метод под названием getCount(), http://developer.android.com/reference/android/support/v4/view/PagerAdapter.html#getCount%28%29, который даст вам размер содержимого.

Поскольку вы теперь знаете размер, вы можете легко отобразить сообщение с помощью инструкции if.

Попробуйте этот код: http://developer.android.com/reference/android/support/v4/view/ViewPager.html

Примечание. Я не думаю, что вам нужен пользовательский ViewPager. Вам также нужно будет понять фрагменты для ViewPager. Посмотрите образцы в ApiDemos. Это отличный источник.