Add animation when hide "LinearLayout" (View.GONE) and show LinearLayout (View.VISIBLE) - android

Sorry for my English... I will try to explain what I want to do.
I have a project. It can be downloaded at the link:
https://drive.google.com/file/d/0Bxhi0uFKK3upcXJjNGtMVkg4TDQ/view?usp=sharing
As you can see the screenshot:
http://pixs.ru/showimage/Screenshot_9509352_15647059.png
The button "Hide/Show B layout" hides and shows the green container - "B layout". I want add animation top down when the container "B layout" is showing. And the animation from the bottom up when the container is hidden. Also, I want the blue container "C", gradually fell together with the container "B". And rising smoothly, together with the container "B". Please help me to do it.
Below duplicate my code:
MainActivity
public class MainActivity extends Activity {
View Layout;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Layout = findViewById(R.id.bLayout);
final View button2 = findViewById (R.id.button);
button2.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick (View v){
if ((Layout.getVisibility() == View.VISIBLE))
{
Layout.setVisibility(View.GONE);
}
else
{
// Animation animFadeIn = AnimationUtils.loadAnimation(getApplicationContext(), android.R.anim.slide_in_left);
// Layout.setAnimation(animFadeIn);
Layout.setVisibility(View.VISIBLE);
}
}
});
}
}

I found a solution to the problem. Full lesson and source code can be downloaded here: click here
Or use the code below:
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<LinearLayout
android:id="#+id/header"
android:layout_width="match_parent"
android:layout_height="64dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginTop="16dp"
android:background="#FCF"
android:orientation="horizontal" >
<TextView
android:id="#+id/color"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
android:layout_marginTop="8dp"
android:background="#drawable/rectangle"
android:fontFamily="sans-serif-light"
android:gravity="center_vertical"
android:text=""
android:textAlignment="center"
android:textStyle="bold" />
<TextView
android:id="#+id/clickme"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="4dp"
android:fontFamily="sans-serif-light"
android:gravity="center_vertical"
android:text="click_here"
android:textStyle="bold" />
</LinearLayout>
<LinearLayout
android:id="#+id/expandable"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:background="#FFF"
android:orientation="vertical"
android:paddingLeft="4dp" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="text1" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="text2" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Слуга: text3" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="text4" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="text5" />
</LinearLayout>
MainActivity.java
public class MainActivity extends Activity {
LinearLayout mLinearLayout;
LinearLayout mLinearLayoutHeader;
ValueAnimator mAnimator;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setTitle("title");
mLinearLayout = (LinearLayout) findViewById(R.id.expandable);
// mLinearLayout.setVisibility(View.GONE);
mLinearLayoutHeader = (LinearLayout) findViewById(R.id.header);
// Add onPreDrawListener
mLinearLayout.getViewTreeObserver().addOnPreDrawListener(
new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
mLinearLayout.getViewTreeObserver()
.removeOnPreDrawListener(this);
mLinearLayout.setVisibility(View.GONE);
final int widthSpec = View.MeasureSpec.makeMeasureSpec(
0, View.MeasureSpec.UNSPECIFIED);
final int heightSpec = View.MeasureSpec
.makeMeasureSpec(0,
View.MeasureSpec.UNSPECIFIED);
mLinearLayout.measure(widthSpec, heightSpec);
mAnimator = slideAnimator(0,
mLinearLayout.getMeasuredHeight());
return true;
}
});
mLinearLayoutHeader.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mLinearLayout.getVisibility() == View.GONE) {
expand();
} else {
collapse();
}
}
});
}
private void expand() {
// set Visible
mLinearLayout.setVisibility(View.VISIBLE);
mAnimator.start();
}
private void collapse() {
int finalHeight = mLinearLayout.getHeight();
ValueAnimator mAnimator = slideAnimator(finalHeight, 0);
mAnimator.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationEnd(Animator animator) {
// Height=0, but it set visibility to GONE
mLinearLayout.setVisibility(View.GONE);
}
#Override
public void onAnimationStart(Animator animator) {
}
#Override
public void onAnimationCancel(Animator animator) {
}
#Override
public void onAnimationRepeat(Animator animator) {
}
});
mAnimator.start();
}
private ValueAnimator slideAnimator(int start, int end) {
ValueAnimator animator = ValueAnimator.ofInt(start, end);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
// Update Height
int value = (Integer) valueAnimator.getAnimatedValue();
ViewGroup.LayoutParams layoutParams = mLinearLayout
.getLayoutParams();
layoutParams.height = value;
mLinearLayout.setLayoutParams(layoutParams);
}
});
return animator;
}
}

