GithubHelp home page GithubHelp logo

massivemadness / fragula Goto Github PK

View Code? Open in Web Editor NEW
323.0 2.0 18.0 54.37 MB

πŸ§› Fragula is a swipe-to-dismiss extension for navigation component library for Android

License: Apache License 2.0

Kotlin 51.41% Shell 0.25% Java 48.33%
android navigation swipeback gesture swipe-to-dismiss swipeable fragment backstack compose compose-navigation jetpack-compose kotlin library navigation-component navigator transitions type-safety

fragula's Introduction

Fragula 2

Fragula is a swipe-to-dismiss extension for navigation component library for Android.
It is an adaptation of an earlier version created by @shikleev and now maintained in this repository.

Android CI License Android Arsenal

Dark Theme Light Theme

Table of Contents

Fragments

  1. Gradle Dependency
  2. The Basics
  3. More Options
    1. Navigate with arguments
    2. Multiple BackStacks
  4. Swipe Direction
  5. Swipe Transitions
  6. Theming

Jetpack Compose

  1. Gradle Dependency
  2. The Basics
  3. More Options
    1. Navigate with arguments
    2. Multiple BackStacks
  4. Customization

Fragments

The fragula-core module provides everything you need to get started with the library. It contains all core and normal-use functionality.

MavenCentral

Gradle Dependency

Add this to your module’s build.gradle file:

dependencies {
  ...
  implementation 'com.fragula2:fragula-core:2.10.1'
}

The fragula-core module does not provide support for jetpack compose, you need to add the fragula-compose dependency in your project.


The Basics

First, you need to replace NavHostFragment with FragulaNavHostFragment in your layout:

<!-- activity_main.xml -->
<androidx.fragment.app.FragmentContainerView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:name="com.fragula2.FragulaNavHostFragment" 
    android:id="@+id/nav_host"
    app:navGraph="@navigation/nav_graph"
    app:defaultNavHost="true" />

Second, you need to replace your <fragment> destinations in graph with <swipeable> as shown below:

<!-- nav_graph.xml -->
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/nav_graph"
    app:startDestination="@id/detailFragment">

    <swipeable
        android:id="@+id/detailFragment"
        android:name="com.example.fragula.DetailFragment"
        android:label="DetailFragment"
        tools:layout="@layout/fragment_detail" />

    ...
    
</navigation>

Finally, you need to set opaque background to your fragment’s root layout to avoid any issues with swipe animation.

<!-- fragment_detail.xml -->
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="?android:colorBackground"
    android:layoutDirection="local">
    
    ...
    
</androidx.constraintlayout.widget.ConstraintLayout>

That's it! No need to worry about gestures, animations and switching the navigation framework you already use in your project.


More Options

Navigate with arguments

In general, you should work with Fragula as if you would work with normal fragments. You should strongly prefer passing only the minimal amount of data between destinations, as the total space for all saved states is limited on Android.

First, add an argument to the destination:

<swipeable 
    android:id="@+id/detailFragment"
    android:name="com.example.fragula.DetailFragment">
     <argument
         android:name="itemId"
         app:argType="string" />
 </swipeable>

Second, create a Bundle object and pass it to the destination using navigate() as shown below:

val bundle = bundleOf("itemId" to "123")
findNavController().navigate(R.id.detailFragment, bundle)

Finally, in your receiving destination’s code, use the getArguments() method to retrieve the Bundle and use its contents:

val textView = view.findViewById<TextView>(R.id.textViewItemId)
textView.text = arguments?.getString("itemId")

It's strongly recommended to use Safe Args plugin for navigating and passing data, because it ensures type-safety.

Multiple BackStacks

Currently multiple backstacks is not supported, which means you can’t safely use extensions such as setupWithNavController(...) without losing your current backstack.

This issue affects both BottomNavigationView and NavigationView widgets.


Swipe Direction

If you want to change the direction of swipe gesture, you can do that by setting app:swipeDirection="..." manually in your navigation container. This example below sets up vertical swipe direction.

<!-- activity_main.xml -->
<androidx.fragment.app.FragmentContainerView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:name="com.fragula2.FragulaNavHostFragment" 
    android:id="@+id/nav_host" 
    app:swipeDirection="top_to_bottom"
    app:navGraph="@navigation/nav_graph"
    app:defaultNavHost="true" />

