A think a do not understand enough matrices theory to build animation for matrix inside image view.
For example i have some value that i want to set in postScale method to my matrix.
I use this code
fun animateScale(scale_factor:Float,matrix: Matrix)
{
matrix.postScale(scale_factor,scale_factor)
image_view.imageMatrix = matrix
}
This code makes scale to image view as it is expected. But i cant calculate postScale with animation. I tried different approaches using ValueAnimator.ofFloat(0f, 1f) or ValueAnimator.ifInt(1, 100) but result is weird.
Updated
I added my tries of animating as it asked in comments.
val animator = ValueAnimator.ofFloat(0f, 1f)
animator.addUpdateListener(
{ animation ->
val current_anim_value = animation.animatedValue as Float
val factor_to_anim = scale_factor - ( scale_factor * current_anim_value)
matrix.postScale(factor_to_anim, factor_to_anim)
image_view.imageMatrix = matrix
})
animator.duration = 3000
animator.start()
Related
I am trying to implement similar animation like this, with Jetpack Compose
figure: https://dribbble.com/shots/4762799-Microinteraction-Exploration-002
For the play icon’s transformation (from a triangle to a rectangle) , it not difficult to get it done by using path morphing animation.After reading some gist, I found that I can build an ImageVector by supplying the pathData , that's new to me~
While for ****the part on the right, the rotation of the cube object. Well, maybe I should call that a rolling-over or whatever, because the cube changed its pivot after -90 degrees.
I'm wondering that wether I can create a VectorGroup for the cube’s pathData and animate it by updating its group parameters.
re: androidx.compose.ui.graphics.vector.ImageVector.Builder#addGroup
ImageVector.Builder(defaultWidth = 100.dp, defaultHeight = 100.dp, viewportWidth = 100, viewportHeight = 100)
.addGroup(name = "CubeRotation", rotate = params.rotate, pivotX = params.pivotX, pivotY = params.pivotY,)
.addPath(pathData = pathData, fill = SolidColor(Color.LightGray))
.clearGroup()
.build()
Here I trying to update the pivotX halfway through the animation, so I divide it into two section:
// rotate -90 degrees twice with different pivot
val rotate = if (fraction <= 0.5f) {
lerp(0f, -180f, fraction)
} else {
lerp(0f, -180f, fraction - 0.5f)
}
// change the pivotX
val pivotX = if (fraction <= 0.5f) 52f else 30f
GroupParams(
pivotX = pivotX,
pivotY = 100f,
rotate = rotate,
)
Frustratedly, after rotating by the first -90 degrees, the transformation that this rotation performed will NOT persist, -or- its transformation NOT being applied after the half time of the transition.
fraction: 0~0.5
fraction: 0.5~1
The code sample I've uploaded: IndicatorDrawable.kt
Can I implement the rotate transformation by just updating the pathData ?
For me, the VectorGroup in ImageVector looks like creating AnimatedVectorDrawable in xml, or maybe I should try some traditional way like ObjectAnimationSet in View system ?
Sceneform 1.15 on Android
I want to make that the cube renderable is rotating around the own centar.
val anchorNode = AnchorNode().apply {
setParent(scene)
worldPosition = Vector3(2f, 3f, 0f)
}
scene.addChild(anchorNode)
dieNode = Node().apply {
setParent(anchorNode)
localRotation = Quaternion.eulerAngles(Vector3(10f,20f,60f))
name = "die"
renderable = it
}
I made an animator that is supposed to only rotate the cube around its own center.
private fun roll() {
val anim = createAnimator()
val node = scene.findByName("die")!!
anim.target = node
anim.setDuration(9000)
anim.start()
}
private fun createAnimator() : ObjectAnimator {
val o1 = Quaternion.eulerAngles(Vector3(-90f,180f,90f))
val animator = ObjectAnimator()
animator.setObjectValues(o1)
animator.setPropertyName("localRotation")
animator.setEvaluator(QuaternionEvaluator())
animator.setInterpolator(LinearInterpolator())
animator.setAutoCancel(true)
return animator
}
But, it happens that while cube is rotating, it is also moved which is not desired behavior.
Screenshots where one of the symetrically placed die in world should be only rotated:
The position is not centred for the Cube object. If it is off the centre with respect to the parent object, it will rotate around (0,0,0), if it lies off this axis - the object will move in a circle, not rotate.
I am wanting to hide an extended fab when it is clicked using an Animation. I want to scale the button down from original height and width to 0/gone. It disappears in the corner but the animation is laggy in the middle.
private fun animateHideScoreFab(){
val animX = ValueAnimator.ofInt(editScoreFab.measuredWidth, 0).apply {
duration = 1000
}
val animY = ValueAnimator.ofInt(editScoreFab.measuredHeight, 0).apply {
duration = 1000
}
animX.addUpdateListener {
val value = it.animatedValue as Int
editScoreFab.layoutParams.width = value
editScoreFab.requestLayout()
}
animY.addUpdateListener {
val value = it.animatedValue as Int
editScoreFab.layoutParams.height = value
}
AnimatorSet().apply {
this.interpolator = AccelerateDecelerateInterpolator()
play(animX).with(animY)
start()
}
}
Result:
Using AccelerateDecelerateInterpolator https://developer.android.com/reference/android/view/animation/AccelerateDecelerateInterpolator says
An interpolator where the rate of change starts and ends slowly but accelerates through the middle.
So in the middle the rate of change is faster than the start which could make it look laggy
Try another Interpolator like LinearInterpolator https://developer.android.com/reference/android/view/animation/LinearInterpolator.html which has a constant rate of change.
Update
For AccelerateDecelerateInterpolator if you look at the table in https://developer.android.com/guide/topics/graphics/prop-animation.html#interpolators between 400ms and 600ms the the value jumps 45.5% of the distance you and animating
The other factor of smoothness is not to use an Int but use a Float e.g. ValueAnimator.ofFloat so it has intermediate steps,
Update2
Re-laying out an item is expensive as it has to be measured and redrawn.
It should be faster and smoother just to scale the already drawn image as this is usually done by the GPU and thus faster and smoother. Also scaling a view takes a Float
example of scaling a Fab to top right onClick (Note using ObjectAnimator as it is simpler to implement)
Sorry in Java not Kotlin
FloatingActionButton fab = findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
AnimatorSet animationSet = new AnimatorSet();
// Set point to scale around to top right
view.setPivotY(0);
view.setPivotX(view.getMeasuredWidth());
ObjectAnimator scaleY = ObjectAnimator.ofFloat(view,"scaleY", 1f, 0f);
scaleY.setDuration(1000);
// Optional as AccelerateDecelerateInterpolator is the default
scaleY.setInterpolator(new AccelerateDecelerateInterpolator());
ObjectAnimator scaleX = ObjectAnimator.ofFloat(view,"scaleX", 1f, 0f);
scaleX.setDuration(1000);
// Optional as AccelerateDecelerateInterpolator is the default
scaleX.setInterpolator(new AccelerateDecelerateInterpolator());
animationSet.playTogether(scaleX, scaleY);
animationSet.start();
}
});
There's a scaleX and scaleY property in Views that you can interpolate from 1 to 0, this will give the effect of the View shrinking and not the container.
Second, for a scale animation work to the top if your parent layout params doesn't do for you, you have to set the pivot to the rightXtop corner with: view.pivotX = view.width; view.pivotY = 0
Also, if you using propertyListener and updating it yourself you can use only one ValueAnimator and do the calc yourself plus consider replacing editScoreFab.requestLayout() with editScoreFab.invalidate()
I am trying to play animation (like drop or bounce) on placing of an 3D object (.sfb in my case), but I don't have any idea how can I do that.
I have tried to use ValueAnimator that is working fine for changing its color value, but that's not I wanted.
val alphaAnimator = ValueAnimator.ofFloat(0.0f, 1.0f, 0.0f)
alphaAnimator.addUpdateListener { animation ->
val animatedAlpha = animation.animatedValue as Float
modelRenderable.material.setFloat4(
MaterialFactory.MATERIAL_COLOR,
Color(0.0f, 0.0f, 1.0f * animatedAlpha, animatedAlpha)
)
}
alphaAnimator.repeatCount = ValueAnimator.INFINITE
alphaAnimator.duration = 1000
alphaAnimator.start()
val animatorSet = AnimatorSet()
animatorSet.playSequentially(
ObjectAnimator.ofFloat(modelRenderable, "translationY", 0.0f)
ObjectAnimator.ofFloat(modelRenderable, "translationY", 1.5f)
ObjectAnimator.ofFloat(modelRenderable, "translationY", 0.0f)
)
animatorSet.duration = 600
animatorSet.start()
But this is giving me an error "Could not find property setter method setTranslationY on com.google.ar.sceneform.rendering.ModelRenderable".
You should animate the node where the renderable is attached to and not the model itself. The node has a setLocalPosition(Vector3) method which you can use for the ObjectAnimator. So to animate for example the position of your model you should do something like this:
ObjectAnimator nodeAnimator = ObjectAnimator.ofObject(
yourNode,
"localPosition",
new Vector3Evaluator(),
Vector3.zero(), new Vector3(0f, 1f, 0f));
Then you can set the duration, repeat count, mode etc. You can also scale and rotate the model over a animation.
today I set up the new Android JB 4.3 on my Nexus 7 and i tried to run my application.
Everythings works like it should except one little thing about ImageViews with ScaleType.MATRIX.
Basically what i have in my application is a ImageView as background and accordingly to a ViewPager callbacks i move the focused part of the image updating the Matrix i gave to the imageView using setImageMatix( Matrix matrix ).
the problem seems to be that i can't update the matrix anymore, i just have to instantiate a new one a pass it to the ImageView.
i managed to work around it instantiating everytime a new Matrix but it seems awfully memory expensive compared to the old version.
is this a BUG?
is there a way to udpate the Matrix? ( i by the way already tried to invalidate() the ImageView ecc. )
NOT WORKING
private void updateMatrix( final int page, final double offset ) {
double pagePosition = page + offset;
Matrix matrix = imageView.getImageMatrix();
matrix.setScale( scale, scale );
matrix.postTranslate( - (float) ( pagePosition * pageWidth ) , 0 );
imageView.setImageMatrix( matrix );
imageView.invalidate();
}
WORKING
private void updateMatrix( final int page, final double offset ) {
double pagePosition = page + offset;
Matrix matrix = new Matrix();
matrix.setScale( scale, scale );
matrix.postTranslate( - (float) ( pagePosition * pageWidth ) , 0 );
imageView.setImageMatrix( matrix );
imageView.invalidate();
}
EDIT:
in the first case the image is shown at the top left corner of the ImageView without any scale or translate applied to it, like if the matrix is back to identity.
Just preserve your Matrix as field instead of retrieving it from ImageView and you'll be happy :)
There may be a bug with ImageView scaling starting with 4.3. See my question and answer about this bug.