How to optimize Animated CustomView inside ListView item - android

I have this layout for ListView item
<com.example.donutgraph.TalkingFrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:padding="10dp" >
<TextView
android:id="#+id/position"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="TextView" />
<FrameLayout
android:layout_width="150dp"
android:layout_height="150dp" >
<com.example.donutgraph.GaugeView
android:id="#+id/gauge"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_gravity="center" />
<ImageView
android:id="#+id/img"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="right"
android:layout_marginRight="10dp"
android:layout_marginTop="20dp" />
</FrameLayout>
</com.example.donutgraph.TalkingFrameLayout>
The one which animated is a GaugeView. I create a simple time-based animation which will invalidate the view like this
private Runnable animator = new Runnable() {
#Override
public void run() {
....
update(now);
if (!isFinish()) {
needNewFrame = true;
} else {
Log.e(tag, "millisecond : " + (now - startTime));
}
if (needNewFrame) {
postDelayed(this, timeBetweenFrame);
}
invalidate();
}
};
private void update(long now) {
float dt = Math.min(now - lastTime, timeBetweenFrame);
currentTime += dt;
if (currentTime > duration) {
currentTime = duration;
}
}
protected void onDraw(Canvas canvas){
....
float percent = getPercentForTime(currentTime);
canvas.drawArc(rectF, 270, percent * -360.0f, false, paint);
....
canvas.drawText(String.valueOf(percentInt), xPos, yPos, paint);
}
This is the result I archieve
The problem here is because of animation need to call invalidate so it invoke all onDraw() in a hierarchy which I don't want and I think because of that it made my ListView so laggy when scrolling during the animation. When no animation on this GaugeView ListView runs smoothly.
Anyway to optimize this so that I can scroll smoothly?
and also is there anyway to prevent invalidate() call to invoke onDraw() on all view hierarchy? because everything is the same except the GaugeView which will animate and it is the only one that changing. It seem like a waste to call onDraw() on my TalkingFrameLayout again and again without changing.
Thanks

Related

Circular Reveal Animation not working in the first call

I need to implement a circular reveal animation after the transition between 2 fragments is finished so that the ImageButton (android:id="#+id/update_profile_pic") will be revealed with a nice animation
The problem is that it doesn't work as it should:
setEnterSharedElementCallback(new SharedElementCallback() {
Handler handler = new Handler();
#Override
public void onSharedElementEnd(List<String> sharedElementNames,
List<View> sharedElements,
List<View> sharedElementSnapshots) {
handler.postDelayed(new Runnable() {
#Override
public void run() {
update_profile_pic.setVisibility(View.GONE);
// get the center for the clipping circle
int cx = update_profile_pic.getWidth() / 2;
int cy = update_profile_pic.getHeight() / 2;
// get the final radius for the clipping circle
float finalRadius = (float) Math.hypot(cx, cy);
// create the animator for this view (the start radius is zero)
Animator anim = ViewAnimationUtils.createCircularReveal(update_profile_pic, cx, cy, 0f, finalRadius);
// make the view visible and start the animation
update_profile_pic.setVisibility(View.VISIBLE);
anim.start();
}
}, 600);
}
});
When I try this animation in a button click listener, the button needs to be clicked twice to make the animation work
The layout is like this:
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/activity_simple_two"
android:layout_gravity="center_horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
tools:context=".FragmentB"
xmlns:app="http://schemas.android.com/apk/res-auto">
<com.mikhaellopez.circularimageview.CircularImageView
android:id="#+id/profile_picture"
android:clickable="false"
android:src="#drawable/roni"
app:civ_border_color="#color/fadedText"
app:civ_border_width="0.1dp"
android:layout_width="260dp"
android:layout_height="260dp"
android:layout_margin="18dp"
android:transitionName="#string/simple_fragment_transition"/>
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="16dp"
android:scaleType="centerInside"
android:elevation="3dp"
android:layout_margin="26dp"
android:id="#+id/update_profile_pic"
android:src="#drawable/ic_menu_camera"
android:background="#drawable/round_button"
android:backgroundTint="#color/colorAccent"
app:layout_anchor="#id/profile_picture"
app:layout_anchorGravity="bottom|right|end"
android:visibility="gone"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Any help?
try to set visibility of your ImageButton to invisible instead of gone initially.

Flip single list item on a click and get detailed description on back of that item