You can use either left_to_right (default) or right_to_left for horizontal direction. For vertical direction you can use only top_to_bottom, the bottom_to_top is not supported due to internal ViewPager2 restrictions.

Note If you having an issues with nested scrollable views, this appears to be a scroll issue in ViewPager2. Please follow Google’s example to solve this.


Swipe Transitions

You may want to know when the scrolling offset changes to make smooth transitions inside your fragment view. To start listening scroll events you need to retrieve SwipeController and set OnSwipeListener as shown below:

class DetailFragment : Fragment(R.layout.fragment_detail) {
   
    private lateinit var swipeController: SwipeController
    private lateinit var swipeListener: OnSwipeListener
    
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        // ...
        swipeController = findSwipeController()
        swipeListener = OnSwipeListener { position, positionOffset, positionOffsetPixels ->
            // TODO animate views using `positionOffset` or `positionOffsetPixels`.
            //  the `position` points to the position of the fragment in backstack
        }
        swipeController.addOnSwipeListener(swipeListener)
    }
   
    override fun onDestroyView() {
        super.onDestroyView()
        swipeController.removeOnSwipeListener(swipeListener)
    }
}

Note Currently shared element transitions between destinations are not supported in any form. Remember that you must remove the listener when the fragment view is destroyed.


Theming

In most of the cases there is no need to change any values, but if you wish to override these, there are attributes provided:

<style name="AppTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
    <item name="colorPrimary">...</item>
    <item name="colorPrimaryDark">...</item>
    <item name="colorAccent">...</item>

    <!--
        This overrides the color used for the dimming when fragment is being dragged.
        The default value is #000000 for both light and dark themes.
    -->
    <item name="fgl_scrim_color">#000000</item>

    <!--
        This overrides the amount of dimming when fragment is being dragged.
        Think of it as a `fgl_scrim_color` alpha multiplier.
    -->
    <item name="fgl_scrim_amount">0.15</item>

    <!--
        This overrides the parallax multiplier when fragment is being dragged.
        It determines how much the underneath fragment will be shifted
        relative to the visible fragment (that is being dragged).
    -->
    <item name="fgl_parallax_factor">1.3</item>
   
    <!--
        This overrides the duration of swipe animation using `navController.navigate(...)` 
        and `navController.popBackStack()` methods.
    -->
    <item name="fgl_anim_duration">500</item>
   
    <!--
        This overrides the elevation applied to the fragment view.
        Note that it doesn't support `android:outlineAmbientShadowColor`
        and `android:outlineSpotShadowColor` attributes in your theme.
    -->
    <item name="fgl_elevation">3dp</item>
   
</style>

Jetpack Compose Ξ²

The fragula-compose module provides support for jetpack compose. It may not contain all the features described earlier. If you want to make a feature request, consider creating an issue on GitHub.

MavenCentral

Gradle Dependency

Add this to your module’s build.gradle file:

dependencies {
  ...
  implementation 'com.fragula2:fragula-compose:2.10.1'
}

The fragula-compose module does not provide support for fragments, you need to add the fragula-core dependency in your project.


The Basics

First, you need to replace NavHost(...) with FragulaNavHost(...) in your main composable:

// MainActivity.kt
setContent {
    AppTheme {
        Surface(
           modifier = Modifier.fillMaxSize(), 
           color = MaterialTheme.colors.background,
        ) {
            val navController = rememberFragulaNavController()
            FragulaNavHost(navController, startDestination = "list") {
                // ...
            }
        }
    }
}

Second, you need to replace your composable(...) destinations with swipeable(...) as shown below:

val navController = rememberFragulaNavController()
FragulaNavHost(navController, startDestination = "list") {
    swipeable("list") {
        ListScreen(navController)
    }
    swipeable("details") {
        DetailsScreen(navController)
    }
}

Finally, you need to set opaque background to your composables to avoid any issues with swipe animation.

@Composable
fun DetailsScreen(navController: NavController) {
    Box(modifier = Modifier.fillMaxSize()
       .background(Color.White)
    ) {
        // TODO content
    }
}

More Options

Navigate with arguments

Fragula also supports passing arguments between composable destinations the same way as in the androidx navigation library. Create a deeplink and specify the argument type, then you can extract NavArguments from the NavBackStackEntry that is available in the lambda of the swipeable() function.

NavHost(startDestination = "profile/{userId}") {
    // ...
    swipeable("profile/{userId}", arguments = listOf(
        navArgument("userId") { type = NavType.StringType }
    )) { backStackEntry ->
        ProfileScreen(navController, backStackEntry.arguments?.getString("userId"))
    }
}

