I am currently working on custom animation between switching pages in ViewPager. When I slide to the left, View is moving to the left and from below of it new View is coming to the front. I would like to make the view, that moves to the left (that I dispose) to shrink like on the folowing images:
On the second and third image I didn't picture new View coming to the front, but I think it wasn't necessary. Do you have any idea how can I modify the code? I would like to change height of TableLayout, RelativeLayout and FrameLayout and keep the height of both TextViews. Also I would have to change X-position of the whole View. I am looking forward for your creative answers (code). Below I attach my code for the animation.
import android.view.View;
import android.widget.RelativeLayout;
import android.annotation.SuppressLint;
import android.support.v4.view.ViewPager.PageTransformer;
public class DepthPageTransformer implements PageTransformer {
private static float MIN_SCALE = 0.75f;
#SuppressLint("NewApi")
public void transformPage(View view, float position) {
int pageWidth = view.getWidth();
if (position < -1) { // [-Infinity,-1)
// This page is way off-screen to the left.
view.setAlpha(0);
} else if (position <= 0) { // [-1,0]
// Use the default slide transition when moving to the left page
view.setTranslationX(0);
view.setScaleX(1);
view.setScaleY(1);
//float scaleFactor = (1 - Math.abs(position));
//WHAT TO PUT HERE TO ARCHIVE MY GOAL??
//This is how I can get particular layouts:
// RelativeLayout relativeLayout = (RelativeLayout) view.findViewById(R.id.fragment_object_canvas_RelativeLayout1);
//relativeLayout.setScaleX(scaleFactor);
//relativeLayout.setScaleY(scaleFactor);
} else if (position <= 1) { // (0,1]
// Fade the page out.
view.setAlpha(1 - position);
// Counteract the default slide transition
view.setTranslationX(pageWidth * -position);
//view.setRotation(1 - (position*360));
// Scale the page down (between MIN_SCALE and 1)
float scaleFactor = MIN_SCALE
+ (1 - MIN_SCALE) * (1 - Math.abs(position));
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
} else { // (1,+Infinity]
// This page is way off-screen to the right.
view.setAlpha(0);
}
}
}
UPDATE:
I can manipulate with height of whole View (for now I can do only this) with the following code:
LinearLayout relativeLayout = (LinearLayout) view.findViewById(R.id.fragment_object_canvas_linearLayout1);
relativeLayout.setLayoutParams(new FrameLayout.LayoutParams(relativeLayout.getWidth(), NEW_HEIGHT_HERE)));
However, I am not sure what should I put into NEW_HEIGHT_HERE variable to make it work corectly...
try to work with a position float variable.
Get the height of your layout and...:
relativeLayout.setLayoutParams(....,position*height+height)
You seem pretty insistent on people posting original code, but why reinvent the wheel? This library has a ton of great animations for a ViewPager, including one very similar to what you seem to be requesting.
https://github.com/jfeinstein10/JazzyViewPager
JazzyViewPager -
An easy to use ViewPager that adds an awesome set of custom swiping animations. Just change your ViewPagers to JazzyViewPagers and you're good to go!
public enum TransitionEffect {
Standard,
Tablet,
CubeIn,
CubeOut,
Flip,
Stack,
ZoomIn,
ZoomOut,
RotateUp,
RotateDown,
Accordion
}
You can select your animation by calling
private JazzyViewPager mJazzy;
/* ... */
mJazzy.setTransitionEffect(TransitionEffect.*);
Related
I have a layout with 2*2/3*3/4*4... ImageView. and some of them randomly colored like this:
For ranodomly colored one of Imageview, I have Use this code:
Random random = new Random();
id = array_image1.get(random.nextInt(array_image1.size()));
ObjectAnimator animator = ObjectAnimator.ofInt(findViewById(id), "backgroundResource", R.drawable.original_img, R.drawable.org_state).setDuration(1500);
animator.setStartDelay(1500);
animator.setEvaluator(new ArgbEvaluator());
animator.start();
And I'm handling some click event on colored ImageView like this:
for (int i = 0; i < array_image11.size(); ++i) {
final int btn = array_image11.get(i);
findViewById(btn).setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if ((findViewById(id)).equals(findViewById(btn)))
//Inform the user the button has been clicked
{
//forward
findViewById(id).setBackgroundResource(R.drawable.original_img);
}else {
//backward
Toast.makeText(StaticSpatial.this, "wrong", Toast.LENGTH_SHORT).show();
}
});
}
There is no problem till above.
But When I'm adding a random rotate animation code like this:
int n;
int[] a=new int[]{1,2};
final Random rnd = new Random();
n=a[rnd.nextInt(a.length)];
if(n==1)
{
ObjectAnimator rotateAnimator = ObjectAnimator.ofFloat(l4, View.ROTATION, 0, 90);
rotateAnimator.setDuration(2000); // miliseconds
rotateAnimator.start();n);
}
else
{
ObjectAnimator rotateAnimator = ObjectAnimator.ofFloat(l4, View.ROTATION, 0, 90);
rotateAnimator.setDuration(2000); // miliseconds
rotateAnimator.start();
}
After rotation image look like this(i.e. colored Imageview chage it's position):
After adding this rotate animation code my clickEvent not get correct ImageView id.
i.e. when imageview change it's position,their id should be go with that positon. but imageview id ramains at same postion.
So How to get required ImageviewId after rotation
Update:
After using azizbekian's answer(now using animator instead of animation) I found correct image-view id , but only first time.
i.e. first time when Activity starts it works good but when I'm going to a new view(say 3*3) and return back again to this view(2*2),it returns wrong image-view id till Activity restarts again.see my updated code for ref.
Explanation of working and issue:
I have already said that there are many matix of Imageview such as 2*2/3*3/4*4..... So when we start Application first load 2*2 matrix of imageview and when we click the odd colored imageview it goes to 3*3 matrix but when we click other than odd colored imageviewthen it goes to next level say 3*3.So when app start first time when I click on odd colored imageview it goes to 3*3 matrix but when return again on 2*2 after clicking other than odd colored imageview.and then again when we click on colored imageview it not get correct image id. and if any other query plz ask?
How to resolve this issue ?
When ImageView changes it's position, their id should go with that position. But ImageView id remains at same position.
That's because you are using Animation, which in fact doesn't change your View's position. What is does it makes an illusion of animation, so it only changes that view's matrix, but doesn't perform layout changes to the view.
Use Animator API instead of Animation.
Update
Given this animation xml:
<set xmlns:android="schemas.android.com/apk/res/android">
<rotate
android:fromDegrees="0"
android:toDegrees="90"
android:pivotX="50%"
android:pivotY="50%"
android:duration="2000" />
</set>
This can be substituted with following:
ObjectAnimator rotateAnimator = ObjectAnimator.ofFloat(yourView, View.ROTATION, 0, 90);
rotateAnimator.setDuration(2000);
rotateAnimator.start();
Update:
Just set rotation zero at every load of view (or layout) like this:
mylayoutname.setRotation(0);
Because after rotation it doesn't go to zero degree automatically until activity stops.
Maybe instead of using rotation you can store the Ids of the ImageViews in a List or Array and the Id of the currently colored ImageView in a separated variable, and when you have to rotate instead you can simply select one random ImageView from the List/Array (excluding the currently colored one), remove the color from the previous one and color the new one.
By the way, when you have 3x3, 5x5, 7x7 etc. layouts is the middle ImageView never colored? 'Cause in those cases a rotation wouldn't change anything (visually, at least). I mean, a rotation works for choosing a random square in a layout of 2x2 squares, but not in any other case. Do you need to choose the squares randomly or do they need to always be chosen by a rotation? (I hope what I mean is clear...)
With version 23.2 we can now use WRAP_CONTENT for recyclerView height, which is great. I am doing this, however I want to recalculate the height after an item is added (or removed) to the adapter (thus increasing or decreasing the height).
My particular RecyclerView is starting with 1 item, and then adding items as the user makes selection. So I need the RecyclerView layout to increase in height, up to a point. Ideally this would happen with a smooth animation when the list increases or decreases.
How can we make it WRAP_CONTENT after it has been laid out?
Tried:
recyclerview.requestLayout();
recyclerview.invalidate();
I would expect it to work with View.invalidate().
If that does not work, try to call either requestLayout or invalidate on the parent view.
How RecyclerView Resize itself based on with the new LayoutManger
The RecyclerView widget provides an advanced and flexible base for creating lists and grids as well as supporting animations. This release brings an exciting new feature to the LayoutManager API: auto-measurement! This allows a RecyclerView to size itself based on the size of its contents. This means that previously unavailable scenarios, such as using WRAP_CONTENT for a dimension of the RecyclerView, are now possible. You’ll find all built in LayoutManagers now support auto-measurement.
Due to this change, make sure to double check the layout parameters of your item views: previously ignored layout parameters (such as MATCH_PARENT in the scroll direction) will now be fully respected.
If you have a custom LayoutManager that does not extend one of the built in LayoutManagers, this is an opt-in API - you’ll be required to call setAutoMeasureEnabled(true) as well as make some minor changes as detailed in the Javadoc of the method.
Note that although RecyclerView animates its children, it does not animate its own bounds changes. If you would like to animate the RecyclerView bounds as they change, you can use the Transition APIs.
Please read this
Option I
Did you see this answer?
It's not using the recyclerView's WRAP_CONTENT, but it might work.
You can also create your own custom recyclerView (extends RecyclerView) and override the onMeasure() method there instead using the layoutManager in the link.
Option II
Try to set the layout params before drawing the view. I haven't checked if it is called when recyclerView layout changes, but if it does, then it will work. Something like this (in your Activity/Fragment onCreate()/onCreateView() method:
recyclerView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
recyclerView.getViewTreeObserver().removeOnPreDrawListener(this);
YourParentLayoutType.LayoutParams params = (YourParentLayoutType.LayoutParams) recyclerView.getLayoutParams();
params.height = YourParentLayoutType.LayoutParams.WRAP_CONTENT;
recyclerView.setLayoutParams(params);
return true;
}
});
Use your recyclerView's parent layout type instead of YourParentLayoutType in the code.
I'm not sure this will work when layout refreshes, but maybe worth a try.
Use this class:
Please use 23.2.1 as 23.2 was way buggy.
Also have you tried to call notifyDataSetChanged on the recyclerview adapter , as far as i think it should expand without problem if you have given wrap_content as height of recyclerview
else u can use this class:
import android.content.Context;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
public class MyLinearLayoutManager extends LinearLayoutManager {
public MyLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
super(context, orientation, reverseLayout);
}
private int[] mMeasuredDimension = new int[2];
#Override
public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state,
int widthSpec, int heightSpec) {
final int widthMode = View.MeasureSpec.getMode(widthSpec);
final int heightMode = View.MeasureSpec.getMode(heightSpec);
final int widthSize = View.MeasureSpec.getSize(widthSpec);
final int heightSize = View.MeasureSpec.getSize(heightSpec);
int width = 0;
int height = 0;
for (int i = 0; i < getItemCount(); i++) {
if (getOrientation() == HORIZONTAL) {
measureScrapChild(recycler, i,
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
heightSpec,
mMeasuredDimension);
width = width + mMeasuredDimension[0];
if (i == 0) {
height = mMeasuredDimension[1];
}
} else {
measureScrapChild(recycler, i,
widthSpec,
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
mMeasuredDimension);
height = height + mMeasuredDimension[1];
if (i == 0) {
width = mMeasuredDimension[0];
}
}
}
switch (widthMode) {
case View.MeasureSpec.EXACTLY:
width = widthSize;
case View.MeasureSpec.AT_MOST:
case View.MeasureSpec.UNSPECIFIED:
}
switch (heightMode) {
case View.MeasureSpec.EXACTLY:
height = heightSize;
case View.MeasureSpec.AT_MOST:
case View.MeasureSpec.UNSPECIFIED:
}
int widthDesired = Math.min(widthSize,width);
setMeasuredDimension(widthDesired, height);
}
private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,
int heightSpec, int[] measuredDimension) {
View view = recycler.getViewForPosition(position);
// For adding Item Decor Insets to view
super.measureChildWithMargins(view, 0, 0);
RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams();
int childWidthSpec = ViewGroup.getChildMeasureSpec(
widthSpec,
getPaddingLeft() + getPaddingRight() + getDecoratedLeft(view) + getDecoratedRight(view),
p.width);
int childHeightSpec = ViewGroup.getChildMeasureSpec(
heightSpec,
getPaddingTop() + getPaddingBottom() + getDecoratedTop(view) + getDecoratedBottom(view) ,
p.height);
view.measure(childWidthSpec, childHeightSpec);
// Get decorated measurements
measuredDimension[0] = getDecoratedMeasuredWidth(view) + p.leftMargin + p.rightMargin;
measuredDimension[1] = getDecoratedMeasuredHeight(view) + p.bottomMargin + p.topMargin;
recycler.recycleView(view);
}
}
I wanna create a view with Arc Shape background.. my view has weight of .3.. which makes it fill one third of my layout..
I try to set its background to an arc shape (I want it to be half oval) like this:
ArcShape shape = new ArcShape(270, 180);
ShapeDrawable shapeDrawable = new ShapeDrawable(shape);
shapeDrawable.getPaint().setColor(getResources().getColor(R.color.primary_color));
leftPathView.setBackgroundDrawable(shapeDrawable);
this generates the shape I need but it doesn't fill the space of my view.. It only takes half of it.. But when I create a completed circle it takes all the space..
Any Idea ?
After a bit of research I found this to be the best answer. Especially if you want to do this in your onCreate function, bacause when the onCreate function hasn't ended the layout does not yet have a width and height (more info here).
final LinearLayout leftPathView= (LinearLayout) findViewById(R.id.left_path_view);
layout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
leftPathView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
leftPathView.setX(-layout.getWidth());
leftPathView.getLayoutParams().width = layout.getWidth() * 2;
leftPathView.requestLayout();
}
});
ArcShape shape = new ArcShape(270, 180);
ShapeDrawable shapeDrawable = new ShapeDrawable(shape);
shapeDrawable.getPaint().setColor(getResources().getColor(R.color.primary_color));
layout.setBackground(shapeDrawable);
This code does make your View go out of the bounds of your screen, so when adding other items to this View you need to take that into account. A solution for that could be to put the View in a RelativeLayout and put another view on top of the leftPathView.
I'm trying to animate UI elements. I would like to move an editText and a Button from the middle to the top of the screen and display results of an http call below them in a table. It would be great if anyone could point me in the right direction, at this point I don't know wether I should use Java or XML for this.
Thanks in advance.
Use Translation framework to achieve this, this works as:
TranslateAnimation(float fromXDelta, float toXDelta, float fromYDelta, float toYDelta)
So you need to write your code for moving view in y-axis direction, as follows:
mAnimation = new TranslateAnimation(0, 0, 0, 599);
mAnimation.setDuration(10000);
mAnimation.setFillAfter(true);
mAnimation.setRepeatCount(-1);
mAnimation.setRepeatMode(Animation.REVERSE);
view.setAnimation(mAnimation);
Here view may be anything, textview, imageView etc.
accepted answer caused an error inside my code, code snippet below almost identical to accepted answer & worked without causing errors, to slide an object off the screen. i needed gestures tied to keyPad to also 'slide away' , and switched from TranslateAnimation to ObjectAnimator (second block of code below).
final LinearLayout keyPad = (LinearLayout)findViewById(R.id.keyPad);
moveKeyPadUp(keyPad);
private void moveKeyPadUp(LinearLayout keyPad){
Animation animation = new TranslateAnimation(0,0,0,-500);
animation.setDuration(1000);
animation.setFillAfter(true);
keyPad.startAnimation(animation);
}
private void moveKeyPadUpdated(LinearLayout keyPad){
ObjectAnimator mover = ObjectAnimator.ofFloat(keyPad,"translationY",0,-500);
mover.setDuration(300);
mover.start();
}
I'm trying my app format some images in the screen after the Activity loads. The problem is while inside onCreate(), onResume() methods my ImageView have width and height=0. How can I run some code after the views are resized?
I test onPostResume() but it dont work =(
Views in Android do not have fixed size/position like in Blackberry or iPhone; instead, they are layed out dynamically. Layout happens much later than onCreate/onResume, and theoretically can happen many times. Every view has methods onMeasure and onLayout which are responsible for that. Only after onLayout method returns you can tell the view's size and position. Before that the view's size is 0 and position is 0 (as you've noticed).
So it makes little sense trying to get ImageView's size in onCreate/onResume because onLayout hasn't yet been called at that point.
Instead, override onLayout like this and do your stuff there:
public class MyImageView extends ImageView {
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
// at this point size and position are known
int h = getHeight();
int w = getWidth();
doSomethingCool(h,w);
}
}