I'm currently in the process of creating my first android app, and was wondering what the method would be to set a cardview to raise up and then expand into a larger rectangle, revealing a new fragment?
edit: (the new fragment would fill up the center third of the screen, no matter where the original card was located)
Authentic Motion
Tangible surfaces don’t just appear out of nowhere like a jump-cut in
a movie; they move into place helping to focus attention, establish
spatial relationships and maintain continuity. Materials respond to
touch to confirm your interaction and all changes radiate outward from
your touch point. All motion is meaningful and intimate, aiding the
user’s comprehension.
Activity + Fragment Transitions
By declaring ‘shared elements’ that are common across two screens you
can create a smooth transition between the two states.
album_grid.xml
…
<ImageView
…
android:transitionName="#string/transition_album_cover" />
album_details.xml
…
<ImageView
…
android:transitionName="#string/transition_album_cover" />
AlbumActivity.java
Intent intent = new Intent();
String transitionName = getString(R.string.transition_album_cover);
…
ActivityOptionsCompat options =
ActivityOptionsCompat.makeSceneTransitionAnimation(activity,
albumCoverImageView, // The view which starts the transition
transitionName // The transitionName of the view we’re transitioning to
);
ActivityCompat.startActivity(activity, intent, options.toBundle());
Here we define the same transitionName in two screens. When starting
the new Activity and this transition is animated automatically. In
addition to shared elements, you can now also choreograph entering and
exiting elements.
Source: Implementing Material Design
Related
I am creating a chatting app and when a image arrives in chat it looks like this.
Now I want to achieve WhatsApp like effect. I think on WhatsApp when you click the image it expands to whole screen with a smooth animation. I can add click Listener on the image but I don't know how to achieve that effect with smooth animation.
You can achieve this effect pretty easily with a SharedElementTransition. In short, you create a new activity that only displays the image and tell the framework which view from the first activity/fragment corresponds to the image in the new activity and the rest is done automatically.
In the new activity layout add a transition name to the ImageView. You'll have to load the image in this activity manually, so you have to pass the URL to the activity if you're loading from the network, or pass the bitmap in another way.
<ImageView
android:id="#+id/image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:transitionName="image"/>
When the image is clicked you start the activity and specify ImageView clicked and map it to the transitionName:
// If you're in a fragment
val activity = requireActivity()
// imageView here corresponds to the image before it is animated
// "image" is transitionName in the new activity
val options = ActivityOptionsCompat.makeSceneTransitionAnimation(activity, imageView, "image")
activity.startActivity(Intent(context, ImageActivity::class.java), options.toBundle())
Also, the style used for the activities must set android:windowContentTransitions to true:
<style name="...">
<item name="android:windowContentTransitions">true</item>
</style>
I'm working with Android Lollipop Transitions, and I've sumbled upon the following problem:
I have CardView with an ImageView and, on top of it, a TextView.
When I click on the card, a new Activity is launched, and it contains both the ImageView and the TextView in different positions.
If I don't include the TextView in the Transition as a shared element, it suddenly dissapears [goes behind] the ImageView, which doesn't look, well, great.
If I include it, it doesn't scale the text nicely and suddenly changes to the final size (I am aware of this solution already, but the problem is I want to keep also the default ImageView Transition, which is a combination of a ChangeBounds Transition, a ChangeImageTransform, ... among others).
So, anybody knows how to have different transitions being thrown for different shared views when launching the new Activity?
Cheers
The way you pointed to it in your answer can be applied for this purpose but it's actually for accepting only suitable View types by a special transition (such as only ImageViews for ChangeImageTransform).
You can use addTarget(Class targetType) instead:
final Transition transition = new TransitionSet()
.addTransition(new ChangeTransform()).addTarget(TextView.class) // Only for TextViews
.addTransition(new ChangeImageTransform()).addTarget(ImageView.class) // Only for ImageViews
.addTransition(new ChangeBounds()); // For both
setSharedElementEnterTransition(transition);
This way is more simple and more logical. Also, it can be used for some other filterings (by transitionName and etc). See addTarget() overloaded types.
OK,
This is achievable extending the Transition class. Since I wanted to animate differently an ImageView and a TextView, I just wrote a TextTransform child class ofTransform, analogous to the ChangeImageTransform one which is part of the Android API 21+. The key was overriding this method (shown the case for ChangeImageTransform which looks for ImageView objects):
#Override
private void captureValues(TransitionValues transitionValues) {
View view = transitionValues.view;
if (!(view instanceof ImageView) || view.getVisibility() != View.VISIBLE) {
return;
}
(...)
}
Then you apply all transforms to the new scene, and relevant transform will be attached to their corresponding views:
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
<fade android:fadingMode="fade_out" />
<changeBounds />
<changeImageTransform />
<com.mypackage.transforms.TextTransform />
<fade android:fadingMode="fade_in" />
</transitionSet>
And then you set this Transition on the OnCreate method of the new Activity using setSharedElementEnterTransition(inflatedTransitionSet);
Please look at this video showing a shared elements activity transition.
It's a transition from a list activity to a detail activity.
[Video link no longer works]
As you can see the imageview gets drawn in front of the tabs.
What I would expect is the tabs being drawn in font on the imageview and fading out throughout the transition (so that at the end of the animation they are gone).
The only thing that seems to work is setting windowSharedElementsUseOverlay to true,
but that has other ugly effects, so that seems not to be an option.
The most commonly suggested approach is to include the tabs in the transition itself, but the problem is that the tabs are not there in the detail activity so they cannot be shared.
Code:
I start the detail activity like this:
options = ActivityOptionsCompat.makeSceneTransitionAnimation(activity, pairs);
ActivityCompat.startActivity(activity, subActivity, options.toBundle());
I believe what you may need is to exclude, rather than include, the tab layout from the transition animation.
So in the onCreate of your list activity, include:
Transition fade = new Fade();
fade.excludeTarget(R.id.tab, true); // use appropriate id for you tab
getWindow().setExitTransition(fade);
getWindow().setEnterTransition(fade); // try getWindow().setReenterTransition(fade); instead
Definitely have a look at Alex Lockwood's answer to How do I prevent the status bar and navigation bar from animating during an activity scene animation transition? where he gives a greater and more in-depth but digestible explanation on the topic. You may also want to consider adding/implementing the solution in that post.
You should try this:
On the exiting activity, call getWindow().setExitTransition(null);
On the entering activity, call getWindow().setEnterTransition(null);
It will prevent the fade out of the exiting activity and the fade in of the entering activity, which removes the apparent blinking effect and make transition smooth.
My calling activity has a both a tablayout and a toolbar within and each time I did the transition, the image would appear on top of both tablayout and toolbar, making the transition look untidy.
I fixed the problem quite elegantly by just adding a "dummy" tablayout and a "dummy" toolbar in my called activity. The "dummy" elements are not visible so it doesn't impact the layout of my called activity but the transition effect will work properly if you add them in.
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar2"
android:transitionName="toolbar"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" />
<android.support.design.widget.TabLayout
android:id="#+id/sliding_tabs"
android:layout_width="match_parent"
android:layout_height="60dp"
android:visibility="gone"
android:transitionName="tab"
></android.support.design.widget.TabLayout>
I then added the tablayout and the toolbar as a pair in my transition:
Pair<View, String> p4 = Pair.create(getActivity().findViewById(R.id.sliding_tabs), "tab");
Pair<View, String> p5 = Pair.create(getActivity().findViewById(R.id.toolbar), "toolbar");
Bundle options = ActivityOptionsCompat.makeSceneTransitionAnimation(getActivity(), p1, p2, p3, p4, p5).toBundle();
My goal is to create an Android UI window that displays three regions: navigation, main, and popup. The navigation and main region will function as a split view. The popup region will be centered in the screen and overlay the other two regions; it will also only be visible part of the time. Ideally, I'd like these regions to host fragments that are dynamically changed to display different layouts and view models based on user interaction. And, all of this should be accomplished without breaking the MvvmCross bindings.
I've got something that works, but it feels a bit hacked together. The current implementation most closely follows resource 1 below. Each region has a dictionary. All of the fragments are registered with a dictionary based on their target region. This is done from the activity. The activity also takes care of inflating each layout and associating it with the correct view model. I’d like to change this so that MvvmCross can do more of the work.
Is it possible to create a custom presenter, in Android, that is a mix between the dynamic fragment layout from resource 2 and the iOS custom presenter shown in resource 3? Just to clarify, I want to specifically define where each region will be displayed using a layout. Then I want to dynamically fill the content, of each region, with different layouts and their associated view models, at runtime.
Resource 1: MvvmCross v3 Fragment Sample
https://github.com/slodge/MvvmCross-Tutorials/tree/master/Fragments
See: “FragmentSample.UI.Droid/Views/TitlesView.cs” and “FragmentSample.UI.Droid/Setup.cs”
Resource 2: N=26 - Androids… down at Fragment Rock
http://www.youtube.com/watch?feature=player_embedded&v=uQT3_WXQQr0
Dynamic Fragment Layout created explained at 26:25 – 32:10
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<FrameLayout
android:id="#+id/subframe1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<FrameLayout
android:id="#+id/dubframe1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>
(In addition to being an extremely helpful video, of all the N+1 videos I've had a chance to watch, this one has the best intro!)
Resource 3: N=24 - Split View
http://www.youtube.com/watch?feature=player_embedded&v=PpeysFIINcY
iOS SplitPresenter created at 11:25 – 15:05
public class SplitViewController : UISplitViewController
{
public SplitViewController()
{
this.ViewControllers = new UIViewController[]
{
new UIViewController(),
new UIViewController(),
};
}
public void SetLeft(UIViewController left)
{
this.ViewControllers = new UIViewController[]
{
left,
this.ViewControllers[1]
};
}
public void SetRight(UIViewController right)
{
this.ViewControllers = new UIViewController[]
{
this.ViewControllers[0],
right,
};
}
}
I created a small example project on GitHub that demonstrates how to create multiple regions.
This shows the three regions: Navigation, Main and Popup. The location, size and shape of each region is defined in one layout file. The content is defined, with separate layout files and view models, for each region and is dynamically changed at runtime. MvvmCross bindings still work with each individual view model.
EDIT
I added a more robust solution example on github. This allows the ViewModel to be opened in the standard way. The MultiRegionPresenter handles matching up the view with the correct region by looking at a tag in the view. Views are now tagged with their intended region like this: [Region(Resource.Id.MainRegion)].
The new example project is located here: MultiRegionPresenter Example
Suppose I have 2 XML files and my activity will setContentView the appropriate one based on some button press from the user. Is it possible to change the transition animation for the changing of content view?
So far I see super.overridePendingTransition() which is suitable for starting new activities, however my example does not start a new activity, it just changes the layout in the current one.
Mathias Lin has explained it very well.
You can always use default stock animations supplied by Android framework.
Heres an example code:
boolean isFirstXml=evaluatingConditionFunction();
LayoutInflater inflator=getLayoutInflater();
View view=inflator.inflate(isFirstXml?R.layout.myfirstxml:R.layout.myseconxml, null, false);
view.startAnimation(AnimationUtils.loadAnimation(this, android.R.anim.slide_out_right));
setContentView(view);
Call this from any of your activity which holds your Parent View.
For custom animations you can visit developer docs. Heres the documentation link.
Yes, you can apply an animation on almost any view you like. Just via view.startAnimation(animation);
Take the outer viewgroup of your respective layout (content view) and apply the animation to it. Depending what kind of animation you want to do, it might make sense to inflate/load both layouts but hide one of them and then swap. Please specify what kind of transition you have in mind.
For example: if you do an alpha transition, you would run the alphaAnimation on the current layout, when when the animation ends (AnimationListener), you set the content view to the new layout, and fade the content back in, via another alphaAnimation.
A better solution is using ViewFlipper: it is a FrameLayout, that can do animations when changing the views.
<ViewFlipper
android:id="#+id/[your_id_here]"
android:inAnimation="..."
android:outAnimation="..."
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<RelativeLayout
<!--Your first layout -->
</RelativeLayout>
<RelativeLayout
<!--Your second layout -->
</RelativeLayout>
</ViewFlipper>
Then, switch the views with setDisplayedChild(int) or showNext() or showPrevious. If you want to have different animation for left and right movement, you have to set inAnimation and outAnimation in the code before transition.
More complete example is here.