I have successfully written a new interpolator for a view animation by implementing the Interpolator interface like this.
public class MyInterpolator implements Interpolator {
public MyInterpolator() {}
public float getInterpolation(float t) {
return somefunction(t);
}
}
I know that I can use this interpolator programmatically by creating an instance and passing it to the setInterpolator method of the Animation class.
But is there a way of using MyInterpolator in the XML resources for my animations?
Searching for the same thing, I encounter that android give support to this.Android Custom Interpolators
Related
What I'm trying to do is load one animation on a view with a linear interpolator for example. Then, when a certain event happens in my application, change the interpolator to something like a deceleration interpolator. So the effect would be a constant animation until an event happened, then the animation would slow down to a stop. Is this possible to achieve? Im wondering how I would achieve this and would love some direction.
Thanks!
Yes. You would create a custom Interpolator for the animation. It contains the other interpolators that you want. When the event happens, just trigger it in the interpolator and have the interpolator swap one interpolator for the other.
public class CompositeInterpolator implements TimeInterpolator {
LinearInterpolator mLinear;
DecelerateInterpolator mDecelerate;
boolean mUseLinear = false;
public CompositeInterpolator() {
mLinear = new LinearInterpolator();
mDecelerate = new DecelerateInterpolator();
}
public void useLinear(boolean use) {
mUseLinear = use;
}
#Override
public float getInterpolation(float input) {
if (mUseLinear) {
return mLinear.getInterpolation(input);
} else {
return mDecelerate.getInterpolation(input);
}
}
}
Then just call useLinear(false) when you want to swap.
I want to create skew animation for a View in android.
So, I have rectangular view (this is normal/start state), at the end it should looks like this:
I can do such a thing with android.view.animation package using Transformation of TYPE_MATRIX. So I can create Matrix and use preSkew method, apply this Matrix to my custom animation and then start this animation on a view. So this is OK.
BUT
The problem is I want to do this with ObjectAnimator.
Because using android.view.animation package is not recommended to use.
But I can't get the solution for this problem with ObjectAnimator class.
If I have ImageView, I can use method setImageMatrix for ObjectAnimator (and also create custom MatrixEvaluator to evaluate corresponding matrices for each factor),
but I want to get solution for this problem with a View class, not for some subclass of it.
And the main reason is, that TextView, for example, doesn't have public method like setMatrix, and I want to get the solution for TextView too. So get the solution for base View class is the main desire.
There is another solution: create custom, for example, SkewTextView, in which onDraw method we use canvas.skew method.
But this is worse solution even than using android.view.animation package, because you need to create wrappers for any View subclass you want to skew.
So, I don't know, how I can skew View with a ObjectAnimator (as View class doesn't have public methods like setSkew or setMatrix).
How would you solve this problem?
Have you any idea of how to solve this problem?
Is there a solution for this problem with ObjectAnimator?
Any help (or even thoughts) is greatly appreciated
Thanks
Well without subclassing this might be a bit tricky. My main idea is to use TimeAnimator, which will provide you time callbacks in conjunction with Camera (which can use Matrix transformations). Or you can use TimeAnimator and make a Bitmap from the View you want to skew, make the original View invisible, and draw the Bitmap on each TimeAnimator step applying a Matrix to it. But I'm not sure if this is the optimal way to do that, since you will have to create a new Bitmap on each frame
EDIT: No, Camera approach is not the way to do that as it is stated in comments below
I created a skew animation using Android Property Animation APIs in my project (GitHub Link).
What I did:
Created a custom view (SkewView) and added a SKEW_X property to it.
public class SkewView extends ImageView {
private static final String TAG = "SkewView";
public static final Property SKEW_X
= new FloatProperty("skewX") {
#Override
public void setValue(SkewView object, float value) {
object.setSkewX(value);
}
#Override
public Float get(SkewView object) {
return object.getSkewX();
}
};
private float mSkewX;
// ...
public float getSkewX() {
return mSkewX;
}
public void setSkewX(float skewX) {
mSkewX = skewX;
invalidate();
}
#Override
protected void onDraw(Canvas canvas) {
if (mSkewX != 0) {
canvas.skew((float) (mSkewX * Math.PI / 180.0f), 0);
}
super.onDraw(canvas);
}
}
Used ObjectAnimator to animate this property.
ObjectAnimator skewAnimator = ObjectAnimator.ofFloat(mTarget, SkewView.SKEW_X, 30);
I'm trying to create a custom surfaceview where every time the view is on the screen the view will start playing a video on its own. I was wondering what method within View is notified when a view is displayed on the UI and seen by the user. I'm using a viewpager so the SurfaceCreated doesn't work because views are created before they are displayed on the screen.
How to start a video automatically in a view pager when it comes on the screen
This was the underlying problem. The OP, wisely, wanted to try and isolate the point where it, in a sense "comes on to the screen". Problem is that this can mean many things:
When I first heard the question, I thought a good case would be onAttachedToWindow - see the docs. For people reading this question based on its original title, this is what you want.
The view is inflated and created in the Activity's onCreate in most cases (e.g. if you've used setContentView).
The OP had had no luck with surfaceCreated callbacks either. So we considered in the comments above whether the OP would be interested in the three draw stages layout, measure and draw. There are two stages to actually "putting a view on the screen" in android - the measuring, and the layout pass- see here.
Problem would be that it turned out that the OP was animating his view onto the screen, so the question became how do you tell when a view "arrives" on the screen after animation.
The important point is: you actually wanted to detect a stage much much later in the drawing process, which is understandable! Animation works by many calls to invalidate which in turn require many draws for that view's Canvas - so the stage at which you want to play the video is by no means when the view is first displayed in the UI.
Solution for this particular scenario.
Use animation listeners on your ViewAnimator instances (e.g. ViewPager). To not have to bother with them in teh activity, I would roll your own view, and then use the Adapter type patterns Android is so fond of to manage constantly changing data:
a very hastily written implementation would be:
public class VideoStartingViewFliper extends ViewFlipper {
private final Animation fromRight;
private final Animation toLeft;
private final Animation fromLeft;
private final Animation toRight;
private VideoViewAdapter mAdapter;
public VideoStartingViewFliper(final Context context, final AttributeSet attrs) {
super(context, attrs);
fromRight = new YourChoiceOfAnimation();
fromRight.setAnimationListener(videoStartingAnimationListener);
toLeft = new YourChoiceOfAnimation();
toLeft.setAnimationListener(videoStartingAnimationListener);
fromLeft = new YourChoiceOfAnimation();
fromLeft.setAnimationListener(videoStartingAnimationListener);
toRight = new YourChoiceOfAnimation();
toRight.setAnimationListener(videoStartingAnimationListener);
}
static interface VideoViewAdapter {
public String getVideoPath(int childId);
}
public void setVideoViewAdapter(final VideoViewAdapter adapter) {
mAdapter = adapter;
}
// or even call this showNextVideo and don't override!
#Override
public void showNext() {
setInAnimation(fromRight);
setOutAnimation(toLeft);
super.showNext();
}
#Override
public void showPrevious() {
setInAnimation(fromLeft);
setOutAnimation(toRight);
super.showPrevious();
}
private final AnimationListener videoStartingAnimationListener = new AnimationListener() {
#Override
public void onAnimationStart(final Animation animation) {
final VideoView video = ((VideoView) getCurrentView());
video.stopPlayback();
}
#Override
public void onAnimationRepeat(final Animation animation) {
}
#Override
public void onAnimationEnd(final Animation animation) {
final VideoView video = ((VideoView) getCurrentView());
// check null here!
video.setVideoPath(mAdapter.getVideoPath(getCurrentView().getId()));
video.start();
}
};
}
Hope this helps.
I've come from an iOS background where there was a property called transform which was essentially just a 4x4 matrix for a 3D transformation that is applied to a CALayer (Also UIView).
I have come across the Transformation class, which seems to be a bit different, but I'm hoping that I can use it for some transformations on a View subclass.
I have seen the constructor new Transformation() and the different set methods, but I can't see anything that will allow me to actually set the 3x3 matrix for the Transformation or how it is used on a View.
I would guess that this isn't a very important class, either, as there seem to be errors in the document itself.
I was hoping that someone on SO might be able to help me figure out how to utilize this class to get transformations working on my View subclasses (How to construct and apply a Transformation) or point me towards a better tool/class for my needs.
You'd typically apply a transformation within an Animation object in Android. i.e. Create a new Animation class that sets a transform for your view:
public class myAnimation extends Animation {
public myAnimation() { }
#Override
boolean willChangeTransformationMatrix() { return true; }
#Override
void applyTransformation(float interpolatedTime, Transformation t) {
Matrix m = t.getMatrix();
// do whatever you want to the matrix here, using the interpolatedTime
}
}
Then set the animation on your view:
Animation anim = new myAnimation();
anim.setDuration(100);
view.startAnimation(anim);
On post Honeycomb Android, you should be able to do similar things just by manipulating the matrix on a view though:
Matrix m = view.getMatrix();
// do whatever you want here
I'm not sure if this is possible, and I couldn't find a topic based on it, but if it's been answered before drop me a link and that will be that.
What I'm looking to do right now is resize some of the default Android widgets, specifically DatePicker and TimePicker, to use in an Activity. But as far as I can see the only result of modifying the width or height of either Picker (in a negative direction) results in a cropped view, rather than a scaled/stretched view of the widget.
I am open to my own custom widgets of my own, but I would really prefer to keep this project as simple and clean as possible, matching the Android OS UI as much as possible, so using the native DatePicker and TimePicker seems like a logical choice to me. If anyone knows how to scale these widgets down rather than cropping them, I'd really appreciate it.
Thanks.
It is a very bad hack, but it should work:
Create a new view extending LinearLayout, overwrite method getChildStaticTransformation and setStaticTransformationsEnabled explicit to true.
In the method getChildStaticTransformation you can manipulate the tranformation parameter to scale down all the content of your extended LinearLayout.
And then add the DatePicker or something else as a child of this view.
EG:
public class ZoomView
extends LinearLayout
{
private float sf = 1f;
public ZoomView(final Context context, final AttributeSet attrs)
{
super(context, attrs);
setStaticTransformationsEnabled(true);
}
public ZoomView(final Context context)
{
super(context);
setStaticTransformationsEnabled(true);
}
public void setScaling(final float sf)
{
this.sf = sf;
}
#Override
protected boolean getChildStaticTransformation(final View child, final Transformation t)
{
t.clear();
t.setTransformationType(Transformation.TYPE_MATRIX);
final Matrix m = t.getMatrix();
m.setScale(this.sf, this.sf);
return true;
}
}