I'm trying to create a translate animation to an imageView. The animation works but not according to the value I'm putting in the setDuration()
This is the code
/* flipping the images out of the screen */
float outOfScreenX = currentImageLocationX * DRAG_ACTION_SCREEN_BOUNDS_THREASHOLD;
float outOfScreenY = currentImageLocationY * DRAG_ACTION_SCREEN_BOUNDS_THREASHOLD;
translate = new TranslateAnimation(0, outOfScreenX, 0, outOfScreenY);
long velocity = Math.max(Math.abs((int) vTracker.getXVelocity()), Math.abs((int) vTracker.getYVelocity())) / 10;
velocity = (long) Math.min(velocity, 200);
translate.setDuration(velocity);
translate.setFillAfter(true);
mDragView.clearAnimation();
mDragView.startAnimation(translate);
imageStack.removeView(mOriginator);
The value of "velocity" derived from the vTracker, the speed of the user's touch on the view. It's always between 200-600 proximately, but the view moves much faster than this(and also a little flickering but this is another topic).
Related
After few hours of trying I'm looking for some hints on how to add snap-scroll mechanism to MPAndroid. Basically I want the 5 visible bars to align so they are fully visible and centered. I now imported the library source code because it looks like there's no other way to change the code in computeScroll (BarLineChartTouchListener).
Edit:
To clarify - I'm showing around 20 bars but chart is zoomed so user can scroll horizontally. What bothers me it is not getting aligned automatically so first visible bar might be clipped in half. I'm looking for snapping effect where it will round the position to the nearest multiplication of the bar width, leaving 5 fully visible bars.
I ended up adding the following function in BarLineChartBase.java. I know it's far from elegant, but seems to do the job. It's limited to targetApi > 11, because of the ValueAnimator. For lower API (which I don't cater for) you might need to have a look at nineoldandroids or some other animation loop technique.
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
public void alignX() {
int count = this.getValueCount();
int xIndex = this.getLowestVisibleXIndex() + Math.round( (this.getHighestVisibleXIndex() - this.getLowestVisibleXIndex()) / 2.0f );
float xsInView = this.getXAxis().getValues().size() / this.getViewPortHandler().getScaleX();
Transformer mTrans = this.getTransformer(YAxis.AxisDependency.LEFT);
float[] pts = new float[] { xIndex - xsInView / 2f, 0 };
mTrans.pointValuesToPixel(pts);
final Matrix save = new Matrix();
save.set(this.getViewPortHandler().getMatrixTouch());
final float x = pts[0] - this.getViewPortHandler().offsetLeft();
final int frames = 20;
ValueAnimator valueAnimator = new ValueAnimator().ofInt(0, frames);
valueAnimator.setDuration(500);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
int prev = -1;
#Override
public void onAnimationUpdate(ValueAnimator animation) {
if( (int) animation.getAnimatedValue() > prev ) {
save.postTranslate( -x / (float)frames, 0);
BarLineChartBase.this.getViewPortHandler().refresh(save, BarLineChartBase.this, true);
}
prev = (int) animation.getAnimatedValue();
}
});
valueAnimator.start();
}
I trigger it at the end of computeScroll function in BarLineChartTouchListener.
I kept names of variables as I copied code from functions like MoveViewJob, ViewPortHandler etc. Since it's only aligning in x axis - I removed Y axis calculations and used zeros instead. Any optimizations welcome, especially from the author #PhilippJahoda.
I've got a Custom ViewGroup class and an image I've added to it. When the screen is tapped I want to animate the added image to travel across the screen in a wavelike pattern. What I have now is below but though the image moves in a wavelike pattern it jumps around too quickly and is a blur. How can I slow it down to move in a steady wave?
ValueAnimator animator = ValueAnimator.ofFloat(0, 1); // values from 0 to 1
if(animateImage) {
incrementalValue = 0f;
animator.setDuration(4000);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = ((Float) (animation.getAnimatedValue()))
.floatValue();
float amplitude = 100f;
mImage.setTranslationX(incrementalValue);
mImage.setTranslationY((float) (amplitude * Math.sin((incrementalValue) * Math.PI)));
incrementalValue += 5f;
}
});
animator.setTarget(mImage);
animator.start();
}
You declare a float value in onAnimationUpdate and never use it again. The calcualtion for the image translation is mImage.setTranslationY((float) (amplitude * Math.sin((incrementalValue) * Math.PI)));. If you insert the values and incrementalValue ( = 0) doesn't change, this calculation will always return 0 because sin(0) = 0 and one 0 in a multiplication makes the product 0. You should insert animator.getAnimatedValue for incrementalValue. Besides, i suggest you change the calculation to sin(animator.getAnimatedValue()*PI*2) this makes the wavelength of the sine 1 and the image will move up and down once per repetition of the animation and it won't jump when the aimation restarts.
Note you can still multiply with amplitude to make the image move a certain distance.
I am trying to make a simple face detection app consisting of a SurfaceView (essentially a camera preview) and a custom View (for drawing purposes) stacked on top. The two views are essentially the same size, stacked on one another in a RelativeLayout. When a person's face is detected, I want to draw a white rectangle on the custom View around their face.
The Camera.Face.rect object returns the face bound coordinates using the coordinate system explained here and the custom View uses the coordinate system described in the answer to this question. Some sort of conversion is needed before I can use it to draw on the canvas.
Therefore, I wrote an additional method ScaleFacetoView() in my custom view class (below) I redraw the custom view every time a face is detected by overriding the OnFaceDetection() method. The result is the white box appears correctly when a face is in the center. The problem I noticed is that it does not correct track my face when it moves to other parts of the screen.
Namely, if I move my face:
Up - the box goes left
Down - the box goes right
Right - the box goes upwards
Left - the box goes down
I seem to have incorrectly mapped the values when scaling the coordinates. Android docs provide this method of converting using a matrix, but it is rather confusing and I have no idea what it is doing. Can anyone provide some code on the correct way of converting Camera.Face coordinates to View coordinates?
Here's the code for my ScaleFacetoView() method.
public void ScaleFacetoView(Face[] data, int width, int height, TextView a){
//Extract data from the face object and accounts for the 1000 value offset
mLeft = data[0].rect.left + 1000;
mRight = data[0].rect.right + 1000;
mTop = data[0].rect.top + 1000;
mBottom = data[0].rect.bottom + 1000;
//Compute the scale factors
float xScaleFactor = 1;
float yScaleFactor = 1;
if (height > width){
xScaleFactor = (float) width/2000.0f;
yScaleFactor = (float) height/2000.0f;
}
else if (height < width){
xScaleFactor = (float) height/2000.0f;
yScaleFactor = (float) width/2000.0f;
}
//Scale the face parameters
mLeft = mLeft * xScaleFactor; //X-coordinate
mRight = mRight * xScaleFactor; //X-coordinate
mTop = mTop * yScaleFactor; //Y-coordinate
mBottom = mBottom * yScaleFactor; //Y-coordinate
}
As mentioned above, I call the custom view like so:
#Override
public void onFaceDetection(Face[] arg0, Camera arg1) {
if(arg0.length == 1){
//Get aspect ratio of the screen
View parent = (View) mRectangleView.getParent();
int width = parent.getWidth();
int height = parent.getHeight();
//Modify xy values in the view object
mRectangleView.ScaleFacetoView(arg0, width, height);
mRectangleView.setInvalidate();
//Toast.makeText( cc ,"Redrew the face.", Toast.LENGTH_SHORT).show();
mRectangleView.setVisibility(View.VISIBLE);
//rest of code
Using the explanation Kenny gave I manage to do the following.
This example works using the front facing camera.
RectF rectF = new RectF(face.rect);
Matrix matrix = new Matrix();
matrix.setScale(1, 1);
matrix.postScale(view.getWidth() / 2000f, view.getHeight() / 2000f);
matrix.postTranslate(view.getWidth() / 2f, view.getHeight() / 2f);
matrix.mapRect(rectF);
The returned Rectangle by the matrix has all the right coordinates to draw into the canvas.
If you are using the back camera I think is just a matter of changing the scale to:
matrix.setScale(-1, 1);
But I haven't tried that.
The Camera.Face class returns the face bound coordinates using the image frame that the phone would save into its internal storage, rather than using the image displayed in the Camera Preview. In my case, the images were saved in a different manner from the camera, resulting in a incorrect mapping. I had to manually account for the discrepancy by taking the coordinates, rotating it counter clockwise 90 degrees and flipping it on the y-axis prior to scaling it to the canvas used for the custom view.
EDIT:
It would also appear that you can't change the way the face bound coordinates are returned by modifying the camera capture orientation using the Camera.Parameters.setRotation(int) method either.
I want to draw a infinitely repeating parallax using Cocos2D on Android.
Now, there are some solutions given to this problem in Objective C, but I'm stuck with my implementation in Android. I have tried using
CCSprite background = CCSprite.sprite("background_island.png");
CCTexParams params = new CCTexParams(GL10.GL_LINEAR,GL10.GL_LINEAR,GL10.GL_REPEAT,GL10.GL_REPEAT);
background.getTexture().setTexParameters(params);
But it only extends the background in 1 direction.
I guess I have to use 2 sprites, such that as soon as 1st finishes, the other starts and vice versa, but I'm stuck with the implementation.
I had the same problem and figured it out.
Try this. Declare the background and offset as a member:
CCSprite _bg;
float _bgOffset;
In your scene constructor:
CGSize winSize = CCDirector.sharedDirector().displaySize();
_bg = CCSprite.sprite("yourbg.png"); // needs to be square, i.e. 256x256
_bg.setTextureRect(0, 0, winSize.width, winSize.height, false);
_bg.getTexture().setTexParameters(GL10.GL_LINEAR, GL10.GL_LINEAR, GL10.GL_REPEAT,
GL10.GL_REPEAT);
_bg.setAnchorPoint(CGPoint.zero());
this.addChild(_bg);
And in your update(float dt) method:
if (_bgOffset > 2000000000)
_bgOffset = 0; // don't want problems, do we?
_bgOffset += dt * PIXELS_PER_SECOND; // this can be dynamic if you want
_bg.setTextureRect(0, _bgOffset, _bg.getTextureRect().size.width,
_bg.getTextureRect().size.height, false);
See "Repeating Backgrounds" in http://www.raywenderlich.com/3857/how-to-create-dynamic-textures-with-ccrendertexture for the Objective C code
If you need to go both ways, you could perhaps start with a non-zero _bgOffset and see if that works.
Hope this helps someone!
Please check out below link for Parallax vertical endless background: http://kalpeshsantoki.blogspot.in/2014/07/create-vertical-endless-parallax.html
CGSize winSize = CCDirector.sharedDirector().displaySize();
//I made graphics for screen 720*1200....so I made this dynamic scale to support multiple screens
float sX = winSize.width / 720.0f;
float sY = winSize.height / 1200.0f;
background = CCVerticalParallaxNode.node(sX, sY, true);
background.addEntity(1f, "background.png", 0);
background.addEntity(3, "road_simple.png", winSize.width / 2);
background.addEntity(1.7f, "road_side.png", 0);
addChild(background);
I want my animation to only spin for one rotation. Everytime I adjust the duration it just spins at the same speed for longer/slower. Where am I going wrong?
private static final float ROTATE_FROM = 0.0f;
private static final float ROTATE_TO = -10.0f * 360.0f;
protected RotateAnimation r = new RotateAnimation(ROTATE_FROM, ROTATE_TO,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
r.setDuration(5000);
r.setRepeatCount(0);
r.setInterpolator(this, android.R.anim.linear_interpolator);
r.setAnimationListener(AndroidVideoPlayer.this);
favicon.startAnimation(r);
I believe what you are looking for is repeatCount
r.setRepeatCount(0)
http://developer.android.com/reference/android/view/animation/Animation.html#setRepeatCount(int)
From the documentation:
Sets how many times the animation should be repeated. If the repeat
count is 0, the animation is never repeated. If the repeat count is
greater than 0 or INFINITE, the repeat mode will be taken into
account. The repeat count is 0 by default.
Or are you saying that the animation continues to rotate for whatever duration you set? (i.e., you set it for 5000 it rotates for 5 seconds even if it overshoots the "end"). What if you set that value to less than the amount of time it takes to rotate your animation?
In that case it's probably your LinearInterpolator that's animating for a constant rate of change. You could maybe print the value of computeDurationHint() to see if the application is able to guess how long the duration should be.
P.S. What are your ROTATE_FROM and ROTATE_TO values?
It was the -10.0f that was the problem!