Android transfer animation of view in custom viewgroup - android

I want animation like expanding of the photos when I click folder of photos at gallery, like in this video about Android gallery.
i have two views in same custom viewgroup
view1 is in 0,0
view2 is in 100,100
since click "start" view1 will move to 100,0 and view2 will move to 0,100
My solution so far:
I use timer for refresh layout with new position by requestlayout.
the views' position will refresh by onLayout:
It works but it's not a native function and it is very slow with 100 views moving at same time.
Full code:
private class MyViewGroup extends ViewGroup{
View view1,view2;
Button btn;
public MyViewGroup(Context context) {
super(context);
view1=new View(context);
view1.setBackgroundColor(Color.RED);
this.addView(view1);
view2=new View(context);
view2.setBackgroundColor(Color.BLUE);
this.addView(view2);
btn=new Button(context);
btn.setText("start");
btn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
xLayout=0;
handler.sendEmptyMessage(0);
}
});
this.addView(btn);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int w = MeasureSpec.getSize(widthMeasureSpec);
int h= MeasureSpec.getSize(heightMeasureSpec);
int widthSpec = MeasureSpec.makeMeasureSpec(50, MeasureSpec.EXACTLY);
int heightSpec = MeasureSpec.makeMeasureSpec(50, MeasureSpec.EXACTLY);
view1.measure(widthSpec,heightSpec);
view2.measure(widthSpec,heightSpec);
btn.measure(widthSpec,heightSpec);
this.setMeasuredDimension(w, h);
}
private int xLayout=0;
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
view1.layout(xLayout,0,xLayout+50,50);
view2.layout(100-xLayout,100,150-xLayout,150);
btn.layout(0,200,50,250);
}
private void startAnimation(){
Timer timer = new Timer() ;
timer.schedule(new TimerTask(){
#Override
public void run() {
if(xLayout<100){
handler.sendEmptyMessage(0);
}
this.cancel();
}
},5);
}
private Handler handler=new Handler(){
#Override
public void handleMessage(Message msg) {
xLayout=xLayout+20;
view1.requestLayout();
startAnimation();
}
} ;
}

http://android-developers.blogspot.fr/2011/05/introducing-viewpropertyanimator.html
myView.animate().x(500).y(500);

we can use "LayoutTransition" as
final LayoutTransition transitioner = new LayoutTransition();
myViewGroup.setLayoutTransition(transitioner);
and when we click "start" addview
full code
private class MyViewGroup extends ViewGroup{
View view1,view2;
Button btn;
public MyViewGroup(final Context context) {
super(context);
view1=new View(context);
view1.setBackgroundColor(Color.RED);
this.addView(view1);
view2=new View(context);
view2.setBackgroundColor(Color.BLUE);
this.addView(view2);
btn=new Button(context);
btn.setText("start");
btn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
xLayout+=100;
MyViewGroup.this.addView(new View(context));
}
});
this.addView(btn);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int w = MeasureSpec.getSize(widthMeasureSpec);
int h= MeasureSpec.getSize(heightMeasureSpec);
int widthSpec = MeasureSpec.makeMeasureSpec(50, MeasureSpec.EXACTLY);
int heightSpec = MeasureSpec.makeMeasureSpec(50, MeasureSpec.EXACTLY);
view1.measure(widthSpec,heightSpec);
view2.measure(widthSpec,heightSpec);
btn.measure(widthSpec,heightSpec);
this.setMeasuredDimension(w, h);
}
private int xLayout=0;
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
view1.layout(xLayout,0,xLayout+50,50);
view2.layout(100-xLayout,100,150-xLayout,150);
btn.layout(0,200,50,250);
}
}

Related

Animate newly created View of unknown size

