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

роблема тесно связана с двумя другими вопросами, на которые еще не ответили.

ViewPager не отвечает на прикосновения в области макета, созданной динамически во фрагменте

https://stackoverflow.com/questions/53469581/problem-with-vertical-viewpager-like-inshorts

Мой Vertical ViewPager прекрасно и стабильно работает на любом устройстве, которое я тестировал, и на любой ОС 5–8. Недавно я обновил пиксель 2XL с Android Pie, и теперь мой Vertical ViewPager, кажется, не отвечает, затем работает, затем он работает так, как будто теряет фокус потом работает. Перетащите страницу, и она переместится и вернется в исходное положение. Или просто приходит в норму. Опять же, похоже на два других вопроса, связанных выше.

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

Активность

public class FullscreenActivity extends AppCompatActivity {

VerticalViewPager verticalViewPager;
FragmentStatePagerExample fragmentStatePagerExample;

int pagerPadding;

/**
 * Whether or not the system UI should be auto-hidden after
 * {@link #AUTO_HIDE_DELAY_MILLIS} milliseconds.
 */
private static final boolean AUTO_HIDE = true;

/**
 * If {@link #AUTO_HIDE} is set, the number of milliseconds to wait after
 * user interaction before hiding the system UI.
 */
private static final int AUTO_HIDE_DELAY_MILLIS = 3000;

/**
 * Some older devices needs a small delay between UI widget updates
 * and a change of the status and navigation bar.
 */
private static final int UI_ANIMATION_DELAY = 300;
private final Handler mHideHandler = new Handler();
private FrameLayout mContentView;

private final Runnable mHidePart2Runnable = new Runnable() {
    @SuppressLint("InlinedApi")
    @Override
    public void run() {
        // Delayed removal of status and navigation bar

        // Note that some of these constants are new as of API 16 (Jelly Bean)
        // and API 19 (KitKat). It is safe to use them, as they are inlined
        // at compile-time and do nothing on earlier devices.
        verticalViewPager.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE
                | View.SYSTEM_UI_FLAG_FULLSCREEN
                | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
                | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
    }
};
private View mControlsView;
private final Runnable mShowPart2Runnable = new Runnable() {
    @Override
    public void run() {
        // Delayed display of UI elements
        ActionBar actionBar = getSupportActionBar();
        if (actionBar != null) {
            actionBar.show();
        }
        mControlsView.setVisibility(View.VISIBLE);
    }
};
private boolean mVisible;
private final Runnable mHideRunnable = new Runnable() {
    @Override
    public void run() {
        hide();
    }
};
/**
 * Touch listener to use for in-layout UI controls to delay hiding the
 * system UI. This is to prevent the jarring behavior of controls going away
 * while interacting with activity UI.
 */
private final View.OnTouchListener mDelayHideTouchListener = new View.OnTouchListener() {
    @Override
    public boolean onTouch(View view, MotionEvent motionEvent) {
        if (AUTO_HIDE) {
            delayedHide(AUTO_HIDE_DELAY_MILLIS);
        }
        return false;
    }
};

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_fullscreen);


    pagerPadding = getScreenDimension(this);

    mVisible = true;
    mControlsView = findViewById(R.id.fullscreen_content_controls);

    verticalViewPager = findViewById(R.id.main_viewpager);

    verticalViewPager.setPadding(0,0,0,pagerPadding);
    verticalViewPager.setClipToPadding(false);

    fragmentStatePagerExample = new FragmentStatePagerExample(getSupportFragmentManager());

    verticalViewPager.setAdapter(fragmentStatePagerExample);

    verticalViewPager.setCurrentItem(0);

    // Set up the user interaction to manually show or hide the system UI.
    verticalViewPager.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            toggle();
        }
    });

    // Upon interacting with UI controls, delay any scheduled hide()
    // operations to prevent the jarring behavior of controls going away
    // while interacting with the UI.
    findViewById(R.id.dummy_button).setOnTouchListener(mDelayHideTouchListener);
}

@Override
protected void onPostCreate(Bundle savedInstanceState) {
    super.onPostCreate(savedInstanceState);

    // Trigger the initial hide() shortly after the activity has been
    // created, to briefly hint to the user that UI controls
    // are available.
    delayedHide(100);
}

private void toggle() {
    if (mVisible) {
        hide();
    } else {
        show();
    }
}

private void hide() {
    // Hide UI first
    ActionBar actionBar = getSupportActionBar();
    if (actionBar != null) {
        actionBar.hide();
    }
    mControlsView.setVisibility(View.GONE);
    mVisible = false;

    // Schedule a runnable to remove the status and navigation bar after a delay
    mHideHandler.removeCallbacks(mShowPart2Runnable);
    mHideHandler.postDelayed(mHidePart2Runnable, UI_ANIMATION_DELAY);
}

@SuppressLint("InlinedApi")
private void show() {
    // Show the system bar
    mContentView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
            | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
    mVisible = true;

    // Schedule a runnable to display UI elements after a delay
    mHideHandler.removeCallbacks(mHidePart2Runnable);
    mHideHandler.postDelayed(mShowPart2Runnable, UI_ANIMATION_DELAY);
}

/**
 * Schedules a call to hide() in delay milliseconds, canceling any
 * previously scheduled calls.
 */
private void delayedHide(int delayMillis) {
    mHideHandler.removeCallbacks(mHideRunnable);
    mHideHandler.postDelayed(mHideRunnable, delayMillis);
}

