I set the animation:
slide_in_left.xml
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="-100%" android:toXDelta="0%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="#integer/animation_duration"/>
</set>
slide_out_right.xml
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="0%" android:toXDelta="100%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="#integer/animation_duration"/>
</set>
And I use it by
<action
...
app:popEnterAnim="#anim/slide_in_left"
app:popExitAnim="#anim/slide_out_right"/>
This action is:A->B
A contains a Recyclerview, B is the item.
The expectation is that when exiting from B, A will slowly slide from the left side of the screen to the middle of the screen, and B will slowly slide from the middle of the screen to the right side of the screen (until it is invisible).
But the result I get is: A immediately appears in the middle of the screen and B will slowly slide from the middle of the screen to the right side of the screen (until it is invisible).
What happened?
I solve my problem by uploading the version of fragment and navigation
def versions = [:]
versions.fragment = "1.3.3"
versions.navigation = "2.3.5"
def fragment = [:]
fragment.runtime = "androidx.fragment:fragment:${versions.fragment}"
fragment.ktx = "androidx.fragment:fragment-ktx:${versions.fragment}"
deps.fragment = fragment
def navigation = [:]
navigation.runtime = "androidx.navigation:navigation-runtime:$versions.navigation"
navigation.runtime_ktx = "androidx.navigation:navigation-runtime-ktx:$versions.navigation"
navigation.fragment = "androidx.navigation:navigation-fragment:$versions.navigation"
navigation.fragment_ktx = "androidx.navigation:navigation-fragment-ktx:$versions.navigation"
navigation.ui = "androidx.navigation:navigation-ui:$versions.navigation"
navigation.ui_ktx = "androidx.navigation:navigation-ui-ktx:$versions.navigation"
navigation.safe_args_plugin = "androidx.navigation:navigation-safe-args-gradle-plugin:$versions.navigation"
deps.navigation = navigation
Related
I want to implement enter and exit fragment animation during navigation in MVVMCross project.
[MvxFragmentPresentation(typeof(TestViewModel),
Resource.Id.content_frame, true,
Resource.Animation.enter_from_right,
Resource.Animation.exit_nothing_animation)]
enter_from_right
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<translate
android:fromXDelta="100%p" android:toXDelta="0%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="#android:integer/config_mediumAnimTime" />
</set>
exit_nothing_animation
<?xml version="1.0" encoding="UTF-8" ?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="300"
android:fromAlpha="1"
android:toAlpha="1" />
I expect that new fragment slide from right over the old frgamnet and old fragment will remain in the same place.
But new fragment just instantly appears without animation
Other topics suggest use Add insted Replace, but what the right way in MVVMCross project?
Answer is override this method in base fragment class
public override Animation OnCreateAnimation(int transit, bool enter, int nextAnim)
{
if (nextAnim == Resource.Animation.enter_from_right)
{
ViewCompat.SetTranslationZ(view, 1f);
}
else
{
ViewCompat.SetTranslationZ(view, 0f);
}
return base.OnCreateAnimation(transit, enter, nextAnim);
}
I have a Navigation drawer and Toolbar menu where I can go to another fragment. I used this to navigate:
override fun onNavigationItemSelected(item: MenuItem): Boolean
{
drawerLayout.close()
return NavigationUI.onNavDestinationSelected(
item,
findNavController(R.id.navHostFragment)
)
}
How I can add custom animation while switching fragments?
It is Answer your own question. I have faced this problem and couldn't find any answer which would work 100% well in my case so maybe this will help somebody.
This is how the overridden method onNavigationItemSelected should looks:
override fun onNavigationItemSelected(item: MenuItem): Boolean
{
drawerLayout.close()
// this part checks if current fragment is the same as destination
return if (findNavController(R.id.navHostFragment).currentDestination?.id != item.itemId)
{
val builder = NavOptions.Builder()
.setLaunchSingleTop(true)
.setEnterAnim(R.anim.enter_left_to_right)
.setExitAnim(R.anim.exit_right_to_left)
.setPopEnterAnim(R.anim.popenter_right_to_left)
.setPopExitAnim(R.anim.popexit_left_to_right)
// this part set proper pop up destination to prevent "looping" fragments
if (item.order and Menu.CATEGORY_SECONDARY == 0)
{
var startDestination: NavDestination? =
findNavController(R.id.navHostFragment).graph
while (startDestination is NavGraph)
{
val parent = startDestination
startDestination = parent.findNode(parent.startDestination)
}
builder.setPopUpTo(
startDestination!!.id,
false
)
}
val options = builder.build()
return try
{
findNavController(R.id.navHostFragment).navigate(item.itemId, null, options)
true
}
catch (e: IllegalArgumentException) // couldn't find destination, do nothing
{
false
}
}
else
{
false
}
}
This method prevents going to current, selected fragments. So when a user is in the Fragment A and in the Navigation drawer again selects Fragment A nothing will happen, Navigation drawer will just hide.
This method also prevents "looping" fragments, there could be only one fragment on the stack which was selected from the Navigation drawer or Toolbar menu. E.g. in the navigation drawer is Fragment A and Fragment B. The user is in Fragment Home then go to Fragment A and next to Fragment B. If a user clicks back button app will go back to Fragment Home, not to the Fragment A. Also, instead of finding startDestination in a while loop, it is possible to use R.id.homeFragment. If anyone wants to allow "looping" fragments just delete this part in code.
I have tested this solution and it seems to work well but of course there can be something which doesn't work exactly as it should.
If someone wants simple animation with fade in/fade out and vertical translation:
R.anim.enter_left_to_right
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="#integer/fragment_anim_time"
android:fromXDelta="-100%"
android:fromYDelta="0%"
android:toXDelta="0%"
android:toYDelta="0%" />
<alpha
android:duration="#integer/fragment_anim_time"
android:fromAlpha="0.5"
android:toAlpha="1" />
</set>
R.anim.exit_right_to_left
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="#integer/fragment_anim_time"
android:fromXDelta="0%"
android:fromYDelta="0%"
android:toXDelta="100%"
android:toYDelta="0%" />
<alpha
android:duration="#integer/fragment_anim_time"
android:fromAlpha="1"
android:toAlpha="0.5" />
</set>
R.anim.popenter_right_to_left
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="#integer/fragment_anim_time"
android:fromXDelta="100%"
android:fromYDelta="0%"
android:toXDelta="0%"
android:toYDelta="0%" />
<alpha
android:duration="#integer/fragment_anim_time"
android:fromAlpha="0.5"
android:toAlpha="1" />
</set>
R.anim.popexit_left_to_right
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="#integer/fragment_anim_time"
android:fromXDelta="0%"
android:fromYDelta="0%"
android:toXDelta="-100%"
android:toYDelta="0%" />
<alpha
android:duration="#integer/fragment_anim_time"
android:fromAlpha="1"
android:toAlpha="0.5" />
</set>
res/values/integers.xml
<integer name="fragment_anim_time">250</integer>
I'm using Google Maps Api and 'm using custom marker. I want to set sliding animation to marker.
So user if click to marker, a part of marker sliding hide under the remaining part. When the part of hidden if click animation will reversed.
So like this as images :
to
left_to_right_anim.xml
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<translate android:fromXDelta="-100%" android:toXDelta="0%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="700"/>
</set>
right_to_left.xml
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<translate
android:fromXDelta="0%" android:toXDelta="100%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="700" />
</set>
And I tried in onMapReady method:
mGoogleMap.setOnMarkerClickListener(marker -> {
mCurrLocationMarker.remove();
if (!isMarkerPure) {
AnimationUtil.slideRightToLeft(mCurrLocationMarker, rootView.getContext());
mCurrLocationMarker = mGoogleMap.addMarker(markerOptions.position(latLng).icon(BitmapDescriptorFactory
.fromBitmap(getPureMarker(R.drawable.cengiz)))
.anchor(0.5f, anchorY));
isMarkerPure = true;
} else {
AnimationUtil.slideLeftToRight(mCurrLocationMarker, rootView.getContext());
mCurrLocationMarker = mGoogleMap.addMarker(markerOptions.position(latLng).icon(BitmapDescriptorFactory
.fromBitmap(getMarkerBitmapFromView(R.drawable.cengiz, locName, name)))
.anchor(0.125f, anchorY));
isMarkerPure = false;
}
return false;
});
But animation didn't happen. Has anyone ever done anything like that before?
How create swipe to back?
In iOS:
[assembly: ExportRenderer(typeof(HIPSTO.Controls.CustomContentPage), typeof(HIPSTO.iOS.Platform.Renderers.IOSPageRenderer))]
namespace HIPSTO.iOS.Platform.Renderers
{
public class IOSPageRenderer : PageRenderer
{
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
ViewController.NavigationController.InteractivePopGestureRecognizer.Enabled = true;
ViewController.NavigationController.InteractivePopGestureRecognizer.Delegate = new UIKit.UIGestureRecognizerDelegate();
}
}
}
But it only works from the edge. It is necessary from any place.
No ideas with android
As below shown:
First, You could achieved by NavigationPageRenderer in android.
This is GIF of this demo
TransitionNavigationPageRender.cs
[assembly: ExportRenderer(typeof(SwipePageDemo.Controls.TransitionNavigationPage), typeof(TransitionNavigationPageRenderer))]
namespace SwipePageDemo.Droid.Renderers
{
public class TransitionNavigationPageRenderer : NavigationPageRenderer
{
public TransitionNavigationPageRenderer(Context context) : base(context)
{
}
protected override void SetupPageTransition(Android.Support.V4.App.FragmentTransaction transaction, bool isPush)
{
if (isPush)
{
}
else
{
transaction.SetCustomAnimations(Resource.Animation.enter_left, Resource.Animation.exit_right,
Resource.Animation.enter_right, Resource.Animation.exit_left);
}
}
}
}
enter_left.xml
<?xml version="1.0" encoding="utf-8" ?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:propertyName="enter_from_left"
android:shareInterpolator="false">
<translate
android:fromXDelta="-100%" android:toXDelta="0%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="300"/>
</set>
enter_right.xml
<?xml version="1.0" encoding="utf-8" ?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<translate
android:fromXDelta="100%" android:toXDelta="0%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="300" />
</set>
exit_left.xml
<?xml version="1.0" encoding="utf-8" ?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<translate
android:fromXDelta="0%" android:toXDelta="-100%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="300"/>
</set>
exit_right.xml
<?xml version="1.0" encoding="utf-8" ?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<translate
android:fromXDelta="0%" android:toXDelta="100%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="300" />
</set>
If you want to know more details about Page Transition , you could refer to this link.
https://github.com/jsuarezruiz/xamarin-forms-page-transitions
But it only works from the edge. It is necessary from any place
You could achieved it by threshold property of SwipeGestureRecognizer class
The SwipeGestureRecognizer class also includes a Threshold property, that can be optionally set to a uint value that represents the minimum swipe distance that must be achieved for a swipe to be recognized, in device-independent units. The default value of this property is 100, meaning that any swipes that are less than 100 device-independent units will be ignored. If you want to increase the area that can be swiped, you could reduce this data of Threshold like following code.
var leftSwipeGesture = new SwipeGestureRecognizer { Direction = SwipeDirection.Right };
leftSwipeGesture.Threshold = 50;
leftSwipeGesture.Swiped += (sender, e) => Navigation.PopAsync();
stackLayout.GestureRecognizers.Add(leftSwipeGesture);
I changed value of leftSwipeGesture.Threshold to 50, this is GIF of swipe.
I've implemented a transition between my activities, the problem is that when the transition occurs the content of the first activity is showing on the second one for a millisecond and then it disappears showing the content of the second activity, How can I get rid of that and smoothly show the second activity?
animation_enter:
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<translate android:fromXDelta="0%" android:toXDelta="-100%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="200"
/>
</set>
animation_leave:
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<translate
android:fromXDelta="100%" android:toXDelta="0%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="200"
/>
</set>
And that is how I'm calling it:
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
TextView clienteId = (TextView) view.findViewById(R.id.pedidoID);
Intent intent = new Intent(getActivity(), PedidoDetalheActivity.class);
intent.putExtra("id_pedido", clienteId.getText()); // envia o id do pedido para a tela de detalhes
startActivity(intent);
getActivity().overridePendingTransition(R.anim.animation_enter, R.anim.animation_leave);
}
});
So for your animations to work you have to do the following:
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<translate android:fromXDelta="100%" android:toXDelta="0%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="200"
/>
</set>
This means that the activity will enter from left (100%) and will stop on the it's initial position (0%)
As for the leave animations:
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<translate
android:fromXDelta="0%" android:toXDelta="-100%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="200"
/>
</set>
This means that the current visible activity will leave the screen from it's current position (0%) to the right (-100%)