From ae8833d21b6579eda936544d1c1403b25d90187e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rom=C3=A1n=20Mart=C3=ADnez?= Date: Thu, 26 Nov 2020 22:07:58 +0100 Subject: [PATCH] ViewPager migrate to ViewPager2. Fixes #522. Swiping between tabs work. Fixes #105. --- .../opentracks/TrackRecordedActivity.java | 30 ++++++----- .../opentracks/TrackRecordingActivity.java | 29 +++++----- .../opentracks/chart/ChartView.java | 53 ++++++++++++++++++- src/main/res/layout-land/track_recording.xml | 2 +- src/main/res/layout/track_recorded.xml | 2 +- src/main/res/layout/track_recording.xml | 2 +- 6 files changed, 87 insertions(+), 31 deletions(-) diff --git a/src/main/java/de/dennisguse/opentracks/TrackRecordedActivity.java b/src/main/java/de/dennisguse/opentracks/TrackRecordedActivity.java index b124efaf7..a512526c7 100644 --- a/src/main/java/de/dennisguse/opentracks/TrackRecordedActivity.java +++ b/src/main/java/de/dennisguse/opentracks/TrackRecordedActivity.java @@ -22,11 +22,14 @@ import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; +import android.view.ViewParent; import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentManager; -import androidx.fragment.app.FragmentPagerAdapter; +import androidx.fragment.app.FragmentActivity; +import androidx.viewpager2.adapter.FragmentStateAdapter; + +import com.google.android.material.tabs.TabLayoutMediator; import de.dennisguse.opentracks.content.TrackDataHub; import de.dennisguse.opentracks.content.data.Marker; @@ -75,8 +78,10 @@ public class TrackRecordedActivity extends AbstractListActivity implements Confi trackDataHub = new TrackDataHub(this); - viewBinding.trackDetailActivityViewPager.setAdapter(new CustomFragmentPagerAdapter(getSupportFragmentManager(), FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT)); - viewBinding.trackDetailActivityTablayout.setupWithViewPager(viewBinding.trackDetailActivityViewPager); + CustomFragmentPagerAdapter pagerAdapter = new CustomFragmentPagerAdapter(this); + viewBinding.trackDetailActivityViewPager.setAdapter(pagerAdapter); + new TabLayoutMediator(viewBinding.trackDetailActivityTablayout, viewBinding.trackDetailActivityViewPager, + (tab, position) -> tab.setText(pagerAdapter.getPageTitle(position))).attach(); if (savedInstanceState != null) { viewBinding.trackDetailActivityViewPager.setCurrentItem(savedInstanceState.getInt(CURRENT_TAB_TAG_KEY)); } @@ -220,20 +225,15 @@ public class TrackRecordedActivity extends AbstractListActivity implements Confi } } - private class CustomFragmentPagerAdapter extends FragmentPagerAdapter { + private class CustomFragmentPagerAdapter extends FragmentStateAdapter { - public CustomFragmentPagerAdapter(@NonNull FragmentManager fm, int behavior) { - super(fm, behavior); - } - - @Override - public int getCount() { - return 4; + public CustomFragmentPagerAdapter(@NonNull FragmentActivity fa) { + super(fa); } @NonNull @Override - public Fragment getItem(int position) { + public Fragment createFragment(int position) { switch (position) { case 0: return StatisticsRecordedFragment.newInstance(trackId); @@ -249,6 +249,10 @@ public class TrackRecordedActivity extends AbstractListActivity implements Confi } @Override + public int getItemCount() { + return 4; + } + public CharSequence getPageTitle(int position) { switch (position) { case 0: diff --git a/src/main/java/de/dennisguse/opentracks/TrackRecordingActivity.java b/src/main/java/de/dennisguse/opentracks/TrackRecordingActivity.java index 079b790f2..ba32ecc27 100644 --- a/src/main/java/de/dennisguse/opentracks/TrackRecordingActivity.java +++ b/src/main/java/de/dennisguse/opentracks/TrackRecordingActivity.java @@ -13,8 +13,10 @@ import android.view.WindowManager; import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentManager; -import androidx.fragment.app.FragmentPagerAdapter; +import androidx.fragment.app.FragmentActivity; +import androidx.viewpager2.adapter.FragmentStateAdapter; + +import com.google.android.material.tabs.TabLayoutMediator; import de.dennisguse.opentracks.content.TrackDataHub; import de.dennisguse.opentracks.content.data.Track; @@ -148,8 +150,10 @@ public class TrackRecordingActivity extends AbstractActivity implements ChooseAc trackRecordingServiceConnection = new TrackRecordingServiceConnection(bindChangedCallback); trackDataHub = new TrackDataHub(this); - viewBinding.trackDetailActivityViewPager.setAdapter(new CustomFragmentPagerAdapter(getSupportFragmentManager(), FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT)); - viewBinding.trackDetailActivityTablayout.setupWithViewPager(viewBinding.trackDetailActivityViewPager); + CustomFragmentPagerAdapter pagerAdapter = new CustomFragmentPagerAdapter(this); + viewBinding.trackDetailActivityViewPager.setAdapter(pagerAdapter); + new TabLayoutMediator(viewBinding.trackDetailActivityTablayout, viewBinding.trackDetailActivityViewPager, + (tab, position) -> tab.setText(pagerAdapter.getPageTitle(position))).attach(); if (savedInstanceState != null) { viewBinding.trackDetailActivityViewPager.setCurrentItem(savedInstanceState.getInt(CURRENT_TAB_TAG_KEY)); } @@ -358,20 +362,15 @@ public class TrackRecordingActivity extends AbstractActivity implements ChooseAc finish(); } - private class CustomFragmentPagerAdapter extends FragmentPagerAdapter { + private class CustomFragmentPagerAdapter extends FragmentStateAdapter { - public CustomFragmentPagerAdapter(@NonNull FragmentManager fm, int behavior) { - super(fm, behavior); - } - - @Override - public int getCount() { - return 4; + public CustomFragmentPagerAdapter(@NonNull FragmentActivity fa) { + super(fa); } @NonNull @Override - public Fragment getItem(int position) { + public Fragment createFragment(int position) { switch (position) { case 0: return StatisticsRecordingFragment.newInstance(); @@ -387,6 +386,10 @@ public class TrackRecordingActivity extends AbstractActivity implements ChooseAc } @Override + public int getItemCount() { + return 4; + } + public CharSequence getPageTitle(int position) { switch (position) { case 0: diff --git a/src/main/java/de/dennisguse/opentracks/chart/ChartView.java b/src/main/java/de/dennisguse/opentracks/chart/ChartView.java index 4cdcab9db..97045a9fd 100644 --- a/src/main/java/de/dennisguse/opentracks/chart/ChartView.java +++ b/src/main/java/de/dennisguse/opentracks/chart/ChartView.java @@ -30,6 +30,7 @@ import android.view.GestureDetector; import android.view.MotionEvent; import android.view.ScaleGestureDetector; import android.view.View; +import android.view.ViewParent; import android.widget.Scroller; import androidx.annotation.NonNull; @@ -117,6 +118,14 @@ public class ChartView extends View { private boolean reportSpeed = true; private boolean showPointer = false; + // To handle disallow intercept touch event in parent. + private static final int SCROLL_X_NONE = 0; + private static final int SCROLL_X_LEFT = 1; + private static final int SCROLL_X_RIGHT = 2; + private boolean isOnLeftEdge = true; + private boolean isOnRightEdge = true; + private int scrollXDirection = SCROLL_X_NONE; + private final GestureDetectorCompat detectorScrollFlingTab = new GestureDetectorCompat(getContext(), new GestureDetector.SimpleOnGestureListener() { @Override @@ -129,6 +138,14 @@ public class ChartView extends View { @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { + if (distanceX < 0) { + scrollXDirection = SCROLL_X_LEFT; + } else if (distanceX > 0) { + scrollXDirection = SCROLL_X_RIGHT; + } else { + scrollXDirection = SCROLL_X_NONE; + } + if (Math.abs(distanceX) > 0) { int availableToScroll = effectiveWidth * (zoomLevel - 1) - getScrollX(); if (availableToScroll > 0) { @@ -434,6 +451,9 @@ public class ChartView extends View { chartPoints.clear(); xExtremityMonitor.reset(); zoomLevel = 1; + isOnLeftEdge = true; + isOnRightEdge = true; + scrollXDirection = SCROLL_X_NONE; updateDimensions(); } } @@ -500,6 +520,18 @@ public class ChartView extends View { invalidate(); } + /** + * Handle parent's view disallow touch event. + * + * @param disallow Does disallow parent touch event? + */ + private void requestDisallowInterceptTouchEventInParent(boolean disallow) { + ViewParent parent = getParent(); + if (parent != null) { + parent.requestDisallowInterceptTouchEvent(disallow); + } + } + /** * Scrolls the view horizontally by a given amount. * @@ -507,13 +539,21 @@ public class ChartView extends View { */ private void scrollBy(int deltaX) { int scrollX = getScrollX() + deltaX; - if (scrollX < 0) { + if (scrollX <= 0) { scrollX = 0; + isOnLeftEdge = true; + } else { + isOnLeftEdge = false; } + int maxWidth = effectiveWidth * (zoomLevel - 1); - if (scrollX > maxWidth) { + if (scrollX >= maxWidth) { scrollX = maxWidth; + isOnRightEdge = true; + } else { + isOnRightEdge = false; } + scrollTo(scrollX, 0); } @@ -538,6 +578,15 @@ public class ChartView extends View { public boolean onTouchEvent(MotionEvent event) { boolean isZoom = detectorZoom.onTouchEvent(event); boolean isScrollTab = detectorScrollFlingTab.onTouchEvent(event); + + if (event.getPointerCount() == 1 && ((isOnLeftEdge && scrollXDirection == SCROLL_X_LEFT) || (isOnRightEdge && scrollXDirection == SCROLL_X_RIGHT))) { + // Focus on view's parent. + requestDisallowInterceptTouchEventInParent(false); + } else { + // Focus on ChartView. + requestDisallowInterceptTouchEventInParent(true); + } + return isZoom || isScrollTab; } diff --git a/src/main/res/layout-land/track_recording.xml b/src/main/res/layout-land/track_recording.xml index 87855963b..6c6c0d2e4 100644 --- a/src/main/res/layout-land/track_recording.xml +++ b/src/main/res/layout-land/track_recording.xml @@ -25,7 +25,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" /> - - -