To pass the argument to the destination, simply call navController.navigate("profile/user1234"). For more information read the article Navigating with Compose on official android developers website.

Multiple BackStacks

As already have been mentioned, Fragula doesn't support multiple backstacks both in XML and Compose. If you really need this feature in your app, consider creating a nested NavHost for bottom tabs only.


Customization

If you'd like to discover more customization features, here is parameters list.

@Composable
fun FragulaNavHost(
    navController: NavHostController,
    startDestination: String,
    modifier: Modifier = Modifier,
    route: String? = null,
    onPageScrolled: (Int, Float, Int) -> Unit, // Scroll listener (position, offset, offsetPixels)
    swipeDirection: SwipeDirection = SwipeDirection.LEFT_TO_RIGHT, // Scroll direction
    scrollable: Boolean = true, // Controls user's scrolling
    scrimColor: Color = ScrimColor, // Color used for the dimming
    scrimAmount: Float = 0.15f, // Percentage of dimming (depends on drag offset)
    elevationAmount: Dp = 3.dp, // Elevation applied on the composable
    parallaxFactor: Float = 1.3f, // Parallax multiplier (depends on drag offset)
    animDurationMs: Int = 500, // Duration of swipe animation
    builder: NavGraphBuilder.() -> Unit
) {
    // ...
}

fragula's People

Contributors

jakepurple13 avatar kitsunefolk avatar massivemadness avatar shikleev avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

fragula's Issues

App Crashing When Opening Swipeable Navigation Fragment

Stack trace:
java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.String.hashCode()' on a null object reference
at com.ald.devs47.sam.beckman.palettesetups.models.HomeSetupModel.hashCode(Unknown Source:136)
at androidx.navigation.NavBackStackEntry.hashCode(NavBackStackEntry.kt:256)
at java.util.HashMap.hash(HashMap.java:338)
at java.util.HashMap.put(HashMap.java:611)
at androidx.navigation.NavController.linkChildToParent(NavController.kt:143)
at androidx.navigation.NavController.addEntryToBackStack(NavController.kt:1918)
at androidx.navigation.NavController.addEntryToBackStack$default(NavController.kt:1813)
at androidx.navigation.NavController$navigate$4.invoke(NavController.kt:1721)
at androidx.navigation.NavController$navigate$4.invoke(NavController.kt:1719)
at androidx.navigation.NavController$NavControllerNavigatorState.push(NavController.kt:287)
at com.fragula2.navigation.SwipeBackNavigator.navigate(SwipeBackNavigator.kt:54)
at com.fragula2.navigation.SwipeBackNavigator.navigate(SwipeBackNavigator.kt:33)
at androidx.navigation.NavController.navigateInternal(NavController.kt:260)
at androidx.navigation.NavController.navigate(NavController.kt:1719)
at androidx.navigation.NavController.navigate(NavController.kt:1545)
at androidx.navigation.NavController.navigate(NavController.kt:1472)
at androidx.navigation.NavController.navigate(NavController.kt:1454)
at com.ald.devs47.sam.beckman.palettesetups.recycler.carouselRecycler.CarouselAdapter.onBindViewHolder$lambda$0(CarouselAdapter.kt:136)
at com.ald.devs47.sam.beckman.palettesetups.recycler.carouselRecycler.CarouselAdapter.lambda$TKKZbMgavm5g5IcEqe_Or5TbKTc(Unknown Source:0)
at com.ald.devs47.sam.beckman.palettesetups.recycler.carouselRecycler.-$$Lambda$CarouselAdapter$TKKZbMgavm5g5IcEqe_Or5TbKTc.onClick(Unknown Source:4)
at android.view.View.performClick(View.java:7743)
at android.view.View.performClickInternal(View.java:7720)
at android.view.View.access$3700(View.java:854)
at android.view.View$PerformClick.run(View.java:29111)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:210)
at android.os.Looper.loop(Looper.java:299)
at android.app.ActivityThread.main(ActivityThread.java:8309)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:556)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1038)

BackStack issue with `<fragment>` destinations

Describe the bug
There's an issue when navigating from <swipeable> to <fragment> destination, the fragment will not be added to the backstack, which makes impossible to go back using popBackStack() or navigateUp() methods.

