I have an app where I used default slide in/out effects on standards activities and fade in/out on a few specific activities.
I've noticed that the new Android 4.X (ICS) has a different default, which is exactly fade in/out.
How can i define on my standard activities my slide in/out effect?
I've been trying to define it with:
#Override
public void onCreate(Bundle savedInstanceState)
{
this.overridePendingTransition(0, android.R.anim.slide_in_left);
super.onCreate(savedInstanceState);
}
#Override
public void onPause()
{
super.onPause();
overridePendingTransition(android.R.anim.slide_out_right, 0);
}
To reproduce the fade in / out effect i'm using:
#Override
public void onCreate(Bundle savedInstanceState)
{
this.overridePendingTransition(0, android.R.anim.fade_in);
super.onCreate(savedInstanceState);
}
#Override
public void onPause()
{
super.onPause();
overridePendingTransition(android.R.anim.fade_in, 0);
}
but haven't managed to successfully reproduce it.
Also, I'm using this code on onCreate and onPause, is this correct? Or is there a better place to put it?
Thanks
PS: I've seen this New Android 4.0 Screen Transitions Between Activities but now answer has been provided.
overridePendingTransition() has to be called immediately after starting the new activity, so you would call it after startActivity(intent), for example.
To make a default you can create a class that extends Activity and override startActivity, onBackPressed(), etc. to override the transition. For example:
public class MyActivity extends Activity {
#Override
public void onBackPressed() {
super.onBackPressed();
overridePendingTransition(R.anim.slide_in_transition,R.anim.slide_out_transition);
}
#Override
public void startActivity(Intent intent) {
super.startActivity(intent);
overridePendingTransition(R.anim.slide_in_transition,R.anim.slide_out_transition);
}
#Override
public void finish() {
super.finish();
overridePendingTransition(R.anim.slide_in_transition,R.anim.slide_out_transition);
}
}
Then, just extend MyActivity instead of Activity in your activities and the transitions should all be sliding by default.
Related
I have a use case where I mostly start an activity with a transition, but that's not the case when opening it from the navigation drawer.
To keep the transition smooth I have a Transition.TransitionListener in which I trigger some UI updating when the transition is done.
So I have something like this:
public class SomeActivity extends Activity {
public void onCreate(Bundle savedInstanceState){
// ...
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
Transition sharedElementEnterTransition = getWindow().getSharedElementEnterTransition();
sharedElementEnterTransition.addListener(new Transition.TransitionListener() {
// ...
#Override
public void onTransitionEnd(Transition transition) {
doSomeUiUpdating();
}
});
} else { // Pre-Lollipop
doSomeUiUpdating();
}
}
}
This works well when starting the Activity with the animation, but how can I know if the Activity was started without a transition so that I can call doSomeUiUpdating()?
I'm sure there must be a simple method in Activity, Window, Transition or somewhere that I have overlooked. I don't want to relay on the calling Activity to set some bundle that telling if the animation is showing or not.
You can try onTransitionStart of TransitionListener to set some boolean isAnimationStarted.
public class SomeActivity extends Activity {
private boolean isAnimationStarted = false;
public void onCreate(Bundle savedInstanceState) {
// ...
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
Transition sharedElementEnterTransition = getWindow().getSharedElementEnterTransition();
sharedElementEnterTransition.addListener(new Transition.TransitionListener() {
// ...
#Override
public void onTransitionEnd(Transition transition) {
doSomeUiUpdating();
}
#Override
public void onTransitionStarted(Transition transition) {
isAnimationStarted = true;
}
});
}
}
public void onStart() {
if (!isAnimationStarted) {
doSomeUiUpdating();
}
}
}
Since you are starting an Activity, you'll be making use of an Intent to start it. You can add extras to Intents and check for them in the onCreate() of the called Activity.
Let's assume that we have 2 Activities – ActivityA, and ActivityB.
Now, let's assume that ActivityA is the calling Activity, and that ActivityB is the called Activity.
In ActivityA, let's say you've written some code to start ActivityB with a SharedElementTransition.
#Override
public void onClick(View v) {
Intent startActivityBIntent = new Intent(getContext(), ActivityB.class);
startActivityBIntent.putExtra("IS_SHARED_ELEMENT_TRANSITION_ENABLED", true);
ActivityOptionsCompat activityOptionsCompat = ActivityOptionsCompat.makeSceneTransitionAnimation(getActivity(), view, ViewCompat.getTransitionName(view));
startActivity(startActivityBIntent, activityOptionsCompat);
}
Now, if you notice above, I've passed an Intent extra with the putExtra() method. I've passed a Boolean value of true because I intend to start the Activity with a SharedElementTransition.
Now in ActivityB's onCreate() method, you can just check for the boolean value passed to the Intent. If you passed false, then you can add a conditional statement and perform your UI updating there. I've given you a small snippet below to help you get started:
private static final String isSharedElementTransitionEnabled = "IS_SHARED_ELEMENT_TRANSITION_ENABLED";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_b);
// If you are postponing your SharedElementTransition, don't forget to call postponeEnterTransition() and override onPreDraw()
if (!getIntent().getExtras().getBoolean(isSharedElementTransitionEnabled)) {
//Do your UI updation here
}
}
The good thing about doing it this way is that you can then have full control over how your content transitions and your shared element transitions will play out.
The project that I'm working uses a view-presenter abstraction.
Here is a simplified version of all the main classes.
The abstract activity (wire Presenter instance, with View)
public abstract class MvpActivity<Presenter extends MvpPresenter>
extends ActionBarActivity {
protected Presenter mPresenter;
#Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPresenter = getPresenterInstance();
}
#Override protected void onResume() {
super.onResume();
mPresenter.onResume(this);
}
#Override protected void onPause() {
mPresenter.onPause();
super.onPause();
}
}
The view interface
public interface MyView {
void redirect();
}
The view implementation
public class MyActivity
extends MvpActivity<MyPresenter>
implements MyView {
#Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_view);
Button myButton = (Button)findViewById(R.id.my_button);
myButton.setOnClickListener(v -> mPresenter.onButtonPressed());
}
#Override protected MyPresenter getPresenterInstance() {
return new MyPresenter();
}
#Override void redirect(){
startActivity(new Intent(this, MyOtherActivity.class));
}
The abstract presenter
public abstract class MvpPresenter<ViewType> {
private ViewType mView;
public void onResume(ViewType view) {
mView = view;
}
public void onPause() {
mView = null;
}
protected ViewType getView() {
if (mView == null) {
throw new IllegalStateException("Presenter view is null");
}
return mView;
}
}
And the presenter implementation
public class MyPresenter extends MvpPresenter<MyView> {
#Override public void onResume(MyView myView){
super.onResume(myView);
Log.("MyPresenter", "Presenter resumed");
}
#Override public void onPause(){
super.onPause()
Log.("MyPresenter", "Presenter paused");
}
public void onButtonPressed(){
getView().redirect();
}
}
The issue comes up as an "IllegalStateException: Presenter view is null" triggered by getView().redirect(); when called from the MyPresenter.onButtonPressed() method.
This doesn't make any sense to me, as the view should always be not null if the listener is fired. The view is only set to null if the MvpPresenter.onPause() is executed which is only being called from MvpActivity.onPause(). I wouldn't expect to receive any click events after this happens, so what am I missing here?
Sadly, I can not reproduce this issue by manually testing the application. The reports are coming in from Crashlytics.
Note: retrolambda is in use for the button click listener
Update 10/07/2017
Some ways of fixing this issues:
-
https://developer.android.com/reference/android/view/View.html#cancelPendingInputEvents()
-
https://github.com/JakeWharton/butterknife/blob/master/butterknife/src/main/java/butterknife/internal/DebouncingOnClickListener.java
Short answer: don't do that.
Unfortunately, you're relying on an order of events that is undefined. Activity lifecycle events and Window events are two different things, even though they're often closely related. You'll get onPause() when the activity is paused for any reason. But the View touch events aren't unhooked until the View's window loses focus.
It's very common for an activity to pause right when its window loses focus--for instance, when the screen is locked or when another activity is launched. But as you've seen, you can get pauses without a focus change and focus changes without a pause. Even when the two events occur together, there's a narrow window of time when onPause() has been called but the window input handlers are still active.
As with any undefined behavior, the actual results you see will vary by OS version and hardware type.
If you need to make sure that you don't receive View messages after onPause, you should unhook your handlers in onPause.
I've been trying to use the new fancy animations that come with the L developer preview, but I'm having a lot of difficulties. In particular, I am not seeing any fancy animations. I'm trying to use the Explode exit transition. Here's the code:
public class ActivityA extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// inside your activity
getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
// set an exit transition
getWindow().setExitTransition(new Explode());
setContentView(R.layout.activity_a);
// Find our button and add our click handler
Button button = (Button)findViewById(R.id.buttonA);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// Transition to activity B
Intent intent = new Intent(ActivityA.this, ActivityB.class);
startActivity(intent);
}
});
}
}
Instead of starting another activity using startActivity(intent); use the following statement.
startActivity(intent,ActivityOptions.makeSceneTransitionAnimation(this).toBundle());
I started another activity as said above and it worked for me.
It's said in google documentation Defining Custom Animations as follows.
Solved the problem - you need the
getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
call on the activity you are transitioning too as well!
Try this.
public class MyActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// enable transitions
getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
setContentView(R.layout.activity_my);
}
public void onSomeButtonClicked(View view) {
getWindow().setExitTransition(new Explode());
Intent intent = new Intent(this, MyOtherActivity.class);
startActivity(intent,
ActivityOptions
.makeSceneTransitionAnimation(this).toBundle());
}
}
requestFeature in onCreate an setExitTransition before startActivity
What happens when finish() method is called in onStop() method?
Does it causes anr : means it calls
onPause()->onStop()->finish()->onPause()....
or it finishes the activity : means it calls directly
onDestroy()
Actually, I want to finish my activity when it is completely invisible.
EDIT:
See this scenario, I launch an activity B whose layout height and
width is smaller than activity A, so activity A is partially visible
and when I press the home button activity A becomes completely
invisible. At this point I want to close activity A, so that it do not
call onRestart().
Thanks in advance.
It finishes the activity and onDestroy() is called. If you want to finish your activity when it is invisible then you should call finish() in onStop().
according to your scenario, maintain one flag in MainActivity indicating that other Activity is launched or not? and make sure yourself to finish MainActivity or not based on that flag ...
this may help you...
public class MyActivity extends Activity {
private boolean isSecondActivityLaunched;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
protected void onResume() {
super.onResume();
isSecondActivityLaunched = false;
}
public void onClick(View view) {
Intent intent = new Intent(this, SecondActivity.class);
startActivity(intent);
isSecondActivityLaunched = true;
}
#Override
protected void onStop() {
super.onStop();
if(!isSecondActivityLaunched) {
finish();
}
}
}
It will be best way in your case to call finish() ;
Thanks
I'm trying to make an app where you start at a menu, click a button and are brought to a list of items (which I later hope to make clickable). But I can't seem to make it call my next activity. Can anyone help?
Your main class / activity:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Menu Button
Button startNewActivity = (Button)findViewById(R.id.startnew);
startNewActivity.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Intent newActivityIntent = new Intent(YOUR-CLASS-NAME.this,NewActivity.class);
startActivity(newActivityIntent);
}
});
Your NewActivity Class:
public class NewActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.new);
}
}
Is the question "How do I call the next activity" ?
If so, it's pretty easy - Assuming the Activity you want to call is "SomeActivity", call this:
Intent someActivity = new Intent(getBaseContext(), SomeActivity.class);
startActivity(someActivity);
There's also a "startActivityForResult" method, if you want data back from the Activity you're calling. For reference, the Activity page of the API Documentation can be found here. Good luck!