I am having problem in animation of a single list item. how can i get the flip view upon click on the single item and get the detail on back of the item?
Create your list row item as below
<RelativeLayout
android:id="#+id/rellay"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginTop="20dp"
android:layout_centerHorizontal="true" >
<TextView
android:id="#+id/back"
android:layout_width="300dp"
android:layout_height="200dp"
android:background="#drawable/linearlayoutshape"
android:gravity="center"
android:text="BACK"
android:textAppearance="#android:style/TextAppearance.Large"
/>
<TextView
android:id="#+id/front"
android:layout_width="300dp"
android:layout_height="200dp"
android:background="#drawable/linearlayoutshape"
android:gravity="center"
android:text="FRONT"
android:textAppearance="#android:style/TextAppearance.Large" />
In this case i used to textView as Front and Back.
Now inside your adapter add this method..
public void flip(final View front, final View back, final int duration)
{
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
AnimatorSet set = new AnimatorSet();
set.playSequentially(
ObjectAnimator.ofFloat(front, "rotationY", 90).setDuration(duration / 2),
ObjectAnimator.ofInt(front, "visibility", View.GONE).setDuration(0),
ObjectAnimator.ofFloat(back, "rotationY", -90).setDuration(0),
ObjectAnimator.ofInt(back, "visibility", View.VISIBLE).setDuration(0),
ObjectAnimator.ofFloat(back, "rotationY", 0).setDuration(duration / 2));
set.start();
} else
{
front.animate().rotationY(90).setDuration(duration / 2)
.setListener(new AnimatorListenerAdapter()
{
#Override
public void onAnimationEnd(Animator animation) {
front.setVisibility(View.GONE);
back.setRotationY(-90);
back.setVisibility(View.VISIBLE);
back.animate().rotationY(0).setDuration(duration / 2).setListener(null);
}
});
}
}
Now on click of row item just call flip method like
flip(txtFront, txtBack, DURATION);
It will add the flip animation and make txtBack visible and hide the txtFront

How do you collapse and expand a complex view in android?