To Reproduce
Steps to reproduce the behavior:

  1. Make <swipeable> your start destination
  2. Navigate to a <fragment> destination
  3. Call popBackStack() to return to the previous fragment

Any ideas of how to fix
The issue is not exactly in SwipeBackNavigator, It's the default behavior of androidx.navigation.fragment.FragmentNavigator, which depends on the backstack size to decide whether it should add a transaction to the backstack or not.

Π‘Π½ΠΈΠΌΠΎΠΊ экрана 2022-03-19 Π² 13 39 43

Π‘Π½ΠΈΠΌΠΎΠΊ экрана 2022-03-19 Π² 13 41 00

minSdk Question

Π’ Π±ΠΈΠ»Π΄Π΅ minSdk установлСн 23, я ΠΏΠΎΠ½ΠΈΠ·ΠΈΠ» Π΄ΠΎ 21 Π² Ρ„ΠΎΡ€ΠΊΠ½ΡƒΡ‚ΠΎΠΌ Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΈ, ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ запускаСтся, Π΅ΡΡ‚ΡŒ Π»ΠΈ какая Ρ‚ΠΎ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎΡΡ‚ΡŒ Π² установки minSdk ΠΊΠ°ΠΊ 23 вмСсто 21? Если Π½Π΅Ρ‚Ρƒ, Ρ‚ΠΎ я ΠΌΠΎΠ³Ρƒ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ pull request с ΠΏΠΎΠ½ΠΈΠΆΠ΅Π½Π½Ρ‹ΠΌ sdk.
In the build file minSdk is set to 23, I downgraded to 21 in my forked repo, the app has started, is there a need to set minSdk as 23 instead of 21? If no, I can make a pull request with minSdk 21.

Jetpack Compose improvements

Missing features

  1. Slide transition using NavController.popBackStack() method
  2. Swipe direction parameter
  3. Swipe position listener
  4. Scrolling controls (SwipeController analogue)

Bugfixes

  1. Slide animation repeats on recomposition (when changing device orientation)
  2. Reduce recomposition count
  3. All of the backstack entries (screens) are rendered at the same time

EditText focus issue

Library Version:
2.7

Affected Device(s):
Redmi 9C with API 29

Describe the bug
Edittext loses it's cursor when clicking on it the first time a swipeable fragment is launched

To Reproduce
Steps to reproduce the behavior:

  1. Open the Fragula app
  2. Add an edittext to a swipeable fragment
    I added a video file, so you can reproduce the bug
348821683_9255680534504036_8649609907602659019_n.mp4

Having normal navigate with swipeable screen.

Hey, thank you for this useful library.
How can i have some not-swipeable screen?
imagine i have 10 swipeable screen, but i want to keep one of them normal, i dont want to be swipeable that one.
using composable instead swipeable not working!

Navigation dependencie update issue