I faced a similar issue and this is the easiest solution I could find:
setVisibility(View.GONE) on the view you wish to hide.
And make sure in the xml layout the parent has following attribute:
android:animateLayoutChanges="true"

I think you can easily do this by using the AlphaAnimation class. Here is a similar question with an answer.

So I think what you're looking for is how to hook up translate animations to show/hide a view as opposed to just setting the visibility instantly.
Take a look at Show and hide a View with a slide up/down animation. Instead of just setting the visibility, first you run the translate animations, then add the hooks to show or hide the view after they're finished.
If you find that the bottom view is not moving, jump into your Android developer options and enable "Show layout bounds" then you can see the borders for views (animations don't move the actual view bounds). To get the bottom view to animate as well it will also need an translate animation.

Related

First Time View.getHeight getting "0" after animation ends only I'm getting the height, why?

I have an animation to view Slide up and down in an Activity, I'm using the below code. In the first time, I'm getting the rlView height as "0" once the animation ends only I get the proper height
private void animateView() {
Log.d(TAG, "animateView: height" + markLocationBinding.rlView.getHeight());
if (markLocationBinding.ivHurray.getVisibility() == View.GONE) {
markLocationBinding.ivHurray.setVisibility(View.VISIBLE);
Log.d(TAG, "animateView: inside height" + markLocationBinding.rlView.getHeight());
markLocationBinding.ivHurray.animate()
.translationY(markLocationBinding.rlView.getHeight())
.alpha(1.0f)
.setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
Log.d(TAG, "animateView: inside height end" + markLocationBinding.rlView.getHeight());
}
});
} else {
markLocationBinding.ivHurray.animate()
.translationY(0)
.alpha(0f)
.setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
markLocationBinding.ivHurray.setVisibility(View.GONE);
}
});
}
}
My layout
<RelativeLayout
android:id="#+id/ivHurray"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="-450dp"
android:background="#bb000000"
android:clickable="true"
android:orientation="vertical"
android:visibility="gone">
<RelativeLayout
android:id="#+id/rlView"
android:layout_width="match_parent"
android:layout_height="450dp">
<LinearLayout
android:id="#+id/llText"
android:layout_width="match_parent"
android:layout_height="130dp"
android:layout_below="#+id/ivMan"
android:layout_marginTop="-30dp"
android:background="#94aea1"
android:gravity="bottom"
android:orientation="vertical"
android:paddingBottom="15dp">
<TextView
android:id="#+id/tvHurray"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:padding="8dp"
android:text="#string/hurray"
android:textColor="#color/white"
android:textSize="22dp"
android:textStyle="bold" />
<TextView
android:id="#+id/tvHurraySub"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:padding="5dp"
android:text="#string/geo_marked_loc"
android:textColor="#color/white"
android:textSize="18dp" />
</LinearLayout>
<ImageView
android:id="#+id/ivMan"
android:layout_width="match_parent"
android:layout_height="320dp"
android:background="#drawable/hurray_image"
android:scaleType="center" />
</RelativeLayout>
//some other views
</RelativeLayout>
You need to wait until your views have finished being laid out before you can get their height/width. You can do this using ViewTreeObserver
markLocationBinding.rlView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
//Need to remove the layout listener otherwise animateView() will be called every time view updates
rlView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
animateView();
}
});
You can get measured height and width like below:
view.measure(0,0);
int width=view.getMeasuredWidth();
int height=view.getMeasuredHeight();