I want to animate View right after it was added to parent (something like DrawerLayout). The problem is that View has varying size, and animation target position depends on that size. Simplified sample code:
AnimatingView extends View {
public int offsetX;
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int screenWidth = MeasureSpec.getSize(widthMeasureSpec);
final int screenHeight = MeasureSpec.getSize(heightMeasureSpec);
offsetX = calculateOffset(screenWidth);
...
}
}
Code similar to this triggers the animation:
#Override
public void onClick(View v) {
AnimatingView animatingView = new AnimatingView(getContext());
parentLayout.addView(animatingView);
animatingView.animate().x(animatingView.offsetX).setDuration(500).start();
}
In this case onMeasure() happens after animate(), so animation fails. What is the correct way of doing stuff which depends on view measuring?
The simple & stupid way would be something like animateOnceAfterMeasuring() based on isInitialized flag, but I don't think it the correct way of doing this.
this should work:
AnimatingView animatingView = new AnimatingView(getContext());
parentLayout.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
#Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
v.removeOnLayoutChangeListener(this);
animatingView.animate().x(animatingView.offsetX).setDuration(500).start();
}
});
You can use the ViewTreeObserver for this
#Override
public void onClick(View v) {
final AnimatingView animatingView = new AnimatingView(getContext());
parentLayout.addView(animatingView);
animatingView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
if (Build.VERSION.SDK_INT < 16) {
animatingView.getViewTreeObserver().removeGlobalOnLayoutL‌​istener(this);
} else {
animatingView.getViewTreeObserver().removeOnGlobalLayoutList‌​ener(this);
}
animatingView.animate().x(animatingView.offsetX).setDuration(500).start();
}
});
}

How to invalidate view after it changed?

Please see this example img below first.
Sorry, my reputation is not enough, click below to see gif please
example img
Just as you see, i am using horizontalscrollview in bottom area. I can not scroll it to border when it become bigger. I can not figure out why, hope someone can help me solve this problem.
public class Rebound extends HorizontalScrollView implements View.OnClickListener {
private LinearLayout container;
private HorizontalScrollViewAdapter adapter;
private int childWidth, childHeight;
private CurrentImageChangeListener listener;
private OnItemClickListener onClickListener;
public Rebound(Context context, AttributeSet attrs) {
super(context);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
container = (LinearLayout) getChildAt(0);
}
#Override
public void invalidate() {
super.invalidate();
}
public void initDatas(HorizontalScrollViewAdapter adapter) {
this.adapter = adapter;
container = (LinearLayout) getChildAt(0);
final View view = adapter.getView(0, null, container);
container.addView(view);
calculateChildView(view);
}
private void calculateChildView(View view) {
if (childWidth == 0 && childHeight == 0) {
int w = View.MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
int h = View.MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
view.measure(w, h);
childHeight = view.getMeasuredHeight();
childWidth = view.getMeasuredWidth();
}
initChild();
}
private void initChild() {
container = (LinearLayout) getChildAt(0);
container.removeAllViews();
for (int i = 0; i < adapter.getCount(); i++) {
View view = adapter.getView(i, null, container);
view.setOnClickListener(this);
container.addView(view);
}
}
#Override
public void onClick(View v) {
}
public interface CurrentImageChangeListener {
void onCurrentImgChanged(int position, View viewIndicator);
}
public interface OnItemClickListener {
void onClick(View view, int pos);
}
public void setOnItemClickListener(OnItemClickListener onClickListener) {
this.onClickListener = onClickListener;
}
public void setCurrentImageChangeListener(CurrentImageChangeListener listener) {
this.listener = listener;
}
}

Passing data from View To Activity