I am implementing the search functionality which consists of a search box, and a list of categories. For design purposes I have used EditText , GridView etc.
But when the activity starts I don't want all the search box to be displayed. I just want the EditText, and then when the EditText is clicked I need the view to expand, and when some other part of the screen is clicked, for example touching the ListView or pressing the button I need the view to collapse in its default state consisting the EditText.
I can use View.GONE or VIEW.VISIBLE but I want to reach a smooth animation for expanding and collapsing.
My activity_layout.xml:
<RelativeLayout
android:id="#+id/search_box"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="2dp"
android:layout_marginRight="2dp"
android:background="#android:color/transparent"
>
<android.support.v7.widget.CardView xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="#+id/cv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:background="#drawable/njoftime_item_background"
card_view:cardCornerRadius="1dp"
card_view:cardElevation="2dp">
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#color/white"
android:id="#+id/sr"
android:animateLayoutChanges="true"
android:padding="20dp">
<RelativeLayout
android:layout_width="fill_parent"
android:id="#+id/search_area"
android:layout_height="wrap_content"
android:focusableInTouchMode="true"
android:background="#drawable/njoftime_item_background"
>
<ImageButton
android:layout_width="100dp"
android:layout_height="50dp"
android:layout_marginLeft="1dp"
android:id="#+id/btn_search"
android:layout_alignParentRight="true"
android:background="#color/njoftime_main_color"
android:src="#drawable/ic_search_white"
android:onClick="searchPressed"
android:scaleType="fitCenter"
/>
<EditText
android:layout_width="fill_parent"
android:layout_height="50dp"
android:layout_toLeftOf="#+id/btn_search"
android:id="#+id/search_text"
android:layout_alignParentLeft="true"
android:background="#null"
android:ems="20"
android:textSize="18sp"
android:paddingLeft="10dp"
android:imeOptions="actionSearch"
android:inputType="text"
android:maxLines="1"
android:textColor="#color/njoftime_desc"
android:textCursorDrawable="#null"
/>
</RelativeLayout>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/search_categories_area"
android:layout_below="#+id/search_area"
android:paddingTop="20dp"
android:paddingBottom="10dp"
>
<GridView
android:id="#+id/search_grid"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:drawSelectorOnTop="false"
android:horizontalSpacing="2dp"
android:numColumns="5"
android:padding="4dp"
android:verticalSpacing="4dp" >
</GridView>
</RelativeLayout>
</RelativeLayout>
</android.support.v7.widget.CardView>
</RelativeLayout>
For this I have used android:animateLayoutChanges="true" and the following code
my_relative_layout = (RelativeLayout) findViewById(R.id.search_categories_area);
with:
public void searchPressed(View v) {
if (!searchbox_expanded) {
my_relative_layout.setVisibility(View.VISIBLE);
searchbox_expanded = true;
} else {
my_relative_layout.setVisibility(View.GONE);
searchbox_expanded = false;
}
}
Well the expanding is really smooth animation, but the collapsing is not animated.
I have used other solutions online but I have not reached the desire effect due to the complex layout I think. Any solutions will be appreciated.
This is quite simple :
To collapse the view you only need to add an onClickListener on the parent view (search_box) which triggers a function to collapse the view with an animation.
To expand the view you need to trigger another animation to expend the view when clicking on the search EditText
Here is an example of animation to collapse and to expend a view:
` import android.view.View;
import android.view.animation.Animation;
import android.view.animation.Transformation;
/**
* Created by wajdichamakhi on 26/01/15.
*/
public class ResizeAnimation extends Animation {
private int endHeight; // distance between start and end height
private int endWidth; // distance between start and end width
private View view;
/**
* constructor, do not forget to use the setParams(int, int) method before
* starting the animation
*
* #param v
*/
public ResizeAnimation(View v) {
this.view = v;
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
view.getLayoutParams().height = (int) (view.getHeight() + (endHeight - view.getHeight()) * interpolatedTime);
view.getLayoutParams().width = (int) (view.getWidth() + (endWidth - view.getWidth()) * interpolatedTime);
view.requestLayout();
}
/**
* set the starting and ending height for the resize animation
* starting height is usually the views current height, the end height is the height
* we want to reach after the animation is completed
*
* #param endWidths width in pixels
* #param endHeight height in pixels
*/
public void setParams(int endWidths, int endHeight) {
this.endWidth = endWidths;
this.endHeight = endHeight;
}
/**
* set the duration for the hideshowanimation
*/
#Override
public void setDuration(long durationMillis) {
super.setDuration(durationMillis);
}
#Override
public boolean willChangeBounds() {
return true;
}
/**
* Verify if this animation needs to be fired or not.
*/
public boolean isValidAnimation() {
if (this.endWidth == view.getWidth() && this.endHeight == view.getHeight())
return false;
else
return true;
}
}`
Now you put the function that returns a set of animation which contains this animation. I work with animation set so I can add several animation at once to the view and create a cool animation.
public AnimationSet getExpend_CollapseAnimationSet(final View v, int height, int width) {
AnimationSet animationSet = new AnimationSet(true);
ResizeAnimation resizeAnimation = new ResizeAnimation(v);
resizeAnimation.setParams(
width,
height);
if (resizeAnimation.isValidAnimation()) {
resizeAnimation.setDuration(ANIMATION_DURATION);
animationSet.addAnimation(resizeAnimation);
}
return animationSet;
}
Now use this function in your listeners with the right width and height
AnimationSet initialStateAnimation = getExpend_CollapseAnimationSet(myViewToExpend_Collapse,deiredHeight, desiredWidth);
myViewToExpend_Collapse.startAnimation(initialStateAnimation);

ImageView and EditText becomes dead after animation