ΠŸΡ€ΠΈ ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠΈ androidx.navigation:navigation ΠΊ 2.6.0 ΠΌΠ΅Ρ‚ΠΎΠ΄ backQueue(ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ Π² SwipeBackFragment.restoreBackStack стал ΠΏΡ€ΠΈΠ²Π°Ρ‚Π½Ρ‹ΠΌ, ΠΈΠ·-Π·Π° этого Π²ΠΎΠ·Π½ΠΈΠΊΠ°Π΅Ρ‚ ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ ΠΏΡ€ΠΈ использовании Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ с ΠΎΠ±Π½ΠΎΠ²Π»Ρ‘Π½Π½ΠΎΠΉ dependencie, Π•ΡΡ‚ΡŒ Π΄Ρ€ΡƒΠ³ΠΎΠΉ ΠΌΠ΅Ρ‚ΠΎΠ΄, Π½ΠΎ ΠΎΠ½ Ρ‚Π°ΠΊΠΆΠ΅ ΠΎΠ³Ρ€Π°Π½ΠΈΡ‡Π΅Π½ Π² ΠΏΡ€Π΅Π΄Π΅Π»Π°Ρ… Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ ΠΈ ΠΌΠΎΠΆΠ΅Ρ‚ ΡΡ‚Π°Ρ‚ΡŒ Π½Π΅ доступСн Π² ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΡ… вСрсиях navigation, ΠΈ Π΅Ρ‰Ρ‘ Π΅Π³ΠΎ использованиС Π½Π΅ Π²Ρ‹Π·Ρ‹Π²Π°Π΅Ρ‚ pop() Π½Π° Ρ„Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚Π΅ ΠΏΡ€ΠΈ Π½Π°ΠΆΠ°Ρ‚ΠΈΠΈ Π½Π° back button, Π° сразу Π·Π°ΠΊΡ€Ρ‹Π²Π°Π΅Ρ‚ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅:

@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public val currentBackStack: StateFlow<List<NavBackStackEntry>> =
    _currentBackStack.asStateFlow()

ВСстируСмый ΠΊΠΎΠ΄ ΠΌΠ΅Ρ‚ΠΎΠ΄Π° с Π±Π°Π³ΠΎΠΌ:

private fun restoreBackStack() {
        viewPager?.currentItem = navController?.currentBackStack?.value.orEmpty()
            .filter { it.destination is SwipeBackDestination }
            .also { navBackStackAdapter?.addAll(it) }
            .size
    }

Exception when clicking on the back arrow button while swiping a swipeable fragment

Library Version:
2.7

Affected Device(s):
Redmi 9C with Android 10, API 29
Describe the bug
If we open a swipeable fragment and then try to unswipe on 5dp or something, then slowly swipe back and press the back arrow button in the toolbar, the fragment becomes black. If we swipe from right to left, then it back to normal, but swipeable fragments in the recyclerview are not opening and if we try to open a swipeable fragment from the navigation view again, it throws the exception below:

java.lang.IllegalStateException: Fragment SwipeBackFragment{21e6e36} (56b51e72-7a1b-490c-82f0-2ad41f0a08f2) not attached to a context.
                                                                                                    	at androidx.fragment.app.Fragment.requireContext(Fragment.java:967)
                                                                                                    	at com.fragula2.adapter.NavBackStackAdapter.createFragment(NavBackStackAdapter.kt:14)
                                                                                                    	at androidx.viewpager2.adapter.FragmentStateAdapter.ensureFragment(FragmentStateAdapter.java:268)
                                                                                                    	at androidx.viewpager2.adapter.FragmentStateAdapter.onBindViewHolder(FragmentStateAdapter.java:175)
                                                                                                    	at androidx.viewpager2.adapter.FragmentStateAdapter.onBindViewHolder(FragmentStateAdapter.java:67)
                                                                                                    	at androidx.recyclerview.widget.RecyclerView$Adapter.onBindViewHolder(RecyclerView.java:7065)
                                                                                                    	at androidx.recyclerview.widget.RecyclerView$Adapter.bindViewHolder(RecyclerView.java:7107)
                                                                                                    	at androidx.recyclerview.widget.RecyclerView$Recycler.tryBindViewHolderByDeadline(RecyclerView.java:6012)
                                                                                                    	at androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:6279)
                                                                                                    	at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6118)
                                                                                                    	at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6114)
                                                                                                    	at androidx.recyclerview.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2303)
                                                                                                    	at androidx.recyclerview.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1627)
                                                                                                    	at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1587)
                                                                                                    	at androidx.recyclerview.widget.LinearLayoutManager.scrollBy(LinearLayoutManager.java:1391)
                                                                                                    	at androidx.recyclerview.widget.LinearLayoutManager.scrollHorizontallyBy(LinearLayoutManager.java:1116)
                                                                                                    	at androidx.recyclerview.widget.RecyclerView.scrollStep(RecyclerView.java:1838)
                                                                                                    	at androidx.recyclerview.widget.RecyclerView.scrollByInternal(RecyclerView.java:1940)
                                                                                                    	at androidx.recyclerview.widget.RecyclerView.scrollBy(RecyclerView.java:1812)
                                                                                                    	at androidx.viewpager2.widget.FakeDrag.fakeDragBy(FakeDrag.java:95)
                                                                                                    	at androidx.viewpager2.widget.ViewPager2.fakeDragBy(ViewPager2.java:735)
                                                                                                    	at com.fragula2.utils.ExtensionsKt.fakeDragTo$lambda$1$lambda$0(Extensions.kt:88)
                                                                                                    	at com.fragula2.utils.ExtensionsKt.$r8$lambda$C6bpgJwUl--4hf-kWEmxak-d7uU(Unknown Source:0)
                                                                                                    	at com.fragula2.utils.ExtensionsKt$$ExternalSyntheticLambda0.onAnimationUpdate(Unknown Source:8)
                                                                                                    	at android.animation.ValueAnimator.animateValue(ValueAnimator.java:1558)
                                                                                                    	at android.animation.ValueAnimator.animateBasedOnTime(ValueAnimator.java:1349)
                                                                                                    	at android.animation.ValueAnimator.doAnimationFrame(ValueAnimator.java:1481)
                                                                                                    	at android.animation.AnimationHandler.doAnimationFrame(AnimationHandler.java:146)
                                                                                                    	at android.animation.AnimationHandler.access$100(AnimationHandler.java:37)
                                                                                                    	at android.animation.AnimationHandler$1.doFrame(AnimationHandler.java:54)
                                                                                                    	at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1039)
                                                                                                    	at android.view.Choreographer.doCallbacks(Choreographer.java:860)
                                                                                                    	at android.view.Choreographer.doFrame(Choreographer.java:781)
                                                                                                    	at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1026)
                                                                                                    	at android.os.Handler.handleCallback(Handler.java:914)
                                                                                                    	at android.os.Handler.dispatchMessage(Handler.java:100)
                                                                                                    	at android.os.Looper.loop(Looper.java:225)
                                                                                                    	at android.app.ActivityThread.main(ActivityThread.java:7563)
                                                                                                    	at java.lang.reflect.Method.invoke(Native Method)
                                                                                                    	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:539)
                                                                                                    	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:994)