Cannot set a click listener for the button that is first outside of the screen (and then animates inside)

I am trying to recreate the edit behavior of iOS list in Android using a RecyclerView. This is the result I want to get (without the delete button):
I don't need the edit button in this context and I am assuming that the little red circle on the left side is always there. When you click the red round button, a rectangle delete button should slide from the right, pushing the row to the left.
What I tried to do was to have a horizontal LinearLayout that is hosting two children. One is a ConstraintLayout that has the main layout of each row and its width is set to match_parent so that it take all the screen width. The other child is the delete button with the width of 130dp which will be outside the screen by default.
Here's the code to the layout file:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipChildren="false">
<LinearLayout
android:id="#+id/root_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:clipChildren="false">
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="9dp"
android:layout_marginTop="9dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageButton
android:id="#+id/remove_circle_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:visibility="visible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="#drawable/ic_remove_circle"
android:background="#null"/>
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="#+id/remove_circle_button"
app:layout_constraintTop_toTopOf="parent"
tools:text="some text" />
</android.support.constraint.ConstraintLayout>
<Button
android:id="#+id/remove_main_button"
style="?android:borderlessButtonStyle"
android:layout_width="130dp"
android:layout_height="match_parent"
android:background="#color/red"
android:stateListAnimator="#null"
android:text="Delete"
android:textColor="#color/white" />
</LinearLayout>
</FrameLayout>
My logic is that when the user clicks the circular red button, the linear layout will animate 130dp to the left making the red button visible while the rest of the row is pushed to the left. Visually it looks good enough for the requirement we have.
Here's the code to the RecyclerView adapter that I wrote:
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {
private Context mContext;
private List<String> mStrings;
private SparseBooleanArray mHasDeleteButtonPressed;
public RecyclerViewAdapter(Context context, List<String> strings) {
this.mContext = context;
this.mStrings = strings;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View row = LayoutInflater.from(mContext).inflate(R.layout.rv_item, parent, false);
return new ViewHolder(row);
}
#Override
public void onBindViewHolder(#NonNull final ViewHolder holder, int position) {
String value = mStrings.get(position);
holder.textView.setText(value);
holder.smallDeleteButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
holder.rootLayout.animate().translationX(
-1 * holder.mainDeleteButton.getWidth())
.setDuration(300)
.start();
mHasDeleteButtonPressed.put(holder.getAdapterPosition(), false);
}
});
holder.mainDeleteButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(mContext, "clicked", Toast.LENGTH_LONG).show();
}
});
}
#Override
public int getItemCount() {
return mStrings.size();
}
static class ViewHolder extends RecyclerView.ViewHolder {
LinearLayout rootLayout;
TextView textView;
ImageButton smallDeleteButton;
Button mainDeleteButton;
ViewHolder(View itemView) {
super(itemView);
rootLayout = (LinearLayout) itemView.findViewById(R.id.root_layout);
textView = (TextView) itemView.findViewById(R.id.time_textView);
smallDeleteButton = (ImageButton) itemView.findViewById(R.id.remove_circle_button);
mainDeleteButton = (Button) itemView.findViewById(R.id.remove_main_button);
}
}
}
The boolean array is to know which button of each row was clicked so that we can animate back the delete button if the user decided they didn't want to delete that row.
Theoretically, with this code the delete button should be pressed and a toast should be shown stating that the button was clicked. However, it appears that the OnClickListener is not being set at all and no code inside the onClick method is being called. My suspicion is that since the button is outside the screen at first, and we are forcing the view not to clip it (using android:clipChildren="false" in the xml file), the setOnClickListener method is not working. Because when I rearrange the layout in a way that the Delete button is inside the screen, the adapter code above will work without any changes.
So how can I fix my problem? I don't want to use any external libraries and I want to do this in a RecyclerView.
Thanks in advance
This is an interesting problem. I can't say what is really going on, but the button that you are sliding onto the screen is being defined outside the bounds of the screen and never really gets onto the screen although it appears to. It's hit rectangle is defined off the screen so the button never gets clicked.
My solution is to first simplify the layout for the RecyclerView items as follows:
activity_main.xml
I have changed a few things such as the button color, etc. for my own ease of use, but they have no bearing on the solution.
<android.support.constraint.ConstraintLayout
android:id="#+id/root_layout"
android:layout_width="match_parent"
android:layout_height="70dp"
android:layout_marginBottom="9dp"
android:layout_marginTop="9dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageButton
android:id="#+id/remove_circle_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:background="#null"
android:visibility="visible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="#drawable/circle_button" />
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:text="some text"
android:textColor="#color/colorPrimary"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="#+id/remove_circle_button"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="#+id/remove_main_button"
style="?android:borderlessButtonStyle"
android:layout_width="130dp"
android:layout_height="0dp"
android:background="#android:color/holo_blue_light"
android:stateListAnimator="#null"
android:text="Delete"
android:textColor="#android:color/white"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
This layout will show the button on screen. In the activity, the layout will be given a specified width that is the width of the screen plus the width of the button. This re-dimensioning of the layout will move the button off-screen. Code can then do a translation to move it back onto the screen.
MainActivity.java
public class MainActivity extends AppCompatActivity {
private View rootLayout;
private View mainDeleteButton;
private View circleButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
rootLayout = findViewById(R.id.root_layout);
mainDeleteButton = findViewById(R.id.remove_main_button);
circleButton = findViewById(R.id.remove_circle_button);
rootLayout.post(new Runnable() {
#Override
public void run() {
rootLayout.getLayoutParams().width = rootLayout.getWidth() + mainDeleteButton.getWidth();
rootLayout.requestLayout();
}
});
circleButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
rootLayout.animate().translationX(
-1 * mainDeleteButton.getWidth())
.setDuration(300)
.start();
}
});
mainDeleteButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "clicked", Toast.LENGTH_SHORT).show();
}
});
}
}
Here is the effect:
Although this example does not involve a RecyclerView, the technique can be applied to a RecyclerView.

