Before you start:
I'm using Kotlin
I'm using ConstraintLayout (switching to LinearLayout or RelativeLayout is not an option)
I have my layout as follows:
<TextView android:id="#+id/myRefer" .../>
<ScrollView
...
app:layout_constraintTop_toBottomOf="#id/myRefer">
...
</ScrollView>
And my animation is developed as follows:
myRefer.animate()
.translationY(-myRefer.height.toFloat())
.alpha(0.0f)
So far so good, no problem with the animation, everything goes as expected.
The problem is, I thought that from the moment I'm using TranslateY, the ScrollView would follow the new position reference (topToBottom). But it keeps a white hole (as if my TextView is still using the reference height)
Did I misunderstand the use of TranslateY, or am I using animate() incorrectly? How would I solve this problem for my ScrollView to follow the reference.
Note: Don't suggest using onAnimatonEnd and setting View.GONE, it just makes things worse.
I would just use android:animateLayoutChanges="true" on the layout. And then instead of animate... just call myRefer.visibility = View.VISIBLE or View.GONE. It will have the same effect and the Scrollview will adjust to the hidden element.
Related
I have a RecyclervView with a rounded Drawable background and .clipToOutline = true in order to keep the overscroll animation inside the background. When I set requiresFadingEdge="vertical", there's a glitch where the fading edge is; example below. How can I fix this? The issue doesn't appear when I set .clipToOutline = false or when I don't have a fading edge, but I would like both of these effects. Thanks for the help.
You can see the issue in the bottom corners of the blue RecyclerView.
This can be fixed by setting a different layer type either in xml, or programatically when initialising your recyclerview:
XML
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerView"
android:layerType="hardware"
...
Programatically
recyclerView.setLayerType(VIEW.LAYER_TYPE_HARDWARE, null)
You can also use LAYER_TYPE_SOFTWARE, but it's better to use LAYER_TYPE_HARDWARE for performance reasons.
Find out more about this 2 options in these docs:
https://developer.android.com/reference/android/view/View#LAYER_TYPE_HARDWARE
https://developer.android.com/reference/android/view/View#LAYER_TYPE_SOFTWARE
I am working on an android app and I have a scrollview, and in that, I have a linear layout in the main activity. I want to have the top and bottom borders of the linear layout to be "faded
" so as the user scrolls down the child views in the layout will "fade out" as the go down.
Here is an example of what I am trying to achieve in my linearlayout or scrollview (the "fading bottom border".
Thanks for you help!
Subby
You can do that by using the following attributes in the ScrollView.
android:requiresFadingEdge="vertical"
android:fadingEdgeLength="20dp"
If you want it on devices before API14, you need to use the following:
android:requiresFadingEdge="vertical"
android:fadingEdgeLength="20dp"
NOTE: This is actually discouraged as it is seen to have a negative performance impact on devices.
At the bottom of your layout, you can have a view above the listView, and set Gradient Color for the view, and also make it semitransparent, then you can have the effect you want.
Gridlayout (it is centered inside a relative layout)
<GridLayout
android:id="#+id/ticketLayout"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#drawable/pile"
android:visibility="gone"
android:animateLayoutChanges="true" >
<!-- some content -->
Now when I make it visible
ticketLayout.setVisibility(View.VISIBLE);
it just appears, there is no animation at all. Am I missing something?
You need to animate your View.
You can do it, for example, like this:
mticketLayout.setAlpha(0f);
mticketLayout.setVisibility(View.VISIBLE);
// Animate the content view to 100% opacity, and clear any animation
// listener set on the view.
mticketLayout.animate()
.alpha(1f)
.setDuration(mShortAnimationDuration)
.setListener(null);
Take a look at the Android Training: http://developer.android.com/training/animation/crossfade.html
There is no default animation for this. In order to achieve what you want I think you need to play an animation on the alpha property of your gridview.
Depending on what minimum API you want to support you can use the old animation system, or the new one, or even use NineOldAndroids.
The animateLayoutChange flag specifies that if you dynamically add a view inside this grid view, the system will have to play a default animation. (Most likely a fading effect) It doesn't help for the grid view itself.
I have a nested layout like the following:
<LinearLayout> <!----Parent layout--->
<LinearLayout> <!-----child 1--->
...
</LinearLayout> <!----child 1 ended--->
<LinearLayout> <!-----child 2--->
...
</LinearLayout> <!----child 2 ended--->
</LinearLayout> <!----Parent endded--->
The problem I am having now is that since all my data items are within child 1 or child 2 Linearlayout, if I add or delete a item the child linearlayout will animated with the effect of animateLayoutChanges but the parent layout will not do any animation. (I have android:animateLayoutChanges set to true for all linear layouts). Especially when I delete an item within child 1 the animation effect becomes weird (basically child 2 will jump up while child 1 is still doing its animation).
Does anybody have any idea how to solve this?
Thanks
UPDATE
Shortly after I posted this question, I found this on android developer's site in the LayoutTransition API.
Using LayoutTransition at multiple levels of a nested view hierarchy may not work due to the interrelationship of the various levels of layout.
So does anyone have any work around suggestions for this issue?
The animateLayoutChanges property makes use of LayoutTransitions, which animate both the layout's children and, from Android 4.0 onward, ancestors in the layout hierarchy all the way to the top of the tree. In Honeycomb, only the layout's children will be animated. See this Android Developers Blog post for details.
Unfortunately, it seems that there's currently no simple way to have the siblings of a layout react to its LayoutTransitions. You could try using a TransitionListener to get notified when the layout's bounds are being changed, and move the sibling views accordingly using Animators. See Chet Haase's second answer in this Google+ post.
EDIT - Turns out there is a way. In Android 4.1+ (API level 16+) you can use a layout transition type CHANGING, which is disabled by default. To enable it in code:
ViewGroup layout = (ViewGroup) findViewById(R.id.yourLayout);
LayoutTransition layoutTransition = layout.getLayoutTransition();
layoutTransition.enableTransitionType(LayoutTransition.CHANGING);
So, in your example, to have child 2 layout animated, you'd need to enable the CHANGING layout transformation for it. The transformation would then be applied when there is a change in the bounds of its parent.
See this DevBytes video for more details.
Ok, after digesting the first answer, I make it simple here, for those who don't get proper animation result when using android:animateLayoutChanges="true" in NESTED layout:
Make sure you add android:animateLayoutChanges="true" to the will-be-resized ViewGroup (LinearLayout/RelativeLayout/FrameLayout/CoordinatorLayout).
Use setVisibility() to control the visibility of your target View.
Listen carefully from here, add android:animateLayoutChanges="true" to the outer ViewGroup of your will-be-resized ViewGroup, this outer ViewGroup must be the one who wraps all the position-changing View affected by the animation.
Add following code in your Activity before the setVisibility(), here the rootLinearLayout is the outer ViewGroup I mentioned above:
LayoutTransition layoutTransition = rootLinearLayout.getLayoutTransition();
layoutTransition.enableTransitionType(LayoutTransition.CHANGING);
Before:
After:
Reminder: If you miss the 3rd step, you will get null pointer exception.
Good luck!
As a Kotlin Extension
fun ViewGroup.forceLayoutChanges() {
layoutTransition.enableTransitionType(LayoutTransition.CHANGING)
}
Usage
someContainer.forceLayoutChanges()
Notes:
In my experience, this happens when the container is a deep nested layout. For some reason android:animateLayoutChanges="true" just doesn't work, but using this function will force it to work.
We had added the android:animateLayoutChanges attribute to our LinearLayout but the change didn’t trigger an animation. To fix that, use this code:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
((ViewGroup) findViewById(R.id.llRoot)).getLayoutTransition()
.enableTransitionType(LayoutTransition.CHANGING);
}
More details.
It seems that a delayed transition on the parent also works for animating. At least for me the following code gives a proper expand/collapse animation.
expandTrigger.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
TransitionManager.beginDelayedTransition(parentLayout);
expanded = !expanded;
child1.setVisibility(expanded ? View.VISIBLE : View.GONE);
}
});
For deeply nested layouts you sometimes might need to use a parent higher up in the hierarchy in the call to the TransitionManager.
I had a similar issue:
I was using a animatelayoutchanges in one of my activity with a recycler view, I also added some custom layout transition because I wanted to increase speed of the animation while an item disappears in the list. It was working fine when it was not in a nested layout.
I had used the same adapter for another recyclerview which was in a nested layout. It was not working and I tried all the above solutions, None worked for me.
The real reason was, I forgot to set
mTicketsListAdapter.setHasStableIds(true);
in the nested layout activity. And after setting setHasStableIds to true, the animations was working perfectly in the nested layout.
For animation i use a ViewPropertyAnimator.
mAnimatedView.animate().translationYBy(50).start();
Before translation:
After translation:
I want buttons to stay below AnimatedView (according to the mentioned above illustrations it is not right now). There is only one idea that comes to my mind: animate buttons too, but i am sure it is not the best solution. Maybe there is a method that recalculates all layout while animation, that i have missed?
Add Buttons to xml before AnimatedView:
<Button ...>
<AnimatedView ...>