private static int getScreenDimension(Context context)
{
    WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
    Display display = wm.getDefaultDisplay();
    DisplayMetrics metrics = new DisplayMetrics();
    display.getMetrics(metrics);
    int width = metrics.widthPixels;
    int height = metrics.heightPixels;

    return (int)Math.round(height * .2);
}
}

Фрагмент

public class ImageFragment extends Fragment{

ImageView imageView;

String imageUrl = "";

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
}

@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    super.onCreateView(inflater, container, savedInstanceState);

    Bundle bundle = getArguments();

    imageUrl = bundle.getString("url");

    return inflater.inflate(R.layout.fragment_image, container,false);

}

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);

    imageView = (ImageView)view.findViewById(R.id.iv_imagefragment);

    Glide.with(getActivity()).load(imageUrl).into(imageView);

}

public static Fragment getInstance(int position, String url){

    Bundle bundle = new Bundle();
    bundle.putString("url",url);
    ImageFragment fragment = new ImageFragment();
    fragment.setArguments(bundle);
    return fragment;

}
}

ViewPager

public class VerticalViewPager extends ViewPager {

public VerticalViewPager(Context context) {
    super(context);
    init();
}

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

private void init() {
    // The majority of the magic happens here
    setPageTransformer(true, new VerticalPageTransformer());
    setOffscreenPageLimit(2);
    // The easiest way to get rid of the overscroll drawing that happens on the left and right
    setOverScrollMode(OVER_SCROLL_NEVER);
}

private class VerticalPageTransformer implements ViewPager.PageTransformer {

    @Override
    public void transformPage(View view, float position) {

        if (position < -1) { // [-Infinity,-1)
            // This page is way off-screen to the left.
            view.setAlpha(0);

        } else if (position <= 1) { // [-1,1]
            view.setAlpha(1);

            // Counteract the default slide transition
            view.setTranslationX(view.getWidth() * -position);

            //set Y position to swipe in from top
            float yPosition = position * view.getHeight();
            view.setTranslationY(yPosition);

        } else { // (1,+Infinity]
            // This page is way off-screen to the right.
            view.setAlpha(0);
        }
    }
}

/**
 * Swaps the X and Y coordinates of your touch event.
 */
private MotionEvent swapXY(MotionEvent ev) {
    float width = getWidth();
    float height = getHeight();

    float newX = (ev.getY() / height) * width;
    float newY = (ev.getX() / width) * height;

    ev.setLocation(newX, newY);

    return ev;
}

@Override
public boolean onInterceptTouchEvent(MotionEvent ev){
    boolean intercepted = super.onInterceptTouchEvent(swapXY(ev));
    swapXY(ev); // return touch coordinates to original reference frame for any child views
    return intercepted;
}

@Override
public boolean onTouchEvent(MotionEvent ev) {
    return super.onTouchEvent(swapXY(ev));
}

}

Адаптер ViewPager

public class FragmentStatePagerExample extends FragmentStatePagerAdapter {

String url = "";

public FragmentStatePagerExample(FragmentManager fm) {
    super(fm);
}

@Override
public Fragment getItem(int position) {


    switch (position){
        case 0:
            url = "https://images.unsplash.com/photo-1532977692289-827d858a170b?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=29b1d5377ad9db8de64b1b73d21812c7&auto=format&fit=crop&w=1474&q=80";
            return ImageFragment.getInstance(position,url);
        case 1:
            url = "https://images.unsplash.com/photo-1533029516911-0458c644baea?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=0f618e036e338f48ef919b8fb86c5ba1&auto=format&fit=crop&w=701&q=80";
            return ImageFragment.getInstance(position,url);
        case 2:
            url = "https://images.unsplash.com/photo-1532989622000-d4f013a215e1?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=1a69643c04176376315714b9b2897de5&auto=format&fit=crop&w=677&q=80";
            return ImageFragment.getInstance(position,url);
        default:
            url = "https://images.unsplash.com/photo-1532983819500-85d633c73b7a?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=1f0b228b67f03064241534a6c65d9497&auto=format&fit=crop&w=1050&q=80";
            return ImageFragment.getInstance(position,url);
    }


}

@Override
public int getCount() {
    return 4;
}
}

XML деятельности

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#0099cc"
tools:context=".FullscreenActivity">

<!-- This FrameLayout insets its children based on system windows using
     android:fitsSystemWindows. -->


    <com.david.verticalviewpagerexample.VerticalViewPager
        android:id="@+id/main_viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>



    <LinearLayout
        android:id="@+id/fullscreen_content_controls"
        style="?metaButtonBarStyle"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|center_horizontal"
        android:background="@color/black_overlay"
        android:orientation="horizontal"
        tools:ignore="UselessParent">

        <Button
            android:id="@+id/dummy_button"
            style="?metaButtonBarButtonStyle"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="@string/dummy_button" />

    </LinearLayout>


</FrameLayout>

Фрагмент XML

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">

<ImageView
    android:id="@+id/iv_imagefragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:scaleType="centerCrop"/>

</LinearLayout>

Обновление: 1

https://github.com/youngkaaa/YViewPagerDemo

Есть еще одна библиотека, которая отлично работает на Android Pie, но у нее мало мягких сбоев. Также происходит сбой API 19.

Обновление: 2

Google недавно выпустила ViewPager2 с библиотекой поддержки androidxhttps://developer.android.com/jetpack/androidx/releases/viewpager2, который поддерживает вертикальный просмотр. Тем не менее, он все еще находится в альфа-версии и имеет много известных проблем.

Ответы на вопрос(1)

Ваш ответ на вопрос