How to know when enter transition ended on Fragment? - android

I have a fragment, which shows enter animation, I set transition by
this.setEnterTransition(transition);
After that I want to show another animation. But I need to know when transition animation ends to start the second one.
For activity there is a callback like onEnterAnimationComplete() but it is not called when Fragment's transition ends.
Is there any way to know when enter transition ends for the Fragment?

transition.addListener(new Transition.TransitionListener() {
#Override
public void onTransitionStart(Transition transition) {}
#Override
public void onTransitionEnd(Transition transition) {}
#Override
public void onTransitionCancel(Transition transition) {}
#Override
public void onTransitionPause(Transition transition) {}
#Override
public void onTransitionResume(Transition transition) {}
});
this.setEnterTransition(transition);

If you have the following setup:
FragmentA calls FragmentB with a SharedElementEnterTransition like
private final TransitionSet transition = new TransitionSet()
.addTransition(new ChangeBounds());
//...
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction()
.replace(R.id.container, fragment, fragment.getClass().getSimpleName());
transaction.addSharedElement(view, view.getTransitionName());
fragment.setSharedElementEnterTransition(transition);
fragment.setSharedElementReturnTransition(transition);
transaction.commit();
to listen for the end of the SharedElementTransition in your second Fragment. Then you have to get the SharedElementEnterTransition in your FragmentB's onAttach like:
#Override
public void onAttach(Context context) {
super.onAttach(context);
TransitionSet transitionSet = (TransitionSet) getSharedElementEnterTransition();
if (transitionSet != null) {
transitionSet.addListener(new Transition.TransitionListener() {
#Override
public void onTransitionEnd(#NonNull Transition transition) {
// remove listener as otherwise there are side-effects
transition.removeListener(this);
// do something here
}
#Override
public void onTransitionStart(#NonNull Transition transition) {}
#Override
public void onTransitionCancel(#NonNull Transition transition) {}
#Override
public void onTransitionPause(#NonNull Transition transition) {}
#Override
public void onTransitionResume(#NonNull Transition transition) {}
});
}
}
As pointed out in the comments of this answer there is a bug when not setting the listener in onAttach().

Related

Handling activity toolbar visibility according to visible fragment

In my android application I have one activity and many fragments. However, I only want to show the toolbar for some fragments, for the others I want the fragment to be fullscreen. What's the best and recommended way to do this (show and hide the activity toolbar according to the visible fragment)?
I preferred using interface for this.
public interface ActionbarHost {
void showToolbar(boolean showToolbar);
}
make your activity implement ActionbarHost and override showToolbar as.
#Override
public void showToolbar(boolean showToolbar) {
if (getSupportActionBar() != null) {
if (showToolbar) {
getSupportActionBar().show();
} else {
getSupportActionBar().hide();
}
}
}
Now from your fragment initialize from onAttach()
private ActionbarHost actionbarHost;
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof ActionbarHost) {
actionbarHost = (ActionbarHost) context;
}
}
now just if you want to hide action bar call actionbarHost.showToolbar(false); from fragment.
if (actionbarHost != null) {
actionbarHost.showToolbar(false);
}
Also I'd suggest to show it again in onDetach()
#Override
public void onDetach() {
super.onDetach();
if (actionbarHost != null) {
actionbarHost.showToolbar(true);
}
}
Since you want different representations, each of your fragments should have (when you want) their own toolbar.
Hence your Activity's layout will have a simple fragment_container.
if you are using viewPager then you can do this using only single toolbar in your MainActivity
pager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
if(position==YourFragmentPosition)
{
toolbar.setVisibility(View.VISIBLE);
}
else{
toolbar.setVisibility(View.GONE);
}
}
}
#Override
public void onPageScrollStateChanged(int state) {
});

How to hide BottomNavigation bar(Botton Navigation Bar Activity) in specific Fragment

