Animate LinearLayout when keyboard goes up/down - android

I have a layout like this:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="25dp"
android:paddingRight="25dp">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/imageView"
android:background="#drawable/logo" />
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView ... />
<EditText ... />
</LinearLayout>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView ... />
<EditText ... />
</LinearLayout>
</LinearLayout>
<Button ... />
</LinearLayout>
I want to fade out the ImageView and move the second (inner) LinearLayout up (near the top of the screen) when the keyboard comes up and then do the opposite when the keyboard goes back down.
How can I achieve this?

Use TranslateAnimation class to animate your view.
Animation slide = new TranslateAnimation(fromX,toX,fromY,toY);
slide.setDuration(300);//here you can set your own duration of animation in ms.
yourView.startAnimation(slide);
You can also override some callbacks.
slide.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
There is no direct way of finding out whether android softkey pad is opne or not . But you can do a work around and calculate the size diff between your activity's view root and the window size. There are many ways to do it, one way that i found was this:
final View activityRootView = findViewById(R.id.activityRoot);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
int heightDiff = activityRootView.getRootView().getHeight() - activityRootView.getHeight();
if (heightDiff > 100) { // if more than 100 pixels, its probably a keyboard...
... do something here
}
}
});

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();

Flickers while layout visible/gone

Is there any way to hide a view without flickering its above view?
I am trying to hide a View below MapView. Once I set its visibility to GONE, MapView flickers. As I have to add more markers dynamically, couldn't able to keep MapView and bottomView in FrameLayout, since the bottomView will hide those markers in small size screens.
Layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true">
<com.myapp.widgets.MapPlacePicker
android:id="#+id/lay_fr_map_inc"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="#+id/options_layout" />
<LinearLayout
android:id="#+id/options_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:animateLayoutChanges="true"
android:background="#FFFFFF"
android:orientation="vertical"
android:visibility="visible">
<com.myapp.widgets.FontTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="10dp"
android:text="Please select a location!!"
android:textAppearance="#android:style/TextAppearance.Small" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<com.aigestudio.wheelpicker.WheelPicker
android:id="#+id/main_option_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:layout_weight="0.5"
app:wheel_atmospheric="true"
app:wheel_curved="false"
app:wheel_item_space="15dp"
app:wheel_item_text_color="#ffafafaf"
app:wheel_item_text_size="12dp"
app:wheel_selected_item_text_color="#color/colorPrimary"
app:wheel_visible_item_count="3" />
</LinearLayout>
</LinearLayout>
</RelativeLayout>
Output:
I have also tried TranslationAnimation, but no luck. Its showing more gray space than before.
int fromY = (visibility == View.GONE) ? 0 : optionLayout.getHeight();
int toY = (visibility == View.GONE) ? optionLayout.getHeight() : 0;
if (visibility == View.VISIBLE) {
optionLayout.setVisibility(visibility);
}
TranslateAnimation animate = new TranslateAnimation(
0, // fromXDelta
0, // toXDelta
fromY, // fromYDelta
toY); // toYDelta
animate.setDuration(1000);
animate.setInterpolator(new AccelerateDecelerateInterpolator());
//animate.setFillAfter(false);
animate.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
if (visibility == View.GONE)
optionLayout.setVisibility(visibility);
optionLayout.clearAnimation();
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
optionLayout.startAnimation(animate);
I don't see any flickering in that animation; if you want to avoid the vertical resizing behavior of lay_fr_map_inc then you can just remove this attribute:
android:layout_above="#+id/options_layout"
...and maybe make the height match_parent. Then, lay_fr_map_inc will stay full height, but the bottom portion will be hidden by options_layout when it appears (instead of scooting upwards).
Don't forget to change the map padding when you do this, so you don't obscure the Google logo (which is a violation of the rules): setPadding()

Android: RelativeLayout translateY animation with layout_alignParentBottom

