Why doesn't the textView become invisible?
Here is my layout xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="#+id/tvRotate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Rotate Me"
/>
</LinearLayout>
..and here is my activity:
public class RotateMeActivity extends Activity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView tvRotate = (TextView) findViewById(R.id.tvRotate);
RotateAnimation r = new RotateAnimation(0, 180, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
r.setDuration(0);
r.setFillAfter(true);
tvRotate.startAnimation(r);
tvRotate.setVisibility(View.INVISIBLE);
}
}
My goal is to rotate a view and then be able to hide and show it in code by setting setVisibility. The following works, but setRotation is available only in API Level 11. I need a way to do it in API Level 10.
tvRotate.setRotation(180);//instead of the RotateAnimation, only works in API Level 11
tvRotate.setVisibility(View.INVISIBLE);
For me calling clearAnimation of the View fixed the problem. In my case I wanted to set the View back to its original position after doing a translation with fillAfter set to true.
All the animations (before android 3.0) are actually applied to a bitmap which is a snapshot of your view instead of on your original view. When you are setting the fill after to true this actually means that the bitmap will continue to be displayed on the screen instead of your view. This is the reason why the visibility won't change upon using setVisibility and also the reason why your view will not be receiving touch events in its new (rotated) bounds. (but since you're rotating on 180 degrees that's not an issue).
Another way to work around this is to wrap your animated view in another view and set the visibility of that wrapper view.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<FrameLayout
android:id="#+id/animationHoldingFrame"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="#+id/tvRotate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Rotate Me"
/>
</FrameLayout>
</LinearLayout>
And the code then becomes this:
TextView tvRotate = (TextView) findViewById(R.id.tvRotate);
FrameLayout animationContainer = (FrameLayout)findViewById(R.id.animationHoldingFrame)
RotateAnimation r = new RotateAnimation(0, 180, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
r.setDuration(0);
r.setFillAfter(true);
tvRotate.startAnimation(r);
animationContainer.setVisibility(View.INVISIBLE);
Use this before setVisibility after animation is completed:
anim.reverse();
anim.removeAllListeners();
anim.end();
anim.cancel();
where anim is your ObjectAnimator
but if you are using the Animation class, then just do:
view.clearAnimation();
on the view upon which the animation was performed
I ended up requiring API Level 11 and using setRotation to accomplish this. This seems like a pretty simple requirement that can't be done pre-Honeycomb though. All i wanted to do was rotate a button and then hide/show it.
I came up with a workaround for this: basically right before you call setVisibility(View.GONE), do an animation with duration=0 setFillAfter(false) and have the angle from/to set to the current angle of rotation.
This will clear the setFillAfter bitmap and allow the view to be gone.
Related
I have the view with layout below.
What I want is moving View B to the position of View A and at the same time move RelativeLayout C up with the same height of View B. The two actions will be done with the animations. Like the picture shown below.
I am using ObjectAnimation to implement this feature, but when I am using the
float viewBY = viewB.getTranslationY();
ObjectAnimator viewBMoveUp
= ObjectAnimator.ofFloat(viewB, "translationY",
viewBY, viewBY - viewB.getHeight());
float layoutCCurrentY = layoutC.getY();
ObjectAnimator layoutCMoveUp
= ObjectAnimator.ofFloat(layoutC, "Y",
layoutCCurrentY, layoutCCurrentY - viewB.getHeight());
AnimatorSet animSet = new AnimatorSet();
animSet.play(viewBMoveUp).with(layoutCMoveUp);
animSet.setDuration(150);
animSet.start();
I find the LayoutC's bottom is also up with viewB.getHeight(), which is not I expected. Like the picture below:
So anybody can help about this?
One simpler way to achieve the expected result is to use animateLayoutChanges attribute in the parent layout.
<!-- Defines whether changes in layout (caused by adding and removing items) should cause
a LayoutTransition to run. When this flag is set to true, a default LayoutTransition object
will be set on the ViewGroup container and default animations will run when these layout
changes occur.-->
<attr name="animateLayoutChanges" format="boolean" />
With this, you don't need to manually animate each movement.
When you set viewA visibility to View.GONE, the parent layout will fade out viewA and translate position of viewB and layoutC.
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true">
<View
android:id="#+id/viewA"
android:layout_width="match_parent"
android:layout_height="60dp" />
<View
android:id="#+id/viewB"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_below="#+id/viewA" />
<RelativeLayout
android:id="#+id/layoutC"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/viewB"
android:layout_alignParentBottom="true">
</RelativeLayout>
</RelativeLayout>
I have an existing layout that I am setting my current activity to. However, I want to draw a line (horizontal) and move it down in slow motion. Most articles talk about creating custom view and doing
setContentView(myView) .
How ever I dont want to set my activity view to only this view. I already did setContentView(R.layout.main). And I just want to draw the line on top of moving contents.
Something like drawLine(fromX, fromY, toX, toY) and then add a loop while increasing Y to show it in motion.
I hope I am clear. Please point me to the right direction.
Thank you
create a view and then animate it.
<View
android:id="+#id/ivHorizontalLine"
android:layout_width="match_parent"
android:layout_height="1px"
android:background="#000000" />
change the height of the view to match how thick you want the line to be. and the background color for the color of the line.
TranslateAnimation horizontalLineAnimation = new TranslateAnimation(0, 0, YstartPoint, YendPoint);
horizontalLineAnimation.setDuration(duration);
ivHorizontalLine.startAnimation(horizontalLineAnimation);
change YstartPoint and YendPoint to match where you want the line to move from and to. and the duration to match how fast you want the line to move.
The best way to do this is create a View that takes up the entire container that you would like to paint on top of. No background is necessary, as it is only to be used to create a canvas on it. An example would be like this:
<FrameLayout 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"
>
<com.packagename.PaintView
android:id="#+id/paintView"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</FrameLayout>
And PaintView would be a public class PaintView extends View
I'm trying to animate a view and hide it after some DP's were scrolled and i made everything fine, but the problem is that it will flick horribly when you are scrolling slowly before or after the Y value that is supposed to trigger the animation.
I think the flick is because i have to set its visibility to Gone and update the other view as match_parent, it won't work with just the TraslationY:
view.animate()
.translationY(-view.getBottom())
.alpha(0)
.setDuration(HEADER_HIDE_ANIM_DURATION)
.setInterpolator(new DecelerateInterpolator());
I tried to set the layout to relative and View 2 as match_parent to see if i could avoid the visibility change but it didn't work...
I have implemented all required code from Google I/O 2014 BaseActivity.java file:
https://github.com/google/iosched/blob/master/android/src/main/java/com/google/samples/apps/iosched/ui/BaseActivity.java#L17
And the animation works... but i assume that, as my customview isn't an actionbar with overlay properties, the customview won't leave and LinearLayout below won't fill the empty space (there is none).
SO, i made it to work with an animationlistener and setting customview visibility to gone when the animation is over but it will flick in a horrible way when you are close to the expected Y point that trigger the animation (flick as customview visibility is gone and LinearLayout below needs to resize itself to fill the empty space, and will quickly repeat if you scroll slowly around there).
XML:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="false"
android:animateLayoutChanges="true">
<com.project.app.layouts.TabsLayout
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/tabs">
<FrameLayout
android:id="#+id/content_frame_header"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<android.support.v4.view.ViewPager
android:id="#+id/viewpager"
android:layout_width="match_parent"
android:layout_height="0px"
android:layout_weight="1"
android:background="#android:color/white"/>
</LinearLayout>
</RelativeLayout>
Is there any way to do this when it's not an actionbar?
EDIT:
Added the comment about how it will flick when you scroll slowly around Y point that triggers the animation to hide/show.
I recommend you to use android:hardwareAccelerated="true" attribute in your Manifest file. It will use your device's GPU to draw views and animations.
I suggest you to check the value of view.getBottom() in both cases (when it works and when not).
It may be that it flicks because the value returned by view.getBottom() is very big.
Add this line in your code:
Log.i("YourAppName", "view.getBottom(): -" + view.getBottom());
view.animate()
.translationY(-view.getBottom())
.alpha(0)
.setDuration(HEADER_HIDE_ANIM_DURATION)
.setInterpolator(new DecelerateInterpolator());
Then check your log to see if the values are the same or not.
I have made it in a slightly different way. Note that the call I'm using requires SDK 19 (KitKat), but you can still do it using ViewPropertyAnimatorCompat
I have a FrameLayout that has the header view and the main view, with the header view on front.
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:fab="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<include layout="#layout/main_layout" android:id="#+id/main_layout" />
<include layout="#layout/header_layout" android:id="#+id/header_layout" />
</FrameLayout>
Once the views are measured (posting a runnable during onResume) I set the topPadding of the main view to be the Height of the header.
In the hide and show animation, I add an update listener and inside it I update the top padding of the main view to be the Height of the header + the Translation on Y.
final View header = findViewById(R.id. header_layout);
header.animate()
.translationY(-header.getBottom())
.setDuration(200)
.setInterpolator(new DecelerateInterpolator())
.setUpdateListener(new AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
int top = (int) (header.getHeight()+header.getTranslationY());
findViewById(R.id.main_view).setPadding(0, top, 0, 0);
}
});
This makes it a bit smoother, since the padding gets updated together with the translation.
Actually, setting an AnimationListener using ViewPropertyAnimatorCompat does not work. The listener is never called, so for backwards compatibility I opted for this solution, not elegant, but at least it work on pre-KitKat devices:
final View mainView = findViewById(R.id.main_view);
Runnable mainUpdateRunnable = new Runnable() {
#Override
public void run() {
int top = (int) (header.getHeight()+header.getTranslationY());
mainView.setPadding(0, top, 0, 0);
if (mAnimatingHeader) {
mainView.post(this);
}
}
};
mainView.post(mainUpdateRunnable);
The variable mAnimatingHeader is updated using the AnimationListener (which works)
I'm attempting to replicate the Facebook app's new menu slider. Creating a slider that comes in from the left is easy enough. However, the Facebook app takes the Activity's layout and slides it right, with only a small part of its left edge still showing on the right side of the screen. I'm a bit confused about how to do this. Does anyone have any ideas?
This best thing I can think of, which I have not tried, is to use the Display class to determine the width of the screen, set the width of the outer-most View to that and display it to the right of the slider (obviously wrapped by a RelativeView).
Update: I've tried the following.
My outer-most View is a RelativeLayout. Inside this RelativeLayout there are two sibling Views. Both of them are LinearLayouts. The first one is a layout containing the side bar (in my XML, this is accomplished through an include). The second one, which sits on top, is a layout containing the main body of the Activity (the screen as I want the user to normally see it).
Here is my XML:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#color/black" >
<include
android:id="#+id/mainnew_slider"
layout="#layout/layout_slidermenu" />
<LinearLayout
android:id="#+id/mainfeed_mainlayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#drawable/loginbg"
android:orientation="vertical" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="64dip"
android:background="#drawable/titlebar_background"
android:orientation="vertical"
android:padding="4dip" >
<ImageButton
android:id="#+id/mainfeed_slider"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/selector_titlebar_button"
android:src="#drawable/sidebarico" />
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="1dip"
android:background="#color/store_toolbar_bottom_border" />
</LinearLayout>
</RelativeLayout>
When the user clicks the ImageButton, I use some animation code to make the main layout move to the right. The code I use to animation the main layout is:
AnimationSet set = new AnimationSet(true);
Animation animation = new TranslateAnimation(
Animation.RELATIVE_TO_PARENT, 0.0f,Animation.RELATIVE_TO_PARENT, 1.0f,
Animation.RELATIVE_TO_PARENT, 0.0f,Animation.RELATIVE_TO_PARENT, 0.0f
);
animation.setDuration(1000);
set.addAnimation(animation);
LayoutAnimationController controller = new LayoutAnimationController(set, 0.0f);
LinearLayout main = (LinearLayout) findViewById(R.id.mainfeed_mainlayout);
main.setLayoutAnimation(controller);
When I click the slider button, the two children of the main layout slide to the right, but not the main layout itself (its background stays static). When the animation is complete, everything snaps back to its original position.
I don't understand why it's not moving the whole main layout and keeping it at its resting place.
A simple TranslateAnimation applied to your top-level view should do it. Don't do it via layout, it'll be way too slow.
Okay, so I've done some looking around and I see how you are SUPPOSED to do it, but for me, it is just not working.
I need to be able to set the alpha of a RelativeLayout both in XML and in code. For my XML, I have the following
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/player_controls"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:alpha="0.0">
<RelativeLayout
android:layout_height="match_parent"
android:layout_width="match_parent"
android:id="#+id/player_controls_touch_me"
>
</RelativeLayout>
</RelativeLayout>
I get the error: no resource identifier found for attribute 'alpha' in package 'android'
Also, based on the Android documentation, I should be able to call setAlpha(double) on any View object, but when I try to make that call on a RelativeLayout it tells me that this method is not defined for this object.
Why am I not able to control the alpha transparency for a RelativeLayout object in Android? Am i missing something? Thanks!
Update
Although using the visibility property works, it prevents me from be able to click on the ViewGroup. This is important for me because I am utilizing the OnTouchListener of the ViewGroup.
What I am trying to do is to have a layer with media controls, initially hidden. when the user taps anywere on the screen, I want the controls to fade in and when they tap the screen again I want the controls to fade out. I have this part already working. I am using a viewgroup that sits over-top my entire application with an OnTouchListener attached that can determine if it has or hasn't been touched. My problem is that after the animation runs to fade out the controls, they re-appear. If I use #Hydrangea suggestion, I can have it fade out and immediately made invisible. This gives me the desired effect, but then the ViewGroup is unclickable and the user cannot get the controls to come back (or go away, depending on what we decide to do first).
I hope this makes sense.
You'll want to use a alpha animation to fade things in and out. This will maintain your touch events for your layouts. Here's an example
public class Main extends Activity {
/** Called when the activity is first created. */
private boolean mShowing = false;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
findViewById(R.id.textview).setOnClickListener(new OnClickListener(){
#Override
public void onClick(View arg0) {
if(mShowing){
Animation animation = new AlphaAnimation(1.0f, 0.0f);
animation.setFillAfter(true);
arg0.startAnimation(animation);
} else {
Animation animation = new AlphaAnimation(0.0f, 1.0f);
animation.setFillAfter(true);
arg0.startAnimation(animation);
}
mShowing = !mShowing;
}
});
}
}
Here's the accompanying xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:id="#+id/textview"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="#string/hello"
android:clickable="true"
/>
</LinearLayout>
Unless you need levels of alpha between 0 and 1, I'd suggest, if you truly want to make this item invisible, to use setVisibility();
android:visibility="invisible"
I checked out the android:alpha line, and my ide doesn't find it either. I can't guess why, though... the documentation seems pretty clear.
The alpha property is new in Android 3.0, and it's not the most efficient way to hide a view. Use View.setVisibility() or android:visibility to achieve what you want.
You can set alpha by setting the (background) color i guess. Color values can be in the format of #aarrggbb (alpha, red, green, blue).
You can add to the right answer the following option:
animation.setDuration(xxx);
To each animation instance. In this way your animation will look better.
Based on your discription, you should be able to create a view that contains only the relative layout and have the onClickListener set to it. This way you can set the visibility of the relative layout to invisible, but still register a click.
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/clickable_layout"
android:layout_height="match_parent"
android:layout_width="match_parent" >
<RelativeLayout
android:id="#+id/player_controls"
android:layout_height="match_parent"
android:layout_width="match_parent" >
<RelativeLayout
android:layout_height="match_parent"
android:layout_width="match_parent"
android:id="#+id/player_controls_touch_me"
>
</RelativeLayout>
</RelativeLayout>
</FrameLayout>
Use onTouchEvent in Activity, and then you could get touch event to control to your RelativeLayout even if it is "invisible".