I know I am not the first to ask this question but I have referred many SO post regarding this but nothing is solved my query .
What I want to do is in my MainActivity(Bottom Navigation bar Activity) I have Bottom Navigation Bar, In this MainActivity I have cardviews If I clicked on the cardview I need to show another fragment in that fragment I want to hide the bottom navigation bar .And When I nav back to MainActivity botoom Navigation bar should be there.
Here in my case Alarm.java is the fragment where I want to hide the bottom navigation bar.
Alarm.java
public class Alarm extends Fragment {
private OnFragmentInteractionListener mListener;
public Alarm() {
}
public static Alarm newInstance(String param1, String param2) {
Alarm fragment = new Alarm();
Bundle args = new Bundle();
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_alarm, container, false);
}
public void onButtonPressed(Uri uri) {
if (mListener != null) {
mListener.onFragmentInteraction(uri);
}
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
public interface OnFragmentInteractionListener {
void onFragmentInteraction(Uri uri);
}
}
In your MainActivity you can implement two methods that will be responsible for showing and hiding your BottomNavigationView. For example, these two methods animate it sliding up and down:
private void hideBottomNavigationView(BottomNavigationView view) {
view.clearAnimation();
view.animate().translationY(view.getHeight()).setDuration(300);
}
public void showBottomNavigationView(BottomNavigationView view) {
view.clearAnimation();
view.animate().translationY(0).setDuration(300);
}
In MainActivity you call hide right before opening your CardView, and call show in onCreate or onResume.
EDIT:
But, I think that a cleaner way would probably be to create an interface in your Fragment:
public interface OnCardViewOpenedInterface{
void onOpen(); // hide bottom bar when photo is opened
void onClose(); // show bottom bar when photo is opened
}
And call these methods in onStop and onResume of your Fragment:
#Override
public void onStop() {
super.onStop();
mListener.onClose();
}
#Override
public void onResume() {
super.onResume();
mListener.onOpen();
}
And then implement the interface in your MainActivity, override the methods onOpen() and onClose() and inside call your hide and show methods.
They will probably both work, maybe the second one is overcomplicated, it's just I like it more.
I have tried the method by #Suleyman but it didn't work for me. The simplest solution is to use a public static method in the MainActivity and reference it from the fragment where you want to hide the bottom navigation bar.
Don't forget to initialize navView as public static.
In your MainActivity
public static void hideBottomNav(){
navView.setVisibility(View.GONE);
}
public static void showBottomNav(){
navView.setVisibility(View.GONE);
}
In your MyFragment
#Override
public void onResume() {
super.onResume();
MainActivity.hideBottomNav();
}
#Override
public void onStop() {
super.onStop();
MainActivity.showBottomNav();
}

How to show banner ads in fragment Revmob?

I would like to show banners in a fragment instead of an activity, how can I do this?
My Fragment:
Variables:
RevMob revmob;
Activity currentActivity;
Functions:
My Code:
public void startRevMobSession(){
currentActivity = this;
revmob = RevMob.startWithListener(currentActivity, new RevMobAdsListener() {
#Override public void onRevMobSessionStarted() {loadBanner();}
#Override public void onRevMobSessionNotStarted(String message) {}});
}
public void loadBanner() {
revmob.showBanner(currentActivity, Gravity.BOTTOM, null, new RevMobAdsListener() {
#Override public void onRevMobAdReceived() {}
#Override public void onRevMobAdNotReceived(String message) {}
#Override public void onRevMobAdDismissed() {}
#Override public void onRevMobAdClicked() {}
#Override public void onRevMobAdDisplayed() {}});
}
onCreate:
startRevMobSession();
It's working when I'm using it in an activity, but I would like to use it in a fragment. How can I do so?
In a fragment you should do:
currentActivity = getActivity();
instead of
currentActivity = this;
That's the only difference, it should all work properly then.

EventBus event between two fragments not fired

Problem: I am using EventBus by greenrobot to pass some events.
It is working for me unfortunately for the scenario of passing data between two fragments it does not. So the event does not get fired.
Question: Do I misunderstand the concept? Or is there a mistake in my code?
Note: Both Fragments exist at the time of sending the event. One fragment is the parent and the other one the child to display details.
detail fragment:
public class DetailFragment extends Fragment {
(...)
refreshButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
EventBus.getDefault().post(new IntentRefresh());
}
});
(...)
}
EventBus class:
public class IntentRefresh {
public IntentRefresh (){}
public void refreshParent() {
}
}
parent fragment:
public class ParentFragment extends Fragment {
(...)
#Override
public void onPause() {
super.onPause();
EventBus.getDefault().unregister(this);
}
#Override
public void onResume() {
super.onResume();
EventBus.getDefault().register(this);
}
#Subscribe(threadMode = ThreadMode.MAIN)
public void updateList(IntentRefresh intentRefresh) {
Toast.makeText(getActivity(), "LUEEEEPT", Toast.LENGTH_SHORT).show();
}
(...)
}
The Fragment lifecycle is quite a bit more complicated than the Activity lifecycle. I would guess that your onResume() isn't being called how you think it is. I would recommend moving your registering and un registering to the onAttach() and onDetach() methods.
I use #CaseyB's answer. its working for me perfectly.Like below
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (!EventBus.getDefault().isRegistered(this))
EventBus.getDefault().register(this);
}
#Override
public void onDetach() {
super.onDetach();
EventBus.getDefault().unregister(this);
}
#Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(CallbackModel event) {
}