I need view width and height to use in some calculations in activity.
In a SO Q&A i saw
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
this.setMeasuredDimension(parentWidth, parentHeight);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
It works but my questions:
1)how can i pass it to activity?
2) Or should i put my CustomView as a inner class into the Activity file like this
public class MainActivity extends ActionBarActivity {
int parentHeight=0;
int parentWidth=0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle aBundle=new Bundle();
MyView myView = new MyView(this);
Binary c=calculateCoordinates();
aBundle.putSerializable("coordinate", c);
myView.setData(aBundle);
myView.setBackgroundColor(Color.WHITE);
setContentView(myView);
}
public Binary calculateCoordinates(){
Random generator = new Random();
Binary c=new Binary();
c.setX(generator.nextInt(parentWidth-1));
c.setY(generator.nextInt(parentHeight-1));
return c;
}
#Override
public boolean onTouchEvent(MotionEvent event) {
//int action = event.getAction();
switch (event.getAction()){
case MotionEvent.ACTION_UP:
Intent intent = getIntent();
finish();
startActivity(intent);
break;
}
return true;
}
public class MyView extends View {
Bundle bundle = new Bundle();
Paint paint = new Paint();
public MyView(Context context) {
super(context);
}
#Override
public void onDraw(Canvas canvas) {
paint.setColor(Color.BLACK);
paint.setStrokeWidth(3);
Binary c = (Binary)bundle.getSerializable("coordinate");
canvas.drawRect(c.getX(), c.getY(), c.getX()+1, c.getY()+1, paint);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
parentWidth = MeasureSpec.getSize(widthMeasureSpec);
parentHeight = MeasureSpec.getSize(heightMeasureSpec);
this.setMeasuredDimension(parentWidth, parentHeight);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
public void setData(Bundle bundle){
this.bundle=bundle;
}
}
}
But if so i can not know when measurement have been got exactly, and if it has been got before i call the coordinate calculation.
Activity Class
add this to your OnCreate code.
final ViewTreeObserver obs = myView.getViewTreeObserver();
obs.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw () {
int height = myView.getHeight();
int width = myView.getWidth();
}
when the View will be drawn this function will be called with the correct width and height.
The OnMeasure function within your view will get called once the View has been placed on your actual page.
So let's say you want to get the Width and the Height when you click a button or something and want to pass those values over to another activity.
Put your view in your XML file:
<your.namespace.app.MyView
xmlns:app="http://schemas.android.com/apk/res/novoda.tastecard"
android:id="#+id/myView"
android:layout_width="match_parent"
...../>
Then reference your View in your activity:
mMyView = findViewById(R.id.myView);
Then you can then just do:
int width = myView.getWidth();
int height = myView.getHeight();
That should return you the width and the height of the view.
Then do the following to call the new Activity with your values:
Intent intent = new Intent(this, NewActivity.class);
intent.putExtra("width", width);
intent.putExtra("height", height);
startActivity(intent);

How to get display keyboard event in android

