I'm trying to create an app using exoplayer, and I'd like to implement a "pull down to exit fullscreen" gesture just like the youtube app has. The gesture itself seems to be doable using a gesture detector, but i don't have a ideo how to create the "pulling down and shrinking the whole video" effect.
Like this
How can i implement this?
To implement this I think you can use MotionLayout. You can take a look to the documentation here: https://developer.android.com/training/constraint-layout/motionlayout/examples
With MotionLayout you can have a view that can be your fullscreen video or whatever and you can animate it based on an action like the user draggin. It defines the animation in a MotionScene like this:
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:motion="http://schemas.android.com/apk/res-auto">
<Transition
motion:constraintSetEnd="#+id/end"
motion:constraintSetStart="#+id/start"
motion:duration="1000"
motion:motionInterpolator="linear">
<OnSwipe
motion:dragDirection="dragRight"
motion:touchAnchorId="#id/button"
motion:touchAnchorSide="right" />
</Transition>
<ConstraintSet android:id="#+id/start">
<Constraint
android:id="#id/button"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_marginStart="8dp"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent">
<CustomAttribute
motion:attributeName="BackgroundColor"
motion:customColorValue="#D81B60" />
</Constraint>
</ConstraintSet>
<ConstraintSet android:id="#+id/end">
<Constraint
android:id="#id/button"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_marginEnd="8dp"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintTop_toTopOf="parent">
<CustomAttribute
motion:attributeName="BackgroundColor"
motion:customColorValue="#9999FF" />
</Constraint>
</ConstraintSet>
</MotionScene>
You can see that you can define the action as a new node like the OnSwipe, there you specify the direction and the touch properties. I think the documentation can help expand on all the posibilities, please take a look.
Related
In my animation one of the views must grow from fixed width to app:layout_constraintEnd_toEndOf="parent" (which is the value from the destination ConstraintSet) by 70% of animation time.
I tried to achive it with the following KeyAttribute:
<KeyAttribute
motion:motionTarget="#id/my_view"
motion:framePosition="70"
>
<CustomAttribute
motion:attributeName="layout_constraintEnd_toEndOf"
motion:customReference="#id/root"/>
</KeyAttribute>
But it has no effect
I would be grateful for working solution of this problem.
If in any case you are interested in Motion Layout for Constraint layout, then you can refer to this provided link for your animation Motion Layout with Stevdza.
MotionLayout animates Views between two ConstraintSets.
It cannot animate Constraints.
You define KeyPosition
With its Size reaching 100% of the size by frame 70.
Constraints control the start and end.
KeyPosition controls the evolution position & size from "start" to "end"
Attributes typically control the viewTransform
For a brief introduction see the KeyPosition video in the MotionTags Series
This is roughly what it should look like:
<Transition
motion:constraintSetEnd="#+id/end"
motion:constraintSetStart="#id/start"
motion:duration="1000">
<KeyFrameSet>
<KeyPosition
motion:framePosition="70"
motion:motionTarget="#+id/view"
motion:sizePercent="1"/>
</KeyFrameSet>
</Transition>
<ConstraintSet android:id="#+id/end"
motion:deriveConstraintsFrom="#id/start" >
<Constraint
android:id="#+id/view"
android:layout_width="40dp"
android:layout_height="wrap_content"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintTop_toTopOf="parent"
motion:layout_constraintStart_toStartOf="parent"
/>
</ConstraintSet>
<ConstraintSet android:id="#+id/start">
<Constraint
android:id="#+id/view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintTop_toTopOf="parent"
motion:layout_constraintStart_toStartOf="parent"
/>
</ConstraintSet>
I'm rotating an imageview using MotionLayout.
First click, image rotate clockwise, that's what i want.
But second click, image rotate counterclockwise. I tried some way to reset state of image but it doesn't work.
Can i have a advise???
<MotionScene
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:motion="http://schemas.android.com/apk/res-auto">
<Transition
motion:constraintSetEnd="#+id/end"
motion:constraintSetStart="#id/start"
motion:duration="1500">
<OnClick motion:clickAction="toggle"
motion:targetId="#id/img_reload_cast_dialog"/>
</Transition>
<ConstraintSet android:id="#+id/start">
<Constraint
android:id="#+id/img_reload_cast_dialog"
motion:layout_constraintEnd_toStartOf="#id/img_help_cast_dialog"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="#dimen/_20sdp"
motion:layout_constraintTop_toTopOf="parent" >
<Transform android:rotation="0" />
</Constraint>
</ConstraintSet>
<ConstraintSet android:id="#+id/end">
<Constraint
android:id="#+id/img_reload_cast_dialog"
motion:layout_constraintEnd_toStartOf="#id/img_help_cast_dialog"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="#dimen/_20sdp"
motion:layout_constraintTop_toTopOf="parent" >
<Transform android:rotation="720" />
</Constraint>
</ConstraintSet>
</MotionScene>
I think I figured out what you wanted.
You want a button that goes from rotate the view and essentially stays in start state
There are several ways to do this.
Probably the simplest from your your current XML is to add
motion:autoTransition="jumpToStart"
to you transition.
Alternative is to add another transition from end to start that is auto transition and duration 0.
<Transition
motion:constraintSetEnd="#+id/start"
motion:constraintSetStart="#id/end"
motion:autoTransition="jumpToStart"
//>
see MotionTags video on Transition for an overview
Other approaches are
ViewTransitions
Adding a KeyCycle of rotation with a wave shape sawtooth
This is my first question on this platform, I am making a part of an app where I need to dynamically move text views with motion layout, but when I add my showBubble () method this when executing the app does not show the text view, there is something I miss?
I think there is some error in the XML when detecting the id of the BubbleUi, but at the end of the day, it may be easier than it seems, you know :(
note: I am translating this text, sorry if there is any mistake in the writing
XML:
<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:motion="http://schemas.android.com/apk/res-auto">
<Transition
motion:constraintSetEnd="#id/end"
motion:constraintSetStart="#+id/start"
motion:duration="3500"
>
<OnClick
motion:targetId="#+id/Bubble"
motion:clickAction="toggle"
/>
</Transition>
<ConstraintSet android:id="#+id/start">
<Constraint
android:id="#id/Bubble"
android:layout_width="70dp"
android:layout_height="70dp"
motion:layout_constraintTop_toTopOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
>
<CustomAttribute
motion:attributeName="backgroundColor"
motion:customColorValue="#color/colorGreenLight"
/>
</Constraint>
</ConstraintSet>
<ConstraintSet android:id="#+id/end">
<Constraint
android:id="#+id/Bubble"
android:layout_width="100dp"
android:layout_height="100dp"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
>
<CustomAttribute
motion:attributeName="backgroundColor"
motion:customColorValue="#color/colorGreenLight"
/>
</Constraint>
</ConstraintSet>
</MotionScene>
java:
private void ShowBubble(String tempWord) {
//Create Motion layout.
MotionLayout motionBubble = new MotionLayout(ActivityGame.this);
motionBubble.setId(View.generateViewId());
motionBubble.setBackgroundColor(getResources().getColor(R.color.colorPrimary));
LinearLayout.LayoutParams linearParams= new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.MATCH_PARENT);
linearParams.setMargins(5,0,5,0);
motionBubble.setLayoutParams(linearParams);
//Create the Bubble.
TextView BubbleUi = new TextView(ActivityGame.this);
BubbleUi.setId(R.id.Bubble);
BubbleUi.setText(tempWord);
BubbleUi.setTextSize(24);
BubbleUi.setTextColor(getResources().getColor(R.color.colorDefaultWhite));
BubbleUi.setBackgroundColor(getResources().getColor(R.color.colorGreenLight));
BubbleUi.setLayoutParams(new ConstraintLayout.LayoutParams(ConstraintLayout.LayoutParams.WRAP_CONTENT, ConstraintLayout.LayoutParams.WRAP_CONTENT));
BubbleUi.setGravity(Gravity.CENTER);
motionBubble.addView(BubbleUi,0);
ConstraintSet constraintSetBubble = new ConstraintSet();
constraintSetBubble.clone(motionBubble);
constraintSetBubble.connect(BubbleUi.getId(),ConstraintSet.TOP,ConstraintSet.PARENT_ID,ConstraintSet.TOP);
constraintSetBubble.connect(BubbleUi.getId(),ConstraintSet.START,ConstraintSet.PARENT_ID,ConstraintSet.START);
constraintSetBubble.connect(BubbleUi.getId(),ConstraintSet.END,ConstraintSet.PARENT_ID,ConstraintSet.END);
constraintSetBubble.applyTo(motionBubble);
//set transition.
motionBubble.loadLayoutDescription(R.xml.scene_bubbles);
linearLayoutBubbles.addView(motionBubble,indiceBubble);
CurrentMotionBubbleCycle [indiceBubble] = motionBubble;
motionBubble.transitionToStart();
motionBubble.transitionToEnd();
}
I've just started working on MotionLayout and it's really easy so far and I'm getting the required output too. But log is filled with errors E/MotionPaths: UNKNOWN customName ImageAlpha
Official documentation also writes
motion:attributeName is required and must match an object with getter and setter methods. The getter and setter much match a specific pattern.
So, what am I doing wrong here?
motion_layout.xml
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:motion="http://schemas.android.com/apk/res-auto">
<Transition
motion:constraintSetEnd="#id/end"
motion:constraintSetStart="#id/start">
<OnSwipe
motion:dragDirection="dragUp"
motion:touchAnchorId="#id/store_viewpager"
motion:touchAnchorSide="top" />
<KeyFrameSet>
<KeyAttribute
motion:framePosition="60"
motion:motionTarget="#id/tab_image_view">
<CustomAttribute
motion:attributeName="imageAlpha"
motion:customIntegerValue="255" />
</KeyAttribute>
<KeyAttribute
motion:framePosition="90"
motion:motionTarget="#id/tab_image_view">
<CustomAttribute
motion:attributeName="imageAlpha"
motion:customIntegerValue="0" />
</KeyAttribute>
</KeyFrameSet>
</Transition>
<ConstraintSet android:id="#+id/start">
<Constraint
android:id="#+id/tab_image_view"
android:layout_height="256dp"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent">
</Constraint>
</ConstraintSet>
<ConstraintSet android:id="#+id/end">
<Constraint
android:id="#+id/tab_image_view"
android:layout_height="96dp"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent">
</Constraint>
</ConstraintSet>
</MotionScene>
It is saying it cant find "imageAlpha". Your customAttributes
implies you have a method setImageAlpha(int) on "#+id/tab_image_view".
Assuming it is an ImageView that it would work but only back to api 16.
Alpha is a little more generic operating from 0.0 to 1.0 and is on View.
You do not need a custom attribute for it. android:alpha="0"
To help further what is the View? (ImageView?)
What device level?
I'm playing around with the MotionLayout in Android. I'm using the alpha 2 version.
'com.android.support.constraint:constraint-layout:2.0.0-alpha2'
I want to react to two different button clicks and trigger an animation for each of them. My current approach is to set two Transitions in the MotionScene with an OnClick trigger in each one.
The problem is that only the first transition seems to be found. For the second one just nothing happens. Am I doing something wrong or can you just set one transition per MotionScene? If that's the case ist there a different solution to the problem?
Here are the important parts of my Motion Scene
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:motion="http://schemas.android.com/apk/res-auto">
<Transition
motion:constraintSetStart="#id/startHome"
motion:constraintSetEnd="#id/endHome"
motion:duration="300">
<OnClick
motion:mode="toggle"
motion:target="#+id/imageView_bottom_home" />
</Transition>
<Transition
motion:constraintSetStart="#id/startSearch"
motion:constraintSetEnd="#id/endSearch"
motion:duration="300">
<OnClick
motion:mode="toggle"
motion:target="#+id/imageView_bottom_search" />
</Transition>
<ConstraintSet android:id="#+id/startSearch">
<Constraint
android:id="#id/imageView_bottom_search"
...startConstraints... />
</ConstraintSet>
<ConstraintSet android:id="#+id/endSearch">
<Constraint
android:id="#id/imageView_bottom_search"
...endConstraints... />
</ConstraintSet>
<ConstraintSet android:id="#+id/startHome">
<Constraint
android:id="#id/imageView_bottom_home"
...startConstraints... />
</ConstraintSet>
<ConstraintSet android:id="#+id/endHome">
<Constraint
android:id="#id/imageView_bottom_home"
...endConstraints... />
</ConstraintSet>
Any help appreciated.
Best regards
I had the same problem. The solution I found was to select which one transitions:
(in java code)...
MotionLayout motionConteiner = findViewById(R.id.motion_container);
button1.setOnClickListener((v) -> {
motionConteiner.setTransition(R.id.start1, R.id.end1);
motionConteiner.transitionToEnd();//
});
button2.setOnClickListener((v) -> {
motionConteiner.setTransition(R.id.start2, R.id.end2);
motionConteiner.transitionToEnd();//
});
A more kotlin'y answer:
with(view as MotionLayout) {
setTransition(R.id.startState, R.id.endState)
transitionToEnd()
}
Multiple transitions are supported.
In the code you shared, you have 4 constraint sets, start_home -> end_home, start_search -> end_search. Instead, have only 3 sets, with one being the base state like, start -> end_home and start -> end_search. The 'start' here represents the base state of the screen
This happens because, say you did the home action first and then you did the search action, then the search is not going to work because the starting criteria (start_search) is not going to match the start_home or end_home (which got applied last)
I think aba is right. I am also having problem adding multiple transitions to a single scene file. Theoretically, MotionLayout should support this because every transition will have a separate trigger (often as click or swipe). Maybe this is a bug with MotionLayout that needs to be fixed.
Out of my experience, only the first transition that is encountered in the scene file is cared for.
So, currently, I don't think there is a way to support more than one transition in a layout description (scene). To put it more specifically, all motion needs to be started once with the same trigger.
Seems to me that MotionLayout only supports one Transition, when you add a second Transition to the MotionScene file the second Transition appears to be ignored. You can however have multiple MotionLayouts in your layout and create a MotionScene for each MotionLayout. This will also keep the MotionScene file cleaner and allow for easier maintenance.
In your layout file, you'll need a Parent layout that can contain multiple MotionLayout files.
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
...
</data>
<!-- [databinding] {"msg":"Only one layout element with 1 view child is allowed. So a Parent Layout is required for Multiple motion layouts. -->
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.motion.widget.MotionLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutDescription="#xml/motion_scene_01"
tools:context=".menu.contextual.FragmentContextualOne"
tools:showPath="true">
<Button
android:id="#+id/btn_one"
android:layout_width="64dp"
android:layout_height="64dp"
tools:layout_editor_absoluteX="8dp"
tools:layout_editor_absoluteY="310dp" />
</androidx.constraintlayout.motion.widget.MotionLayout>
<androidx.constraintlayout.motion.widget.MotionLayout
android:id="#+id/m2"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutDescription="#xml/motion_scene_02">
<Button
android:id="#+id/btn_two"
android:layout_width="64dp"
android:layout_height="64dp"
tools:layout_editor_absoluteX="8dp"
tools:layout_editor_absoluteY="500dp" />
</androidx.constraintlayout.motion.widget.MotionLayout>
</FrameLayout>
</layout>
Motion Scene One.
<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:motion="http://schemas.android.com/apk/res-auto">
<Transition
android:id="#+id/transition_sine_wave"
motion:constraintSetStart="#+id/wave_start"
motion:constraintSetEnd="#+id/wave_end"
motion:duration="2000"
motion:motionInterpolator="linear">
<OnClick
motion:touchAnchorId="#+id/btn_one"
motion:touchAnchorSide="right"
motion:targetId="#+id/btn_one"/>
</Transition>
<ConstraintSet android:id="#+id/wave_start">
<Constraint
android:id="#+id/btn_one"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_marginStart="8dp"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintTop_toTopOf="parent"
motion:layout_constraintStart_toStartOf="parent"/>
</ConstraintSet>
<ConstraintSet android:id="#+id/wave_end">
<Constraint
android:id="#+id/btn_one"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_marginEnd="8dp"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintTop_toTopOf="parent" />
</ConstraintSet>
</MotionScene>
Motion Scene Two
<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:motion="http://schemas.android.com/apk/res-auto">
<Transition
android:id="#+id/transition_straight"
motion:constraintSetEnd="#+id/right_end"
motion:constraintSetStart="#+id/left_start"
motion:duration="2000"
motion:motionInterpolator="linear" >
<OnClick
motion:targetId="#+id/btn_two"
motion:clickAction="toggle"/>
</Transition>
<ConstraintSet android:id="#+id/left_start">
<Constraint
android:id="#+id/btn_two"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_marginStart="8dp"
android:layout_marginBottom="100dp"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintStart_toStartOf="parent" />
</ConstraintSet>
<ConstraintSet android:id="#+id/right_end">
<Constraint
android:id="#+id/btn_two"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_marginEnd="8dp"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintEnd_toEndOf="parent" />
</ConstraintSet>
</MotionScene>
This is the only XML solution I could come up with.