Memory leak using Lollipop's transitions

I'm trying to implement transition between fragment (that attached to the MainActivity) with RecyclerView and the DetailActivity.
In my fragment, I've added RecyclerView listener in onStart() method:
#Override
public void onStart() {
super.onStart();
mRecyclerItemClickListener = new RecyclerItemClickListener(getActivity(), (view, position) -> {
Intent intent = new Intent(getActivity(), DetailActivity.class);
intent.putExtra(ConstantsManager.POSITION_ID_KEY, mFilmsAdapter.getImdbIdByPosition(position));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
ActivityOptionsCompat optionsCompat = ActivityOptionsCompat
.makeSceneTransitionAnimation(getActivity());
ActivityCompat.startActivity(getActivity(), intent, optionsCompat.toBundle());
} else {
startActivity(intent);
}
});
mRecyclerView.addOnItemTouchListener(mRecyclerItemClickListener);
mSwipeRefreshLayout.setOnRefreshListener(this);
mTopFilmsPresenter.attachView(this);
mTopFilmsPresenter.getFilms();
}
You can see, that the transition begins in the if block. In the DetailActivity I have the following method which I call in onCreate():
#TargetApi(Build.VERSION_CODES.KITKAT)
private void setupWindowAnimations() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Explode explode = new Explode();
explode.setDuration(ConstantsManager.TRANSITION_DURATION);
getWindow().setEnterTransition(explode);
getWindow().setExitTransition(explode);
}
}
And in the MainActivity I have almost a similar method, which I also call in onCreate():
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void setWindowAnimations() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Explode explode = new Explode();
explode.setDuration(ConstantsManager.TRANSITION_DURATION);
getWindow().setEnterTransition(explode);
getWindow().setExitTransition(explode);
getWindow().setReenterTransition(explode);
getWindow().setReturnTransition(explode);
}
}
I've also implemented Transition.TransitionListener interface in the DetailActivity, because documentation says:
A transition listener receives notifications from a transition. Notifications indicate transition lifecycle events.
So I'm trying to remove listener in the onTransitionEnd(Transition transition), onTransitionCancel(Transition transition) and onTransitionPause(Transition transition) callbacks:
#Override
public void onTransitionStart(Transition transition) {
}
#TargetApi(Build.VERSION_CODES.KITKAT)
#Override
public void onTransitionEnd(Transition transition) {
transition.removeListener(this);
}
#TargetApi(Build.VERSION_CODES.KITKAT)
#Override
public void onTransitionCancel(Transition transition) {
transition.removeListener(this);
}
#TargetApi(Build.VERSION_CODES.KITKAT)
#Override
public void onTransitionPause(Transition transition) {
transition.removeListener(this);
}
#Override
public void onTransitionResume(Transition transition) {
}
I'm using LeakCanary for memory leaks detections and it detects a memory leak after transition:
So I am wondering how can I remove transition listener(s) to prevent this memory leak?
Ensure that you release the Activity reference since you are strongly holding onto it within the Transition class. A simple Transition.removeListener(this) (since your activity implements the interface) in it's onDestroy() method should prevent memory leaks.
Thanks Albert Vila for the answer. The problem lies in TransitionManager.sRunningTransitions according to this topic.

Categories

Resources