I have GridView android:layout_height="match_parent" with Editboxes, in LinearLayout with fix android:layout_height.
When I touch editbox, appears keyboard.
How to change android:layout_height in LinearLayout when keyboard appears and when disappears?
Try the link below hope it may help you
http://android-developers.blogspot.com/2009/04/updating-applications-for-on-screen.html
http://davidwparker.com/2011/08/30/android-how-to-float-a-row-above-keyboard/
private OnSoftKeyboardListener onSoftKeyboardListener;
#Override
protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
if (onSoftKeyboardListener != null) {
final int newSpec = MeasureSpec.getSize(heightMeasureSpec);
final int oldSpec = getMeasuredHeight();
if (oldSpec > newSpec){
onSoftKeyboardListener.onShown();
} else {
onSoftKeyboardListener.onHidden();
}
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
public final void setOnSoftKeyboardListener(final OnSoftKeyboardListener listener) {
this.onSoftKeyboardListener = listener;
}
public interface OnSoftKeyboardListener {
public void onShown();
public void onHidden();
}

How to expand a layout height with animation?

I couldn't find a good example for how to do this.
I have a RelativeLayout set with x height.
I want to add a button which expands the height to x+y height.
can someone refer me to a good example on how to do it programmatically?
You marked the solution that was closest. This is the exact solution. I had the same problem. Hopefully this answer will help others.
InstantiateResizeAnimation
ResizeAnimation resizeAnimation = new ResizeAnimation(
view,
targetHeight,
startHeight
);
resizeAnimation.setDuration(duration);
view.startAnimation(resizeAnimation);
ResizeAnimation class should look like this
public class ResizeAnimation extends Animation {
final int targetHeight;
View view;
int startHeight;
public ResizeAnimation(View view, int targetHeight, int startHeight) {
this.view = view;
this.targetHeight = targetHeight;
this.startHeight = startHeight;
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
int newHeight = (int) (startHeight + targetHeight * interpolatedTime);
//to support decent animation, change new heigt as Nico S. recommended in comments
//int newHeight = (int) (startHeight+(targetHeight - startHeight) * interpolatedTime);
view.getLayoutParams().height = newHeight;
view.requestLayout();
}
#Override
public void initialize(int width, int height, int parentWidth, int parentHeight) {
super.initialize(width, height, parentWidth, parentHeight);
}
#Override
public boolean willChangeBounds() {
return true;
}
}
You need a scale animation here is the official documentation
this is in code
private void animate() {
ImageView imageView = (ImageView) findViewById(R.id.ImageView01);
ScaleAnimation scale = new ScaleAnimation((float)1.0, (float)1.5, (float)1.0, (float)1.5);
scale.setFillAfter(true);
scale.setDuration(500);
imageView.startAnimation(scale);
}
Please check below new edited answer as below. But here you need to know the exact new height.
public class LayoutAnimationActivity extends Activity {
RelativeLayout ril1;
Button btn;
int initialHeight;
int actualHeight;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main2);
ril1 = (RelativeLayout) findViewById(R.id.relativeLayout1);
btn = new Button(this);
btn.setWidth(100);
btn.setHeight(200);
btn.setText("Button");
actualHeight = 210;
Ani a = new Ani();
a.setDuration(2000);
ril1.startAnimation(a);
}
class Ani extends Animation {
public Ani() {}
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
int newHeight;
newHeight = (int) (initialHeight * interpolatedTime);
ril1.removeAllViews();
btn.setWidth(100);
btn.setHeight(300);
btn.setText("as");
ril1.addView(btn);
ril1.getLayoutParams().height = newHeight;
ril1.requestLayout();
}
#Override
public void initialize(int width, int height, int parentWidth, int parentHeight) {
super.initialize(width, height, parentWidth, parentHeight);
initialHeight = actualHeight;
}
#Override
public boolean willChangeBounds() {
return true;
}
};
}
Two simple ways to do this without an Animation class:
1) Set android:animateLayoutChanges="true" in you xml layout file
2) Use a ViewProperty animator
layout.setPivot(0);
layout.animate().scaleY(scaleFactor).setDuration(500);
The pivot tells the view where to scale from, default is in the middle, which in my experience is almost never what you want. The duration is optional (default = 1000).
final Button button1 = (Button) view.findViewById(R.id.button);
final CollapseAnimator animator = new CollapseAnimator(topLayout);
final ViewTreeObserver.OnGlobalLayoutListener listener = new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
int mHeight = button1.getMeasuredHeight();
KLog.i("onGlobalLayout() mHeight:" + mHeight);
animator.setValues(mHeight*2, mHeight);
}
};
button1.getViewTreeObserver().addOnGlobalLayoutListener(listener);
button1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
view.post(new Runnable() {
#Override
public void run() {
button1.getViewTreeObserver().removeOnGlobalLayoutListener(listener);
animator.collapse();
}
});
}
});
and class
public class CollapseAnimator {
private View view;
private boolean collapse=true;
private int duation=300;
private int destHeight=300;
private ValueAnimator animator;
private int originHeight=0;
private int from=0;
private int to=0;
public CollapseAnimator(View view ) {
this.view = view;
}
public void setValues(int destHeight,int originHeight){
this.destHeight = destHeight;
this.originHeight=originHeight;
from=originHeight;
to=originHeight;
}
public void collapse(){
from=to;
if(collapse){
to=destHeight;
collapse=false;
}else{
to=originHeight;
collapse=true;
}
KLog.i("from:" + from+",to:"+to);
animator = ValueAnimator.ofInt(from, to);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
int val = (Integer) valueAnimator.getAnimatedValue();
ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
layoutParams.height = val;
view.setLayoutParams(layoutParams);
}
});
animator.setDuration(duation);
animator.start();
}
}

Categories

Resources