I have four linear layouts in my screen.
The first layout contain a textview.
I'm trying to move my textView to the the fourth layout of the right with a translate animation.
But when i do that the text view move behind the other layout and if i move my layout from the fourth layout of the right to the first at the left it's ok.
Im my xml i have put : in all layouts
android:clipChildren="false"
image
Can you help me ?
Thank you
Use setZAdjustment to put your View in front of the other Views.
http://developer.android.com/reference/android/view/animation/Animation.html#setZAdjustment%28int%29
Pre-Kitkat :
yourLayout.bringToFront();
((View)yourLayout.getParent()).requestLayout();
((View)yourLayout.getParent()).invalidate();
KitKat :
yourLayout.bringToFront();
Android linear layout construction starts from first element from the beginning. So any element defined first will be created and then rest, so no matter what you do, you cannot achieve with linear layout. Try with relative layout
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="#+id/testAnimTranslate"
android:layout_width="wrap_content"
android:layout_height="80dp"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:gravity="center_vertical"
android:orientation="horizontal" >
<LinearLayout
android:layout_width="30dp"
android:layout_height="70dp"
android:background="#0000dd"
android:orientation="vertical" />
<LinearLayout
android:layout_width="30dp"
android:layout_height="70dp"
android:layout_alignParentBottom="true"
android:background="#0dd0dd"
android:orientation="vertical" />
<LinearLayout
android:layout_width="30dp"
android:layout_height="70dp"
android:layout_alignParentBottom="true"
android:background="#ddd0dd"
android:orientation="vertical" />
<LinearLayout
android:layout_width="30dp"
android:layout_height="70dp"
android:layout_alignParentBottom="true"
android:background="#44d0dd"
android:orientation="vertical" />
</LinearLayout>
<TextView
android:id="#+id/textAnimate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="#id/testAnimTranslate"
android:layout_alignTop="#id/testAnimTranslate"
android:layout_toLeftOf="#id/testAnimTranslate"
android:gravity="center"
android:background="#00000000"
android:text="qweqwew" />
</RelativeLayout>
Define your translate anim in anim folder or programatically. make sure to add
LinearInterpolator
setFillAfter to true
and start the anim
I think you create the view in the code, so you should add setClipChildren(false)
in your constructor too.
Look at the docs:
ZORDER_TOP: Requests that the content being animated be forced on top of all other content for the duration of the animation.
Please check that setFillAfter(true) does not match this usage.
Does it help?
The main problem with what you are trying to do, is that you want to draw a View outside of its parent. It goes behind the other LinearLayouts because they are drawn after the LinearLayout parent of the View. Even if it is brought to the front, it seems that only relates to children within a single parent?
If you look at how Fragment animations work, you need to recreate the Fragment to translate a from one Frame into another. You also need two separate animations.
BlackBeard's solution will work because it makes the TextView a child of the outermost parent and declares it last. This means the TextView is drawn after everything else and therefore will be drawn on top of everything else.
This doesn't achieve what I think you are trying to do. If you want the TextView to belong to its destination LinearLayout after the animation you'll need to recreate the TextView and add it to the LinearLayout in the correct position in the hierarchy. You'll also need a second animation to move the new TextView into its position.
If done properly the animations should overlay each other perfectly and if in a LinearLayout one or the other of the animated Views will pass on top of everything else.
activity_main.xml
<LinearLayout
android:id="#+id/frame"
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:clipChildren="false"
android:orientation="horizontal"
tools:context=".MainActivity">
<LinearLayout
android:id="#+id/layout1"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#FFAABBCC"
android:orientation="vertical">
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="24sp"
android:text="I'm some text"/>
</LinearLayout>
<LinearLayout
android:id="#+id/layout2"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#FFBBCCAA"
android:orientation="vertical">
</LinearLayout>
<LinearLayout
android:id="#+id/layout3"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#FFCCAABB"
android:orientation="vertical">
</LinearLayout>
<LinearLayout
android:id="#+id/layout4"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#FFBBAACC"
android:orientation="vertical">
</LinearLayout>
</LinearLayout>
MainActivity.java
private LinearLayout mLayout1;
private LinearLayout mLayout2;
private LinearLayout mLayout3;
private LinearLayout mLayout4;
private TextView mTextView;
private View.OnTouchListener mOnTouchListener;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mLayout1 = (LinearLayout) findViewById(R.id.layout1);
mLayout2 = (LinearLayout) findViewById(R.id.layout2);
mLayout3 = (LinearLayout) findViewById(R.id.layout3);
mLayout4 = (LinearLayout) findViewById(R.id.layout4);
mTextView = (TextView) findViewById(R.id.textView);
mOnTouchListener = new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
// simple trigger to start the animation.
startAnimation();
mTextView.setOnTouchListener(null);
return true;
}
};
mTextView.setOnTouchListener(mOnTouchListener);
}
private void startAnimation() {
final LinearLayout origin = (LinearLayout) mTextView.getParent();
LinearLayout destination = null;
// I'm not sure what kind of behaviour you want. This just randomises the destination.
do {
switch (new Random().nextInt(4)) {
case 0:
destination = mLayout1;
break;
case 1:
destination = mLayout2;
break;
case 2:
destination = mLayout3;
break;
case 3:
destination = mLayout4;
break;
default:
}
// if destination == origin or is null, try again.
} while (destination == origin || destination == null);
// Create another TextView and initialise it to match mTextView
final TextView textViewNew = new TextView(this);
textViewNew.setText(mTextView.getText());
textViewNew.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextView.getTextSize());
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
textViewNew.setLayoutParams(params);
textViewNew.setOnTouchListener(mOnTouchListener);
// Add the new TextView to the destination LinearLayout
destination.addView(textViewNew);
// Create animations based on origin and destination LinearLayouts
ObjectAnimator outAnimator = getOutAnimator(origin, destination);
// The in animator also requires a reference to the new TextView
ObjectAnimator inAnimator = getInAnimator(textViewNew, origin, destination);
// All animators must be created before any are started because they are calculated
// using values that are modified by the animation itself.
outAnimator.start();
inAnimator.start();
// Add a listener to update mTextView reference to the new TextView when complete.
inAnimator.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
}
#Override
public void onAnimationEnd(Animator animation) {
origin.removeView(mTextView);
mTextView = textViewNew;
}
#Override
public void onAnimationCancel(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
}
});
}
/**
* This method creates an ObjectAnimator to move the existing TextView out of its parent
* towards its destination
*/
private ObjectAnimator getOutAnimator(View origin, View destination) {
// Calculate the difference between x of destination and of origin
float layoutDifferenceX = destination.getX() - origin.getX();
// initialX is simply mTextView.getX()
// the distance moved == layoutDifferenceX
float finalX = mTextView.getX() + layoutDifferenceX;
ObjectAnimator animator = ObjectAnimator.ofFloat(mTextView, "x",
mTextView.getX(), finalX);
animator.setInterpolator(new AccelerateDecelerateInterpolator());
animator.setDuration(500);
return animator;
}
/**
* This method creates an ObjectAnimator to move the new TextView from the initial position
* of mTextView, relative to the new TextView's parent, to its destination.
*/
private ObjectAnimator getInAnimator(View newView, View origin, View destination) {
// Calculate the difference between x of destination and of origin
float layoutDifferenceX = destination.getX() - origin.getX();
// initialX relative to destination
float initialX = mTextView.getX() - layoutDifferenceX;
// finalX relative to destination == initialX relative to origin
float finalX = mTextView.getX();
ObjectAnimator animator = ObjectAnimator.ofFloat(newView, "x",
initialX, finalX);
animator.setInterpolator(new AccelerateDecelerateInterpolator());
animator.setDuration(500);
return animator;
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
EDIT: You could also declare the TextView in xml and inflate it to get rid of all the code initialising it.
Related
I'm working on getting a animation to work. I'm moving a search bar from the middle of the screen to the top of the screen. The animation works fine, but once it's moved I can't interact with anything. I've updated the position but can't interact with it regardless. Here's what I've got so far:
private void moveSearchToTop()
{
FrameLayout root = (FrameLayout) findViewById( R.id.rootLayout );
DisplayMetrics dm = new DisplayMetrics();
this.getWindowManager().getDefaultDisplay().getMetrics( dm );
statusBarOffset = dm.heightPixels - root.getMeasuredHeight();
int originalPos[] = new int[2];
mSearchBar.getLocationOnScreen( originalPos );
search_top = statusBarOffset - originalPos[1];
TranslateAnimation anim = new TranslateAnimation( 0, 0, 0, search_top);
anim.setDuration(500);
anim.setFillAfter(true);
anim.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
mSearchBar.layout(0, search_top, 0, mSearchBar.getHeight() + search_top);
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
mSearchBar.startAnimation(anim);
}
and here's what the view looks like in xml:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:id="#+id/search_bar"
android:background="#android:drawable/dialog_holo_light_frame">
<ImageView
android:id="#+id/search_icon"
android:layout_width="wrap_content"
android:onClick="onSearchClick"
android:layout_height="25dp"
android:layout_gravity="center_vertical"
android:src="#drawable/search"/>
<EditText
android:id="#+id/search_field"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:singleLine="true"
android:hint="Search"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="25dp"
android:layout_gravity="center_vertical"
android:src="#drawable/camera"/>
</LinearLayout>
Do I need to update the position of all of the child elements too? Thanks for a push in the right position.
No, you won't need to modify the child views. They will go where the search bar goes.
It looks to me like you are using your search_top variable both as a delta (for the TranslateAnimation constructor) and as a position within its parent (in the call to layout). It's really a delta, so the call to layout is incorrect.
Is the parent of your searchBar the "root" FrameLayout? If so, then you just want to use 0 as the new y coordinate in the call to layout. Also, you are using 0 as the right coordinate, which means that it has no width after the animation. This call would position your search bar at the upper-left edge of its parent, and maintain its current width and height:
mSearchBar.layout(0, 0, mSearchBar.getWidth(), mSearchBar.getHeight());
I also would recommend that you do not use screen position. It's safer to just set the position of views within parent views. For example, if the search bar's parent really is root, then you could get the delta with:
search_top = - mSearchBar.getTop();
I have a simple button in my layout. Setting leftMargin to the view actually showing different results.
my_layout.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="#+id/left_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="hello pandora"/>
</RelativeLayout>
In my activity, I'm setting the leftMargin property to the Button.
Button leftBtn = (Button) findViewById(R.id.left_btn);
LayoutParams params = (LayoutParams) leftBtn.getLayoutParams();
params.leftMargin = 550;
If I set leftMargin as negative value or 0, its working fine, but If I set the value greater than the width of screen, it just resizing/compressing the button. I am expecting the button to go out of bounds like negative value.
I am expecting the button in the 3rd image to go out of bounds like the button in 1st image.
Please don't say to set the button layout_alignParentRight="true" in layout and rightMargin = -50in activity(this works) because I want to move the button from left to right.
I assume assigning a specific width larger than the screen size (eg. 1000 dp) to the parent RelativeLayout should solve your problem.
Also why do you want to make out-of-screen UI elements? What is the desired behaviour? Perhaps a transition animation would be better?
EDIT
I've tried the animation + storing the measured width of the Button. It seems to work.
Can you try this on GB?
MainActivity.java
public class MainActivity extends Activity {
final Context context = this;
Button mButton;
int mButtonWidth; // Measured width of Button
int amountToMove; // Amount to move the button in the x direction
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
amountToMove = 600;
mButton = (Button) findViewById(R.id.button);
// Measure Button's width
mButton.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
mButtonWidth = mButton.getMeasuredWidth();
// Simple onClick listener showing a Toast
mButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(context,"Hello Pandora clicked!",Toast.LENGTH_SHORT).show();
}
});
// Onclick listener for the other button
Button toggle = (Button) findViewById(R.id.toggle);
toggle.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Animate the other button
TranslateAnimation a = new TranslateAnimation(0, amountToMove, 0, 0);
a.setDuration(1000);
// Finalize movement when animation ends
a.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationEnd(Animation animation) {
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)mButton.getLayoutParams();
// Restore measured width and change left margin
lp.width = mButtonWidth;
lp.leftMargin = lp.leftMargin + amountToMove;
mButton.setLayoutParams(lp);
amountToMove = -amountToMove;
}
#Override
public void onAnimationStart(Animation animation) { /* Do nothing */ }
#Override
public void onAnimationRepeat(Animation animation) { /* Do nothing */ }
});
mButton.startAnimation(a);
}
});
}
}
activity_main.xml
<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"
tools:context=".MainActivity">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello Pandora"
android:id="#+id/button" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Move the other button"
android:id="#+id/toggle"/>
</LinearLayout>
EDIT 2
It works on a GB Emulator too (the Button gets clipped, is clickable).
u can use max line=1 to show complete text in one line on button when you use leftMargin = 550;
try this
<Button
android:id="#+id/left_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:maxLines="1"
android:text="hello pandora"/>
Hello Edit your button property like this,
android:layout_gravity="center_horizontal"
android:singleLine="true"
and change parent layout to frameLayout
I am new in Android animation and my requirement is to translate a view from one layout to layout in a single xml file on click of that view.
Scenario:
Suppose I click a button, present on the top of the header in a xml file,and it should move/translate downwards (it should give an impact that it lies on the other layout downwards to header), and also I want that when the user clicks on the same again, it should now move to its original position.
Here I am explaining with my xml file:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/app_bg"
android:orientation="vertical" >
<RelativeLayout
android:id="#+id/top"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#drawable/header"
android:paddingLeft="10dp"
android:paddingRight="10dp" >
<Button
android:id="#+id/btnSearchHeader"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_centerInParent="true"
android:background="#drawable/search_icon" />
</RelativeLayout>
<RelativeLayout
android:id="#+id/bottom"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#color/app_transparent"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:layout_marginTop="10dp"
android:visibility="visible" >
<Button
android:id="#+id/btnMenu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_marginRight="5dp"
android:text="ABC" />
<Button
android:id="#+id/btnSearchSelected"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toRightOf="#+id/btnMenu"
android:text="CDE" />
</RelativeLayout>
</LinearLayout>
MORE PRECISE REQUIREMENT SPECIFICATION (Kindly read carefully:)
Here I have two sub inner layouts:-
Top Layout - id-> top
Bottom Layout- id -> bottom
Now a view (Button -> btnSearchHeader) is lying in my top layout and I want to animate the same to the bottom layout (it should give an impact that it is translated with a translate animation to the bottom layout) on click of that button and when the user clicks on that button, it should again translate back to its original position with a translate animation .. i.e it should show back in the top layout
I have no idea how to give these impacts using translate animations, however i just have a basic translate animation knowledge which is insufficient for me to work upon my requirement.
Any type of related help is appreciable.
Thanks
Have you tried something simple like the following?
final int topHeight = findViewById(R.id.top).getHeight();
final int bottomHeight = findViewById(R.id.bottom).getHeight();
final View button = findViewById(R.id.btnSearchHeader);
final ObjectAnimator moveDownAnim = ObjectAnimator.ofFloat(button, "translationY", 0.F, topHeight + bottomHeight / 2 - button.getHeight() / 2);
final ObjectAnimator moveUpAnim = ObjectAnimator.ofFloat(button, "translationY", topHeight + bottomHeight / 2 - button.getHeight() / 2, 0.F);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (0.F == v.getTranslationY())
moveDownAnim.start();
else
moveUpAnim.start();
}
});
If you actually need the button view to change parents, you can use AnimatorListener to achieve this at the end of each animation. Something like:
moveDownAnim.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationEnd(Animator animation) {
((ViewGroup)findViewById(R.id.top)).removeView(button);
((ViewGroup)findViewById(R.id.bottom)).addView(button);
((RelativeLayout)button.getLayoutParams()).addRule(RelativeLayout.CENTER_IN_PARENT);
button.setTranslationY(0.F); // Since it is now positioned in the new layout, no need for translation.
}
#Override
public void onAnimationCancel(Animator animation) { /* NOP */ }
#Override
public void onAnimationRepeat(Animator animation) { /* NOP */ }
#Override
public void onAnimationStart(Animator animation) { /* NOP */ }
});
(And analogous listener for the moveUpAnim.)
However, I doubt you need to actually do this to achieve the visual effect you want. But if you do this part, you will probably also need to set a fixed height for your top view as opposed to wrap_content. (Otherwise, if a layout pass happens while the button has been moved to the bottom view, the top layout's height might go to 0 if there's nothing else in it.) Easiest would be to just do this directly in the xml layout file. However, if you want to "do it on the fly", you can change the layout's height in the onAnimationEnd() method using something like:
#Override
public void onAnimationEnd(Animator animation) {
final ViewGroup topLayout = findViewById(R.id.top);
topLayout.getLayoutParams().height = topLayout.getHeight(); // Keep it the same height...
topLayout.removeView(button);
((ViewGroup)findViewById(R.id.bottom)).addView(button);
((RelativeLayout)button.getLayoutParams()).addRule(RelativeLayout.CENTER_IN_PARENT);
button.setTranslationY(0.F); // Since it is now positioned in the new layout, no need for translation.
}
I have researched the questions thoroughly, but could not yet find the answer. Also, my excuses for my poor english since I am not a native speaker.
The problem: in my android layout we have a status_text with a listview below the status_text. When the status_text is touched, we animate a 'move down' on the status_text and listview so that only the first of the listview row is still on screen. The listview is now still usable.
When the status_text is touched again, we move the status_text and listview up so that the listview uses half of the screen.
The problem we are facing is that during the 'move up' only the first row is animated. After the 'move up' the other rows suddenly appear.
What we would like to have is a 'move up' where the previously hidden rows slide onto the screen.
The layout:
We are using this layout (slightly simplified to focus on the problem at hand):
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/fragment_declareren_choose_verzekerden"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<!-- Dummy anchor to put top of listview in the middle of the screen -->
<RelativeLayout
android:id="#+id/anchor"
style="#style/anchor_status_container"
android:layout_centerVertical="true" >
</RelativeLayout>
<!-- Example image -->
<ImageView
android:id="#+id/my_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="#id/footer"
android:adjustViewBounds="true"
android:contentDescription="#string/image_description"
android:scaleType="centerCrop"
android:src="#drawable/empty" />
<!-- Clickable text which moves up and down on click -->
<RelativeLayout
android:id="#+id/status_container"
style="#style/status_container"
android:layout_alignTop="#id/anchor"
android:background="#color/white" >
<TextView
android:id="#+id/status_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginRight="#dimen/spacing_sml"
android:layout_alignTop="#id/status_container" />
</RelativeLayout>
<!-- Listview which moves up and down with the status_container -->
<RelativeLayout
android:id="#+id/listView_container"
style="#style/padding_content_horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#id/status_container"
android:background="#color/white" >
<ListView
android:id="#+id/mylistView"
style="#style/myListviewStyle"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
android:divider="#null"
android:dividerHeight="0dp" />
</RelativeLayout>
<!-- Footer with buttons -->
<RelativeLayout
android:id="#+id/footer_button_container"
style="#style/footer"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<Button
android:id="#+id/button_again"
style="#style/btn_secondary"
android:layout_width="wrap_content"
android:layout_alignParentLeft="true"
android:text="#string/opnieuw"
android:visibility="gone" />
<Button
android:id="#+id/button_next"
style="#style/btn_primary"
android:layout_width="wrap_content" />
</RelativeLayout>
</RelativeLayout>
And the code (again a bit simplified to show only the problem at hand. Some fade-in/out and rotations are removed):
// The code
#Override
public void onClick(View view)
{
int viewId = view.getId();
if (viewId == R.id.status_container)
{
// Someone clicked the text, move the statusbar (and so the listview) up or down
if (this.viewIsInUpperPosition)
{
startStatusAnimation();
}
}
}
private void startStatusAnimation()
{
if (animationIsRunning)
{
return;
}
setAnimationIsRunning(animValues.START);
// 0. Initialisation
final View statusContainer = (View) getView().findViewById(R.id.status_container);
final View listContainer = (View) getView().findViewById(R.id.listView_container);
final ListView listView = (ListView) getView().findViewById(R.id.myListView);
final View footerButtonContainer = (View) getView().findViewById(R.id.footer_button_container);
// 1. Calculate distance for animation
if (toggleViewDistance == 0)
{
int listViewContainerHeight = listContainer.getHeight();
int footerHeight = footerButtonContainer.getHeight();
int spaceForListView = listViewContainerHeight - footerHeight;
toggleViewDistance = spaceForListView;
}
// 2. Decide if the movement is up or down
float translationDistance = (viewIsInUpperPosition) ? toggleViewDistance : 0 - toggleViewDistance;
// 3. Create the animation
TranslateAnimation yMove = new TranslateAnimation(0, 0, 0, translationDistance);
yMove.setDuration(animValues.ANIMATION_Y_DURATION);
yMove.setInterpolator(new AccelerateDecelerateInterpolator());
// Do here something with scaling and rotating of other objects, not relevant for the question on StackOverflow
// 4. Actions after animation
yMove.setAnimationListener(new AnimationListener()
{
#Override
public void onAnimationEnd(Animation arg0)
{
// Fade de listView in als je van onderen naar boven animeert
if (!viewIsInUpperPosition)
{
// Do some fading, outside scope of question
}
// Create layout after the animation
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) statusContainer.getLayoutParams();
if (viewIsInUpperPosition)
{
// View was previously in upper position, now put the statusbar aligned with the footer
params = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.ABOVE, footerButtonContainer.getId());
}
else
{
// View was previously in bottom position, so put it under the anchor
params = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.ALIGN_TOP, R.id.anchor);
}
}
statusContainer.setLayoutParams(params); // Set the new layout params
viewIsInUpperPosition = !viewIsInUpperPosition;
setAnimationIsRunning(animValues.END);
}
#Override
public void onAnimationRepeat(Animation arg0)
{
// Empty
}
#Override
public void onAnimationStart(Animation arg0)
{
// empty
}
});
// 5. Start the animation
statusContainer.startAnimation(yMove);
listContainer.startAnimation(yMove);
}
Any advice on how to have the rows of the listview 'slide in' on the screen? Much appreciated!
I figured it out. So I am answering my own question in case someone stumbles upon this question.
What needs to be done is that the listview is drawn off-screen. This can be forced by calling the measure- and layout-methods with the off-screen coordinates of the listview.
This fixed it for my code:
// 5a. Draw the listview off-screen
if (translationDistance < 0)
{
// Do this only when the listview is sliding up, e.g. sliding the window in.
int listViewContainerVerticalPos = listContainer.getTop(); // De positie van de listview
// The required height of the listview
int listContainerHeight = (int) Math.abs(translationDistance) + statusContainer.getHeight();
int measureWidth = View.MeasureSpec.makeMeasureSpec(listContainer.getWidth(), View.MeasureSpec.EXACTLY);
int measureHight = View.MeasureSpec.makeMeasureSpec(listContainerHeight, View.MeasureSpec.EXACTLY);
listContainer.measure(measureWidth, measureHight);
listContainer.layout(0, listContainerVerticalPos, listContainer.getMeasuredWidth(), listContainerVerticalPos
+ listContainerHeight);
}
I have a layout with a top bar container and a content container. When clicking on a button in the top bar, a vertical menu is displayed using an animation. My minSdkVersion is 9.
This works well when I start the app and I still haven't clicked a menu button (i.e. the content fragment has not changed), but as soon as I have clicked an option (and then replace the fragment in the content_container), the vertical menu behaves erratically. The click event of the menu btn is properly triggered, but the vertical menu is not always shown (but sometimes it is...). However, when I click the button and then touch the screen, the animation (show or hide the menu) starts.
I guess it has something to do with the vertical menu overlapping the content fragment, and then replacing the content fragment modify it in some way, but I can't find any solution.
Anybody can help?
top bar fragment
#Override
public void onActivityCreated (Bundle savedInstanceState){
super.onActivityCreated(savedInstanceState);
toggleMenu(0);
Button btn_menu = (Button) getView().findViewById(R.id.btn_menu);
btn_menu.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mVerticalMenu.setVisibility(View.VISIBLE);
toggleMenu(1000);
}
});
}
private void toggleMenu(int duration){
if(mMenuIsOpen){
TranslateAnimation anim1 = new TranslateAnimation(0,0,0,-(mHeight-mMenuVerticalOffset));
anim1.setFillAfter(true);
anim1.setDuration(duration);
mVerticalMenu.setAnimation(anim1);
AlphaAnimation anim2 = new AlphaAnimation(0.7f, 0.0f);
anim2.setFillAfter(true);
anim2.setDuration(duration);
menu_option_01.setOnClickListener(null);
menu_option_02.setOnClickListener(null);
menu_option_03.setOnClickListener(null);
mMenuIsOpen = false;
}
else{
TranslateAnimation anim1 = new TranslateAnimation(0,0,-(mHeight-mMenuVerticalOffset),0);
anim1.setFillAfter(true);
anim1.setDuration(duration);
mVerticalMenu.setAnimation(anim1);
AlphaAnimation anim2 = new AlphaAnimation(0.0f, 0.7f);
anim2.setFillAfter(true);
anim2.setDuration(duration);
menu_option_01.setOnClickListener(mButtonClickListener);
menu_option_02.setOnClickListener(mButtonClickListener);
menu_option_03.setOnClickListener(mButtonClickListener);
mMenuIsOpen = true;
}
}
private OnClickListener mButtonClickListener = new OnClickListener()
{
public void onClick(View v)
{
toggleMenu(1000);
if(!v.isSelected()){
FragmentTransaction fragmentTransaction = getActivity().getSupportFragmentManager().beginTransaction();
switch(v.getId()){
case R.id.menu_option_01:
// replace content_container by fragment 1
break;
case R.id.btn_02:
// replace content_container by fragment 2
break;
case R.id.btn_03:
// replace content_container by fragment 3
break;
}
}
}
};
private OnClickListener mBgClickListener = new OnClickListener()
{
public void onClick(View v)
{
toggleMenu(1000);
}
};
Main layout
<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" >
<FrameLayout
android:id="#+id/content_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="44dp" />
<FrameLayout
android:id="#+id/top_bar_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false" />
</RelativeLayout>
top bar layout
<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:background="#00000000" >
<LinearLayout
android:id="#+id/vertical_menu"
android:layout_width="50dp"
android:layout_height="match_parent"
android:layout_marginTop="44dp"
android:background="#ffffff"
android:orientation="vertical"
android:visibility="gone" >
<!-- menu layout -->
</LinearLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="44dp"
android:background="#ffffff" >
<Button
android:id="#+id/btn_menu"
android:layout_width="50dp"
android:layout_height="44dp"
android:background="#drawable/menubtn" />
<ImageView
android:layout_width="130dp"
android:layout_height="44dp"
android:src="#drawable/logo"
android:layout_alignParentRight="true" />
</RelativeLayout>
</RelativeLayout>
At the end of my Toggle method, I invalidate the root view:
rootView.invalidate();
and now it works. Not quite clear why I must do that though...
I know there is already an accepted answer for this but I had a similar problem and the answer didnt help.
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();