Shared element and circular reveal

I would like to make an animation similar to what we can find in the Play Store: https://www.youtube.com/watch?v=B5hBViIzw5Y
I already know how to have shared element between activities and how to make circular reveal, but I'm struggling to do everything in order!
Here is where I am so far, the effect is not so bad, but after the circular reveal (to hide the item) there is a little time before it starts the intent.
My item :
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:card_view="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/card_item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
card_view:cardUseCompatPadding="true"
card_view:cardCornerRadius="2dp">
<RelativeLayout
android:id="#+id/secondary_back"
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="#color/colorPrimary"
android:visibility="gone">
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="200dp"
android:visibility="visible">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true">
<de.hdodenhof.circleimageview.CircleImageView
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/shared_element"
android:transitionName="shared"
android:layout_width="60dp"
android:layout_height="60dp"
android:src="#drawable/shared_color"
android:visibility="gone"/>
</LinearLayout>
</RelativeLayout>
<RelativeLayout
android:id="#+id/primary_back"
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="#drawable/ripple_background_rounded">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="16dp">
<de.hdodenhof.circleimageview.CircleImageView
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/card_image"
android:layout_width="85dp"
android:layout_height="85dp"
app:civ_border_width="3dp"
app:civ_border_color="#color/colorPrimary"/>
</LinearLayout>
<TextView
android:id="#+id/card_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="24sp"
android:textColor="#android:color/black"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:paddingTop="24dp"
android:paddingBottom="24dp"
android:layout_alignParentBottom="true"/>
</RelativeLayout>
</android.support.v7.widget.CardView>
and my function to launch everything :
private void launchAnimation(View v, final int position) {
// previously visible view
final View myView = v.findViewById(R.id.primary_back);
final View background = v.findViewById(R.id.secondary_back);
// my shared element
final CircleImageView sharedElement = (CircleImageView) v.findViewById(R.id.shared_element);
// get the center for the clipping circle
int cx = myView.getWidth() / 2;
int cy = myView.getHeight() / 2;
// get the initial radius for the clipping circle
float initialRadius = (float) Math.hypot(cx, cy);
// create the animation (the final radius is zero)
final Animator anim =
ViewAnimationUtils.createCircularReveal(background, cx, cy, initialRadius, 0);
// fade in background
final Animation fadeIn = new AlphaAnimation(0, 1);
fadeIn.setInterpolator(new DecelerateInterpolator()); //add this
fadeIn.setDuration(200);
final Animation fadeOut = new AlphaAnimation(1, 0);
fadeOut.setInterpolator(new AccelerateInterpolator()); //and this
fadeOut.setDuration(200);
// make the view invisible when the animation is done
anim.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationStart(Animator animation) {
super.onAnimationStart(animation);
}
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
background.setVisibility(View.GONE);
Intent intent = new Intent(context, ResultActivity.class);
// Pass data object in the bundle and populate details activity.
intent.putExtra(ResultActivity.EXTRA_POSITION, position);
ActivityOptionsCompat options = ActivityOptionsCompat.
makeSceneTransitionAnimation(activity, sharedElement, "shared");
activity.startActivity(intent, options.toBundle());
}
});
background.setVisibility(View.VISIBLE);
background.startAnimation(fadeIn);
myView.startAnimation(fadeOut);
fadeIn.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
anim.start();
}
#Override
public void onAnimationEnd(Animation animation) {
myView.setVisibility(View.GONE);
sharedElement.setVisibility(View.VISIBLE);
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
}
If someone knows how to simplify this animation that would be so helpful. Thanks a lot.
For everyone who might want to make this kind of animation, I found an article about this exact transition.
At the end of this article there is the project archive who helped me a lot to make it work.