I have been trying to implement an animation on a relativeLayout. The animation works fine but after the animation is complete the edittext and the imageview inside the relative layout stops responding to any kind of user activity.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<RelativeLayout
android:id="#+id/rl_maincontroller_mainLayout"
android:layout_width="match_parent"
android:layout_height="380dp"
android:background="#color/button_color" >
<ImageView
android:id="#+id/iv_maincontroller_backImage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_centerVertical="true"
android:src="#drawable/back" />
<EditText
android:id="#+id/tv_searchBox"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_toRightOf="#+id/iv_maincontroller_backImage"
android:background="#android:color/white"
android:drawableLeft="#drawable/search"
android:drawablePadding="10dp"
android:gravity="center_vertical"
android:layout_centerVertical="true"
android:hint="#string/search"
android:paddingLeft="10dp"
android:textColor="#android:color/black"
android:textColorHint="#color/grey"
android:textSize="17sp" />
</RelativeLayout>
</LinearLayout>
Before the animation the controls on the widgets work fine, the animation changes the parent relative layout from height 380 to 120 and after that the widgets become dead to any kind of user activity. I cannot control them. Can anyone please suggest an answer. Need it very urgently, have been stuck in it for hours.
The code for animating the layout is put below. I got it from a link and it worked as I wanted the animation to work but the widgets inside the layout became dead.
public class ResizeAnimation extends Animation {
private int startHeight;
private int deltaHeight; // distance between start and end height
private View view;
/**
* constructor, do not forget to use the setParams(int, int) method before
* starting the animation
* #param v
*/
public ResizeAnimation (View v) {
this.view = v;
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
view.getLayoutParams().height = (int) (startHeight + deltaHeight * interpolatedTime);
view.requestLayout();
}
/**
* set the starting and ending height for the resize animation
* starting height is usually the views current height, the end height is the height
* we want to reach after the animation is completed
* #param start height in pixels
* #param end height in pixels
*/
public void setParams(int start, int end) {
this.startHeight = start;
deltaHeight = end - startHeight;
}
/**
* set the duration for the hideshowanimation
*/
#Override
public void setDuration(long durationMillis) {
super.setDuration(durationMillis);
}
#Override
public boolean willChangeBounds() {
return true;
}
Then I call this class as follows:
ResizeAnimation a = new ResizeAnimation(layout);
a.setDuration(500);
a.setParams(oldHeight, newHeight);
layout.startAnimation(a);

Move ImageView relatively to another imageView's position- Android Studio

I'm trying to make an ImageView follow another ImageView, by changing it's coordinates. My movement method is that:
public void move(double zx, double zy) {
if (zx < a.getLeft()) {
if (a.getLeft() - zx > 0) {
a.setLeft(a.getLeft() - 1);
} else
a.setLeft(a.getLeft()+1);
}
if (zx > a.getLeft()) {
if (a.getLeft() - zx > 0) {
a.setLeft(a.getLeft() - 1);
} else
a.setLeft(a.getLeft() - 1);
}
if (zy > a.getTop()) {
if (a.getTop() - zy > 0) {
a.setTop(a.getTop() - 1);
} else
a.setTop(a.getTop() + 1);;
}
if (zy < a.getTop()) {
if (a.getTop() - zy > 0) {
a.setTop(a.getTop() - 1);
} else
a.setTop(a.getTop() + 1);
}
}
OnCreate:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fase);
a = (ImageView)findViewById(R.id.a);
b = (ImageView)findViewById(R.id.b);
move(b.getLeft(), b.getTop());
}
"a" and "b" are the ImageViews, and a should follow b. I declared both ImageViews correctly, and the method should work. Instead of it, the ImageView "a" keep in the same position since the application starts. What is wrong? Is the method move declared at the wrong place (onCreate) ? I also have tried to just set the vertical position of "a" in another part of the screen, for testing if it would work. But it didn't (and according to the logCat it's vertical position had changed). The tutorials I found about moving images are based on dragging them, but I haven't still found anything about another kind of movement, like this.
There is my layout (activity_fase.xml) :
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin"
tools:context="thegame.app.Fase"
android:background="#drawable/seapaint">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/b"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
android:src="#drawable/b"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/a"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:src="#drawable/a"
android:focusable="true"
android:clickable="false"
android:layout_marginBottom="79dp" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/imageView2"
android:layout_above="#+id/b"
android:layout_alignLeft="#+id/a"
android:layout_alignStart="#+id/key"
android:layout_marginBottom="67dp"
android:src="#drawable/key"
android:layout_marginLeft="50dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="Small Text"
android:id="#+id/points"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
I'm new on android developing, and I don't know the difference between relative layout and linear layout.
PROBLEM SOLVED
It's possible to change an ImageView's position for any region of the screen by setting a relativeLayout by code, and adding to it's parameters the leftMargin and the topMargin. Example:
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(80,80);
// 80 is just a number of my choice. There are many possibilities
params.leftMargin = 200;
params.topMargin = 400;
a.setLayoutParams(params);
Now the imageView's coordinates are (200,400). A successive change can be done. If you creat a timer that is called each 0.05 seconds and a task that adds 1 to the leftMargin and topMargin, the image's position will be successfully changed.

Categories

Resources