Flip animation (ObjectAnimator) for supportfragment (API less than 10) - android

I tried use CustomAnimation function for my application. But I end up getting Unknown Object Animator name error. I did some research and found out apparently objectAnimator type of animation is not supported under getSupportFragmentManager (correct me if i'm wrong).
getSupportFragmentManager()
.beginTransaction()
.setCustomAnimations(R.animator.card_flip_left_in, R.animator.card_flip_left_out,
R.animator.card_flip_right_in, R.animator.card_flip_right_out)
.add(R.id.content_frame, reportPage,reportPage.getClass().getSimpleName()).addToBackStack(reportPage.getClass().getSimpleName())
.commit();
getSupportFragmentManager().executePendingTransactions();
I saw multiple threads mentioned use http://nineoldandroids.com/ for ObjectAnimator. But I don't have an idea of how to use this library to implement it on my application.
Is there any workaround that I can use Object Animator type of animation in the above function?

Related

How to use androidx.animation.AnimatorSet?

I need to use reverse() method of Android AnimatorSet class. The problem is that this method was added only in api 26. But I found reverse method in source code in package androidx.animation. And I couldn't find any androidx library that allows to use that AnimatorSet (androidx.animation.AnimatorSet). How can I use that class?
For Api >=26 you just create an AnimatorSet object and after you define the animation you call reverse on it:
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playSequentially(ObjectAnimator.ofFloat(...), ...);
animatorSet.setDuration(...);
animatorSet.reverse();
animatorSet.start();
For older APIs you just reverse the order within the .ofFloat methods in your ObjectAnimators:
If initially you have ObjectAnimator.ofFloat(0, 1) you change it to animator.setFloatValues(1, 0)
If you don't care it's still in alpha, you can import it from here:
// To use the Animator APIs
implementation "androidx.core:core-animation:1.0.0-alpha01"
// To test the Animator APIs
androidTestImplementation "androidx.core:core-animation-testing:1.0.0-alpha01"
```

get v4.app.FragmentManager from Flutter Plugin

i try to get FragmentManager in my android flutter plugin. In my case i need v4.app.FragmentManager.
but in PluginRegistry Registrar. i just get app.FragmentManager from Registrar.activity().fragmentManager
Since i use FlutterFragmentActivity which extend v4.app.FragmentActivity, you can see the code in here.
So i think it's possible to get v4.app.FragmentManager().
anyone have idea how to reach that ?
finally, i solve this problem with simple fact:
First, Registrar.activity is app.activity which is if you want to get fragment manager you only get app.FragmentManager. So we can't call getSupportFragmentManager() function to get v4.app.FragmentManager.
Second, FlutterActivity / FLutterFragmentActivity is extending v4.app.Activity / v4.app.FragmentActivity so we can use getSupportFragmentManager() in this case.
So simply in Flutter Android plugin I just declare Activity / FragmentActivity equals with what MainActivity extended like. After that I can use getSupportFragmentManager() to get v4.app.FragmentManager. the code like below :
v4.app.Activity act = (Activity)vRegistrar.activity();
v4.app.FragmentManager = act.getSupportFragmentManger();
Hope it's helpful. Thanks...

Android fragment `setEnterTransition` doesn't work

I'm trying to animate the showing of a fragment in a very basic way but it doesn't work:
MyFragment myFragment = (MyFragment) getFragmentManager().findFragmentById(R.id.myFragment);
getFragmentManager().beginTransaction()
.hide(myFragment)
.commit();
Slide slideRight = new Slide(Gravity.RIGHT);
slideRight.setDuration(3000);
Slide slideLeft = new Slide(Gravity.LEFT);
slideLeft.setDuration(3000);
myFragment.setEnterTransition(slideRight);
myFragment.setExitTransition(slideLeft);
then later
getFragmentManager().beginTransaction()
.show(myFragment)
.commit();
But fragment just appears without any transition. I can't figure out why it doesn't animate.
Edit:
I ended up using the fragment support library with setCustomAnimations cause the native library doesn't support animation with relative values.
Also using the new API with setEnterTransition doesn't seem to work properly with show/hide and for some unknown reason worked only with replace which doesn't fit my needs.
setCustomAnimation will do the trick.
FragmentManager.beginTransaction()
.replace(R.id.fragment, new Fragment)
.setCustomAnimations(R.anim.slide_out_left, R.anim.slide_in_right).commit();

Why is Android O failing with "does not belong to this FragmentManager!"

I have migrated my application to Android O in Android Studio 3
Running on an Android O emulator all my dialogFragments now fail with :-
java.lang.IllegalStateException: Fragment MyDialogFragment{43ccf50 #2 MyDialogFragment} declared target fragment SettingsFragment{ceed549 #0 id=0x7f0f0142 android:switcher:2131689794:0} that does not belong to this FragmentManager!
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1316)
at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1624)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1689)
at android.support.v4.app.BackStackRecord.executeOps(BackStackRecord.java:794)
at android.support.v4.app.FragmentManagerImpl.executeOps(FragmentManager.java:2470)
at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2260)
at android.support.v4.app.FragmentManagerImpl.optimizeAndExecuteOps(FragmentManager.java:2213)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2122)
at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:746)
at android.os.Handler.handleCallback(Handler.java:769)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6535)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
I have made no code changes whatsoever.
What has changed in Android O that previously working DialogFragments now fail display?
Android Studio 3.0 Canary 1
Build #AI-171.4010489, built on May 15, 2017
JRE: 1.8.0_112-release-b736 x86_64
JVM: OpenJDK 64-Bit Server VM by JetBrains s.r.o
Mac OS X 10.11.6
compileSdkVersion 'android-O'
buildToolsVersion "26.0.0-rc2"
AndroidManifest.xml
defaultConfig {
minSdkVersion 16
targetSdkVersion 'O'
}
compile 'com.android.support:appcompat-v7:26.0.0-beta1'
compile 'com.android.support:cardview-v7:26.0.0-beta1'
compile 'com.android.support:design:26.0.0-beta1'
compile 'com.android.support:percent:26.0.0-beta1'
dependencies {
classpath 'com.android.tools.build:gradle:3.0.0-alpha1'
}
For me this was not only an issue on Android O but also on older versions.
The oldest version I tested was API Level 16.
I was instantiating my fragments using this code:
MyFragment myFragment = MyFragment.newInstance();
myFragment.setTargetFragment(ParentFragment.this, 0);
myFragment.show(getActivity().getSupportFragmentManager(), null);
Where ParentFragment.this is a custom class extending android.support.v4.app.Fragment, MyFragment also extends this class and is a child fragment of the ParentFragment fragment (hence it's name).
I thought that I had to use a SupportFragmentManager (the getSupportFragmentManager() method) because I am using a fragment of the support package so I tried to call getActivity().getSupportFragmentManager() to get an activity reference that supported this method.
This does not seem to be the correct way though.
I changed those calls to:
MyFragment myFragment = MyFragment.newInstance();
myFragment.setTargetFragment(ParentFragment.this, 0);
myFragment.show(getFragmentManager(), null);
so the fragment decides on it's own which FragmentManager to use and the error is gone now.
Hope this helps someone.
I had the same problem, definitely an android bug. It happens when you are showing a fragment from another fragment using it as target. As workaround you can use:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
getActivity().getFragmentManager().beginTransaction().add(dialogFrag, "dialog").commit();
else
getChildFragmentManager().beginTransaction().add(dialogFrag,"dialog").commit();
I just faced the same issues in the project that I am currently working on when we moved to Android Studio 3 and upgraded the support library to version 26. All of a sudden, without changing the code, we got tons of this exception. In the end I found out the following:
Google added a new "sanity check" in the sources of the v4 Fragment Manager in January this year (not sure into what release that went) that refuses to add a fragment using a Fragment Manager, if it has a target fragment set and the target fragment cannot be found in the active fragments of the same Fragment Manager. The patch is described in detail here
Ealier versions seem to not have cared about that. Took me a few days to update all the areas in our code where fragments that were added using the Support Fragment Manager used the Child Fragment Manager for their subfragments with the parent fragment as target. Well, late penalty for writing bad code.
I had the same case as Markus Ressel but I was using getChildFragmentManager(). I replaced that with getFragmentManager() and it resolved the issue.
UPDATE: I've now been working with childFragmentManager and have some feedback.
When dealing with inner fragments that are hosted by a fragment (so a fragment within a fragment) use the childFragmentManager. This fragment manager differs from the activities getSupportFragmentManager. The two are not the same. It's a separation of concerns.
So I've made a rule that fragments hosting child fragments will always use the childFragmentManager and things not inside host fragments can use getSupportfragmentManager.
Recently, my app experienced the same issue when I targeted it for Android O. As a solution, use:
myDialogFragment.show(SettingsFragment.this.getFragmentManager(), TAG);
instead of:
myDialogFragment.show(getFragmentManager(), TAG);
// or
myDialogFragment.show(getSupportFragmentManager(), TAG);
// or
myDialogFragment.show(getChildFragmentManager(), TAG);
while working on an app, I encountered the same problem and I solved it by (in kotlin)
chooseRegionFragment.setTargetFragment(this#ParentFragment, REQUEST_CODE_CHOOSE_REGION)
chooseRegionFragment.show(this#ParentFragment.parentFragmentManager, TAG)
it translates to
chooseRegionFragment.setTargetFragment(ParentFragment.this, REQUEST_CODE_CHOOSE_REGION);
chooseRegionFragment.show(ParentFragment.this.getParentFragmentManager, TAG);
in java
my app work well until upgrade target version to 27 then i face same issue when call setTargetFragment (Fragment fragment,
int requestCode)
example:
chooseRegionFragment.setTargetFragment(ParentFragment.this, REQUEST_CODE_CHOOSE_REGION);
just change to:
chooseRegionFragment.setTargetFragment(getRootParentFragment(this), REQUEST_CODE_CHOOSE_REGION);
getRootParentFragment(this) this method will find root parent of fragments for you
/**
* find root parent of fragment
*/
public static Fragment getRootParentFragment(Fragment fragment) {
Fragment parent = fragment.getParentFragment();
if(parent == null)
return fragment;
else
return getRootParentFragment(parent);
}
Use below solution and you do not need to worry about which fragment managers you are dealing with,
Assuming that you must have used a BaseFragment.
First create an interface:
public interface OnRequestUpdateListener {
void onRequestUpdate(final int requestCode, final Intent data);
void setRequestFragment(final BaseFragment requestFragment, int requestCode);
BaseFragment getRequestFragment();
int getRequestCode();
}
Implement that interface in your BaseFragment
public class BaseFragment extends Fragment implements OnRequestUpdateListener {
private BaseFragment requestFragment;
private int requestCode;
#Override
public void onRequestUpdate(int requestCode, Intent data) {
// you can implement your logic the same way you do in onActivityResult
}
#Override
public void setRequestFragment(BaseFragment requestFragment, int requestCode) {
this.requestFragment = requestFragment;
this.requestCode = requestCode;
}
#Override
public BaseFragment getRequestFragment() {
return requestFragment;
}
#Override
public int getRequestCode() {
return requestCode;
}
}
Then, replace the setTargetFragment with setRequestFragment and replace getTargetFragment with getRequestFragment.
Here, you could also user onRequestUpdate in place of onActivityResult.
This is a custom solution without bothering about the which fragment manager you are using.
Using getFragmentManager() instead of getChildFragmentManager() would also work but it affects getParentFragment(). If you do not use a getChildFragmentManager() for nested fragment then you will not be able the get the parent fragment by using getParentFragment() in child/nested fragment.

How to use default animations in Android?

I'm trying to use the default animations for the Activity with fragments.. here I found something about it:
Android: using Activity's default animation for Fragments
the problem is: ok, I need (for example) "activityOpenEnterAnimation".. how can I use it?
Using the following code won't work:
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.setCustomAnimations(android.R.anim.activityOpenEnterAnimation, android.R.anim.activityOpenExitAnimation);
transaction.replace(R.id.container, fragment)
.addToBackStack(((Object) fragment).getClass().getName())
.commit();
Hints? Thanks! :)
Nowadays, Android documentation clearly recommends not to use resources directly from android.R.*, since every release of the platform has changes on them. Even some resources dissapear from one version to another, so you shouldn't rely on them. On the other hand, lots of resources are private and not available from a developer's code.
The safest (and recommended) way is to simply copy & paste the resources you need (in this case, the animations) from the source code of the Android version you want into your own code, and use them through the regular R.*.
You can browse the Android source code in many ways, as explained in [1].
[1] Where can I find Android source code online?
example of using default android animation when back pressed happen
#Override
public void onBackPressed() {
super.onBackPressed();
overridePendingTransition(android.R.anim.fade_in,android.R.anim.fade_out);
}
for using default animations you should use android.R.anim.ANIMATIONNAME
I managed to get it to work this way:
static public int getResourceIdFromCurrentThemeAttribute(FragmentActivity activity, int attribute){
TypedValue a = new TypedValue();
activity.getTheme().resolveAttribute(attribute, a, false);
return a.resourceId;
}
//This type of fragment will be opened like an activity
static public void openActivityLikeFragment(FragmentActivity activity, BaseFragment fragment, int containerId, String stackRef) {
FragmentManager fm = activity.getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
//The fragment open/close transition should have the same animations as its activity
ft.setCustomAnimations(
getResourceIdFromCurrentThemeAttribute(activity, android.R.attr.activityOpenEnterAnimation),
getResourceIdFromCurrentThemeAttribute(activity, android.R.attr.activityOpenExitAnimation),
getResourceIdFromCurrentThemeAttribute(activity, android.R.attr.activityCloseEnterAnimation),
getResourceIdFromCurrentThemeAttribute(activity, android.R.attr.activityCloseExitAnimation)
);
ft.replace(containerId, fragment);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.addToBackStack(stackRef);
ft.commit();
}
This solution is safer than directly referencing a resource, since its referencing an attribute which won't change without some deprecation warnings first.

Categories

Resources