To Reproduce
Steps to reproduce the behavior:

  1. Open the native kotlin fragula app
  2. Open the Settings fragment in the navigation view
  3. Swipe from left to right a few millimeters, swipe back from right to left while pressing the toolbar's back button
  4. See the black screen, then swipe from right to left to get the fragment to normal
  5. Open the Settings fragment again and see the exception

I attached a video file, so you can see how exactly to reproduce the bug:
https://github.com/massivemadness/Fragula/assets/104719315/cb79f3b7-0c0c-4fbf-b8ae-0f47145c91d9

Restrict swiping area

Hi, I wanted to ask something. Is it possible to restrict swiping, i.e. if you swipe anywhere other than the farthest part of the screen on the left, it should not go back

Fragment Swipe Silent Exception

Please consider making a Pull Request if you are capable of doing so.

Library Version:
2.8

Affected Device(s):
Redmi 9C

Describe the bug
Π’ΠΈΡ…ΠΎΠ΅ ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ ΠΏΡ€ΠΈ свайпС Ρ„Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚Π°:

2023-06-13 11:53:36.549 10961-10961 RecyclerView            com.fragula2.sample                  W  Cannot call this method in a scroll callback. Scroll callbacks mightbe run during a measure & layout pass where you cannot change theRecyclerView data. Any method call that might change the structureof the RecyclerView or the adapter contents should be postponed tothe next frame.
                                                                                                    java.lang.IllegalStateException:  androidx.viewpager2.widget.ViewPager2$RecyclerViewImpl{16cf409 VFED..... ......ID 0,0-720,1433 #1}, adapter:com.fragula2.adapter.NavBackStackAdapter@625909f, layout:androidx.viewpager2.widget.ViewPager2$LinearLayoutManagerImpl@a0935ec, context:com.fragula2.sample.MainActivity@56ee45d
                                                                                                    	at androidx.recyclerview.widget.RecyclerView.assertNotInLayoutOrScroll(RecyclerView.java:3061)
                                                                                                    	at androidx.recyclerview.widget.RecyclerView$RecyclerViewDataObserver.onItemRangeRemoved(RecyclerView.java:5563)
                                                                                                    	at androidx.recyclerview.widget.RecyclerView$AdapterDataObservable.notifyItemRangeRemoved(RecyclerView.java:12288)
                                                                                                    	at androidx.recyclerview.widget.RecyclerView$Adapter.notifyItemRemoved(RecyclerView.java:7515)
                                                                                                    	at com.fragula2.adapter.NavBackStackAdapter.pop(NavBackStackAdapter.kt:55)
                                                                                                    	at com.fragula2.navigation.SwipeBackFragment.popBackStack(SwipeBackFragment.kt:163)
                                                                                                    	at com.fragula2.navigation.SwipeBackNavigator.popBackStack(SwipeBackNavigator.kt:80)
                                                                                                    	at androidx.navigation.NavController.popBackStackInternal(NavController.kt:274)
                                                                                                    	at androidx.navigation.NavController.popBackStackInternal(NavController.kt:557)
                                                                                                    	at androidx.navigation.NavController.popBackStack(NavController.kt:472)
                                                                                                    	at androidx.navigation.NavController.popBackStack(NavController.kt:449)
                                                                                                    	at androidx.navigation.NavController.popBackStack(NavController.kt:434)
                                                                                                    	at com.fragula2.navigation.SwipeBackFragment$onPageChangeCallback$1.onPageScrollStateChanged(SwipeBackFragment.kt:56)
                                                                                                    	at androidx.viewpager2.widget.CompositeOnPageChangeCallback.onPageScrollStateChanged(CompositeOnPageChangeCallback.java:87)
                                                                                                    	at androidx.viewpager2.widget.CompositeOnPageChangeCallback.onPageScrollStateChanged(CompositeOnPageChangeCallback.java:87)
                                                                                                    	at androidx.viewpager2.widget.ScrollEventAdapter.dispatchStateChanged(ScrollEventAdapter.java:426)
                                                                                                    	at androidx.viewpager2.widget.ScrollEventAdapter.onScrolled(ScrollEventAdapter.java:214)
                                                                                                    	at androidx.recyclerview.widget.RecyclerView.dispatchOnScrolled(RecyclerView.java:5173)
                                                                                                    	at androidx.recyclerview.widget.RecyclerView$ViewFlinger.run(RecyclerView.java:5338)
                                                                                                    	at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1041)
                                                                                                    	at android.view.Choreographer.doCallbacks(Choreographer.java:860)
                                                                                                    	at android.view.Choreographer.doFrame(Choreographer.java:781)
                                                                                                    	at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1026)
                                                                                                    	at android.os.Handler.handleCallback(Handler.java:914)
                                                                                                    	at android.os.Handler.dispatchMessage(Handler.java:100)
                                                                                                    	at android.os.Looper.loop(Looper.java:225)
                                                                                                    	at android.app.ActivityThread.main(ActivityThread.java:7563)
                                                                                                    	at java.lang.reflect.Method.invoke(Native Method)
                                                                                                    	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:539)
                                                                                                    	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:994)