I'm working on an Android app with an animation where a vertically central view should be animated from the center to the top of the screen. Below this view is another view containing related content, which is aligned directly below the center view. When the center view animates up, I want the lower view to be 'pinned' to the top but also to the bottom of the screen (as per layout_alignParentBottom="true"). Currently though, as the bottom view animates up a gap is left between the bottom view and the bottom of the screen:
What's the easiest way to animate the bottom view, while keeping it pinned to the bottom of the screen?
Here is my layout XML:
<?xml version="1.0" encoding="utf-8"?>
<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:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context="newsoni.com.testrelativelayouttranslation.MainActivity">
<View
android:layout_width="match_parent"
android:layout_height="20dp"
android:background="#FF0000"
android:layout_centerVertical="true"
android:id="#+id/centerBar" />
<View
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="#00FF00"
android:layout_below="#+id/centerBar"
android:id="#+id/bottomPanel" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Do animation"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:id="#+id/btn" />
</RelativeLayout>
Here is my Java:
public class MainActivity extends AppCompatActivity {
private View mCenter, mBottomPanel;
private Button mBtn;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mCenter = findViewById(R.id.centerBar);
mBottomPanel = findViewById(R.id.bottomPanel);
mBtn = $(R.id.btn);
mBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int value = mCenter.getTranslationY() == 0 ? -mCenter.getTop() : 0;
mCenter.animate()
.translationY(value)
.setDuration(250)
.start();
mBottomPanel.animate()
.translationY(value)
.setDuration(250)
.start();
}
});
}
#SuppressWarnings("unchecked")
public <T extends View> T $(int id) {
return (T) findViewById(id);
}
}
Here is a link to the project which you can download:
https://drive.google.com/file/d/0B-mqMIMqm_XHamxENkhIZDJDMHM/view?usp=sharing
I ended up using a standard Animation and overriding applyTransformation to manually alter the LayoutParams of the bottom view.

Android - TextView with 'zero' height

I would to set dinamically the TextView height with an ObjectAnimator.
This is the code:
if(condition){
height = 136;
}else{
height = 0;
}
ObjectAnimator animator = ObjectAnimator.ofInt(
mText,
"height",
height
).setDuration(400);
animator.start();
This works, somwhere, but it doesn't set the TextView height to 0, but about 80px.
Why?
To hide and show textview, It is not good practice to set its heights instead do this:
textview.setVisibility(View.GONE);
OR
textview.setVisibility(View.INVISIBLE);
View.GONE This view is invisible, and it doesn't take any space for layout purposes.
View.INVISIBLE This view is invisible, but it still takes up space for layout purposes.
To make it Visible again, use
textview.setVisibility(View.VISIBLE);
EDITED
To hide view with animation,
ObjectAnimator anim = ObjectAnimator.ofFloat(view, "alpha", 0.0f);
anim.addListener(new AnimatorListener() {
...
#Override
public void onAnimationEnd(Animator animation) {
animDrawable.stop()
}
...
});
anim.setDuration(300).start();
This will gradually fade your view and hide it with animation.
If you want to hide the TextView with animation, use below code
ViewPropertyAnimator mTextAnimator = myTextView.animate()
.scaleY(0f)
.setListener(new Animator.AnimatorListener() {
public void onAnimationStart(Animator animation) {}
public void onAnimationRepeat(Animator animation) {}
public void onAnimationCancel(Animator animation) {}
public void onAnimationEnd(Animator animation) {
myTextView.setVisibility(View.GONE);
}
})
.setDuration(400);
mTextAnimator.start();
To show TextView with animation, use
mTextAnimator = myTextView.animate()
.scaleY(1f)
.setListener(null)
.setDuration(400);
mTextAnimator.start();
I assume you are trying to hide it by setting height to 0? If this is the case, why not use .setVisibility(View.GONE)?
If you have other views depending on its location then use setVisibility(View.INVISIBLE). Otherwise use setVisibility(View.GONE).
In my .xml file, I used android:visibility="gone". Originally I had this:
<TextView
android:id="#+id/labelReachable"
android:layout_width="wrap_content"
android:gravity="left"
android:textSize="15dp"
android:layout_marginTop="10dp"
android:layout_height="wrap_content"
android:layout_marginRight="10dp"
android:text="Reachability"></TextView>
<ImageView
android:background="#drawable/bar_dark"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
<LinearLayout
android:id="#+id/insertPings"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:orientation="vertical" >
</LinearLayout>
I wanted to make those elements invisible and not take any space for layout purposes. I simply used android:visibility="gone" to have this:
<TextView
android:id="#+id/labelReachable"
android:layout_width="wrap_content"
android:gravity="left"
android:textSize="15dp"
android:layout_marginTop="10dp"
android:layout_height="wrap_content"
android:layout_marginRight="10dp"
android:visibility="gone"
android:text="Reachability"></TextView>
<ImageView
android:background="#drawable/bar_dark"
android:layout_width="fill_parent"
android:visibility="gone"
android:layout_height="wrap_content"/>
<LinearLayout
android:id="#+id/insertPings"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:visibility="gone"
android:orientation="vertical" >
</LinearLayout>

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