Slide up/down layout on click

I am looking to slide/up down a nested layout on its parent layout click.
Ie the parent layout will have a hidden child. On click I would like the parents height to animate down (slide down) to fit the child layout. On click again I would like the child to animate up (slide up). Basically just animating the parents height to show/hide the child.
I have found this which looks to work but seems like a lot of code:
http://gmariotti.blogspot.com/2013/09/expand-and-collapse-animation.html
I have seen a lot of things using 'animateLayoutChanges' to animate things however I cannot get that to work.
I have tried this:
<LinearLayout android:id="#+id/parent"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView android:id="#+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<LinearLayout android:id="#+id/child"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
android:animateLayoutChanges="true">
<TextView android:id="#+id/message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Some text to show/hide"/>
</LinearLayout>
</LinearLayout>
Then in code:
LinearLayout parent = (LinearLayout)findViewById(R.id.parent);
parent.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
LinearLayout child = (LinearLayout)findViewById(R.id.child);
child.setVisibility(child.getVisibility() == View.VISIBLE ? View.GONE : View.VISIBLE);
}
});
That sets the visibility of the child view correctly but there is absolutely no animation.
Well, first of all android:animateLayoutChanges effects the child elements. So, obviously, if you are changing the properties of the element itself, it will not be animated.
I think you can accomplish what you are trying to in API 16 by enabling the LayoutTransition.CHANGING animation.
<LinearLayout android:id="#+id/parent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:animateLayoutChanges="true">
<TextView android:id="#+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Title"/>
<TextView android:id="#+id/message"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:text="Some text to show/hide"/>
</LinearLayout>
LinearLayout parent = (LinearLayout)findViewById(R.id.parent);
parent.getLayoutTransition().enableTransitionType(LayoutTransition.CHANGING);
View text = findViewById(R.id.text);
text.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
View message = findViewById(R.id.message);
ViewGroup.LayoutParams params = message.getLayoutParams();
params.height = params.height == 0 ? ViewGroup.LayoutParams.WRAP_CONTENT : 0;
message.setLayoutParams(params);
}
});
Try to use SlidingDrawer
use this code
xml layout sideupdown.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<Button
android:id="#+id/bopen"
android:layout_width="90sp"
android:layout_height="wrap_content"
android:text="open" />
<Button
android:id="#+id/btogg"
android:layout_width="90sp"
android:layout_height="wrap_content"
android:text="change" />
<Button
android:id="#+id/bclose"
android:layout_width="90sp"
android:layout_height="wrap_content"
android:text="close" />
</LinearLayout>
<SlidingDrawer
android:id="#+id/slidingDrawer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:content="#+id/content"
android:handle="#+id/handle" >
<Button
android:id="#+id/handle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Handle" />
<LinearLayout
android:id="#+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<CheckBox
android:id="#+id/chkbok"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="false"
android:text="On/Off" />
</LinearLayout>
</SlidingDrawer>
</FrameLayout>
java class SlideUpDown.java
public class SlideUpDown extends Activity implements OnClickListener,
OnCheckedChangeListener, OnDrawerOpenListener, OnDrawerCloseListener {
Button opn, cloz, chng, hndl;
CheckBox chkbox;
SlidingDrawer sd;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.sideupdown);
refference();
opn.setOnClickListener(this);
cloz.setOnClickListener(this);
chng.setOnClickListener(this);
chkbox.setOnCheckedChangeListener(this);
sd.setOnDrawerOpenListener(this);
sd.setOnDrawerCloseListener(this);
}
private void refference() {
opn = (Button) findViewById(R.id.bopen);
cloz = (Button) findViewById(R.id.bclose);
chng = (Button) findViewById(R.id.btogg);
chkbox = (CheckBox) findViewById(R.id.chkbok);
sd = (SlidingDrawer) findViewById(R.id.slidingDrawer);
hndl = (Button) findViewById(R.id.handle);
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.bopen:
sd.open();
break;
case R.id.bclose:
sd.close();
break;
case R.id.btogg:
sd.toggle();
break;
}
}
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (chkbox.isChecked()) {
sd.lock();
hndl.setEnabled(false);
} else {
sd.unlock();
hndl.setEnabled(true);
}
}
#Override
public void onDrawerOpened() {
}
#Override
public void onDrawerClosed() {
}
#Override
protected void onDestroy() {
super.onDestroy();
}
}
In one of our applications we hide and show a header and footer. We do this by changing the height and visibility of the view.
It looks something like this
ValueAnimator va;
if (show)
va = ValueAnimator.ofInt(0, px);
else
va = ValueAnimator.ofInt(px, 0);
va.setDuration(400);
va.setInterpolator(new DecelerateInterpolator(2));
va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
public void onAnimationUpdate(ValueAnimator animation) {
Integer value = (Integer) animation.getAnimatedValue();
topicNavBar.getLayoutParams().height = value;
topicNavBar.requestLayout();
if (value == 0) {
if (show)
topicNavBar.setVisibility(View.VISIBLE);
else
topicNavBar.setVisibility(View.GONE);
}
if (show && value == px) {
animationInProgress = false;
}
if (!show && value == 0) {
animationInProgress = false;
}
}
});
va.start();
Hope this helps