To Reproduce
Steps to reproduce the behavior:

  1. ΠžΡ‚ΠΊΡ€Ρ‹Ρ‚ΡŒ Ρ„Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚
  2. Π—Π°ΠΊΡ€Ρ‹Ρ‚ΡŒ Ρ„Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚ свайпом

ΠŸΡ€ΠΈ Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠΈ

viewPager?.post {
    navBackStackAdapter?.pop()
}

вмСсто
navBackStackAdapter?.pop()
ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ Π½Π΅Ρ‚Ρƒ, сдСлаю pr ΠΊΠ°ΠΊ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½Ρ‹ΠΉ фикс.
#22

How to get a reference of the current fragment

Π― ΠΌΠΎΠ³ Π±Ρ‹ ΠΏΠ΅Ρ€Π΅ΠΏΠΈΡΠ°Ρ‚ΡŒ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΡƒ ΠΈ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ ΠΌΠ΅Ρ‚ΠΎΠ΄ Π² NavBackStackAdapter Ρ‡Ρ‚ΠΎ Π±Ρ‹ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ Ρ„Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚, Π½ΠΎ я ΠΏΠΎΠ΄ΡƒΠΌΠ°Π» ΠΌΠΎΠΆΠ΅Ρ‚ сущСствуСт Π»ΡƒΡ‡ΡˆΠΈΠΉ способ? Π― ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽ свайп Ρ„Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚ с Π²Π»ΠΎΠΆΠ΅Π½Π½Ρ‹ΠΌΠΈ Ρ„Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚Π°ΠΌΠΈ Π²Π½ΡƒΡ‚Ρ€ΠΈ, ΠΏΡ€ΠΈ Π½Π°ΠΆΠ°Ρ‚ΠΈΠΈ Π½Π° Π°ΠΉΡ‚Π΅ΠΌ мСню ΠΌΠ½Π΅ Π½ΡƒΠΆΠ½ΠΎ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ Ρ„Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚ Ρ‡Ρ‚ΠΎ Π±Ρ‹ Π²Ρ‹Π·Π²Π°Ρ‚ΡŒ navigate

how to stop one fragment in navHost not to implement swipe Please let me know is this possible? I have map fragment when change fragment to swipeable my map scrolling stops

Please consider making a Pull Request if you are capable of doing so.

Is your feature request related to a problem? Please describe.
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

Describe the solution you'd like
A clear and concise description of what you want to happen.

Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.

Additional context
Add any other context or screenshots about the feature request here.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.