Android animation starts only after scrolling it's parent view

I'm trying to create an expandable menu item in android, which will look like a button and on button click, button will expand to down with animation. I set an expand animation for the layout which i want to expand when clicked to my view and I have problem with animation. It doesn't start immediately when I clicked the view, and it starts when I scroll-down or scroll-up the container of the view. And if the container is not scrollable, my animation never starts. What am I doing wrong?
Here is my expand method, onClick method and the layout xml file for my custom view which will do this things:
expand:
public void expand(final View v) {
try {
Method m = v.getClass().getDeclaredMethod("onMeasure", int.class, int.class);
m.setAccessible(true);
m.invoke(v,
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
MeasureSpec.makeMeasureSpec(((View)v.getParent()).getMeasuredWidth(), MeasureSpec.AT_MOST)
);
} catch (Exception e) {
Log.e(TAG , "Caught an exception!", e);
}
final int initialHeight = v.getMeasuredHeight();
Log.d("test", "initialHeight="+initialHeight);
v.getLayoutParams().height = 0;
v.setVisibility(View.VISIBLE);
Animation a = new Animation() {
#Override
protected void applyTransformation(float interpolatedTime,
Transformation t) {
final int newHeight = (int) (initialHeight * interpolatedTime);
v.getLayoutParams().height = newHeight;
v.requestLayout();
}
#Override
public boolean willChangeBounds() {
return true;
}
};
a.setDuration(1000);
a.setInterpolator(AnimationUtils.loadInterpolator(context,
android.R.anim.accelerate_decelerate_interpolator));
v.startAnimation(a);
isExpanded = !isExpanded;
}
onClick:
public void onClick(View v) {
if (!isExpanded) {
expand(subButtonsLayout);
} else {
collapse(subButtonsLayout);
}
}
Layout xml for custom menu item view:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:mtx="http://schemas.android.com/apk/res/com.matriksdata.trademaster"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:gravity="center_horizontal">
<LinearLayout
android:id="#+id/xExpandableMenuButtonTop"
android:background="#drawable/opened_menu_bg_top"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</LinearLayout>
<LinearLayout
android:background="#drawable/opened_menu_bg_center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center_vertical">
<LinearLayout
android:id="#+id/xExpandableMenuButtonTitle"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical">
<TextView
android:id="#+id/xExpandableMenuButtonText"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:textAppearance="#style/expandable_menu_button_textstyle"
android:text="Button Text">
</TextView>
<ImageView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="6"
android:src="#drawable/menu_button_down_arrow">
</ImageView>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="#+id/xExpandableMenuButtonSubButtonsLayout"
android:background="#drawable/opened_menu_bg_center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center_vertical"
android:visibility="gone">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical">
<com.myproject.control.XSubMenuButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
mtx:XSubMenuButtonText="SubMenu1">
</ccom.myproject.control.XSubMenuButton>
<com.myproject.control.XSubMenuButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
mtx:XSubMenuButtonText="SubMenu2">
</com.myproject.control.XSubMenuButton>
<com.myproject.control.XSubMenuButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
mtx:XSubMenuButtonText="SubMenu3">
</com.myproject.control.XSubMenuButton>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="#+id/xExpandableMenuButtonBottom"
android:background="#drawable/opened_menu_bg_bottom"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</LinearLayout>
</LinearLayout>
If you haven't solved your problem or if anyone else comes across this problem, here is a quick solution. Invalidate your parent view on each click (in the onClick method). This should work regardless of if the parent is scrollable or not.
That is, your code will be something like:
public void onClick(View v) {
if (!isExpanded) {
expand(subButtonsLayout);
} else {
collapse(subButtonsLayout);
}
rootView.invalidate();
}
To anyone who might face this again.
If your view, the one that you are animating is in the gone state, then in that case, before starting the animation, set Visiblity to invisible. And it will work in the first go.
Source from here.
I had a view that I declared at the end of my layout to keep its Z index above its siblings. I had to touch the page to make the animation work.
So I set the Z index again through Java and it worked.
view.bringToFront();
Well, I fixed the problem using only 2 lines.
scroll.setFocusableInTouchMode(true);
scroll.requestFocus();
animation.Start();//Start anim
Good luck
"If the container is not scrollable, the animation never starts" --> Have a look at my similar problem, Scrollview doesn't swipe when it's too short to scroll. I figured out in my case it's a touch bug in Android 2.1 and under.

Categories

Resources