I have a clickable TextView:
width = match_parent, height = "wrap_content"
When I press it, I want to show a LinearLayout containing 3 views, orientation vertical, and I want to animate it to slide down from behind the TextView, below it. Like a drop-down, but not using Spinner.
Any ideas?
If you want a dropdown-like effect, you should probably use a PopupWindow to show your LinearLayout. That's what Spinner uses internally. You can set the enter and exit animations for it. By default, a PopupWindow from a Spinner performs a scale and alpha animation at the same time.
There is also PopupMenu which is a specialized class to show menus with the standard animations.
1. Create an animation XML for slide down in /res/anim/ folder:
slide_down.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >
<translate
android:duration="1000"
android:fromYDelta="0%"
android:toYDelta="25%" />
</set>
FYI, You can change animation duration and YDelta as per your needs.
2. Design your desired layout. Use RelativeLayout as root and set child LinearLayout visibility GONE.
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">
<LinearLayout
android:id="#+id/layout_dropdown"
android:layout_width="fill_parent"
android:layout_height="200dp"
android:orientation="horizontal"
android:background="#android:color/holo_red_dark"
android:visibility="gone">
<!-- Your 3 Views here -->
</LinearLayout>
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:text="Click Here"
android:textSize="30sp"/>
</RelativeLayout>
3. In your Activity, programmatically apply slide_down animation on LinearLayout(layout_dropdown) to show and sliding down when clicked on TextView(textView):
MainActivity.java
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.LinearLayout;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
TextView textView;
LinearLayout linearLayout;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.textView);
linearLayout = (LinearLayout) findViewById(R.id.layout_dropdown);
textView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Animation slideDown = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.slide_down);
linearLayout.setVisibility(View.VISIBLE);
linearLayout.startAnimation(slideDown);
// Required to keep layout stay at final position after animation
slideDown.setFillAfter(true);
}
});
}
}
OUTPUT:
Hope this will help~
Make LinearLayout with scaleY=0 and then animate it to 1.0
Execute this in the onClicklistener:
ViewCompat.animate(yourView)
.scaleY(1.0f)
.start();
Related
I have a fragment with a navigation menu at the top-left corner. At the start of the activity, I want to gradually slide a view (let's call it black_view) out of the menu icon.
Here's a rough breakdown of how I want the animation to be in accordance with the images below:
Activity starts as the first image with black_view being invisible.
black_view gradually slides out from behind the menu icon length by length until it gets to the point of the second image.
>>>
What I've tried:
I tried achieving this by using a TranslateAnimation. However, the whole length of black_view shows up at the start of the animation and this is not what I want. I also saw a couple of sliding animation code snippets like this and this, but they all follow the TranlateAnimation model (with the whole length of black_view showing instantly).
How can I achieve this?
PS: If there's any important detail that I failed to add, kindly let me know.
It can be done easily with Slide transition from Transition API. Just use TransitionManager.beginDelayedTransition method then change visibility of black view from GONE to VISIBLE.
import androidx.appcompat.app.AppCompatActivity;
import androidx.transition.Slide;
import androidx.transition.Transition;
import androidx.transition.TransitionManager;
public class MainActivity extends AppCompatActivity {
private ViewGroup parent;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
parent = findViewById(R.id.parent);
parent.getViewTreeObserver().addOnPreDrawListener(new OnPreDrawListener() {
#Override
public boolean onPreDraw() {
parent.getViewTreeObserver().removeOnPreDrawListener(this);
animate();
return true;
}
});
}
private void animate() {
View textView = findViewById(R.id.text);
Transition transition = new Slide(Gravity.LEFT);
transition.setDuration(2000);
transition.setStartDelay(1000);
TransitionManager.beginDelayedTransition(parent, transition);
textView.setVisibility(View.VISIBLE);
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:text="Button" />
<FrameLayout
android:id="#+id/parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toRightOf="#+id/button">
<TextView
android:id="#+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#000"
android:text="hello world"
android:textColor="#fff"
android:textSize="22sp"
android:visibility="gone" />
</FrameLayout>
</RelativeLayout>
Result:
All classes here are from androix package so code is backward compatible.
I would like to do something like this:
https://storage.googleapis.com/spec-host/mio-staging%2Fmio-design%2F1563837804615%2Fassets%2F1XlKhaQFU9aS84ACmF-EDjVKDgI4pPldv%2F02-overflowmenu.mp4
I would like to squeeze a "ViewGroup" as you can see in the video. In the meantime, I want to fade out the content in the ViewGroup at its original position. i.e. not pushing the content to the right.
Any idea how to implement this?
Thanks!
You can do such animations with Transition API. Declare two ViewGroups: first one is horizontal with cut/copy buttons, second is vertical with search/share buttons. Then switch these ViewGroups with TransitionManager. Then just provide Transition which describes how views on first and second ViewGroups appears and disappers.
import androidx.appcompat.app.AppCompatActivity;
import androidx.transition.ChangeBounds;
import androidx.transition.Fade;
import androidx.transition.Scene;
import androidx.transition.Slide;
import androidx.transition.Transition;
import androidx.transition.TransitionManager;
import androidx.transition.TransitionSet;
public class MainActivity extends AppCompatActivity {
private ViewGroup mSceneRoot;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_layout);
mSceneRoot = findViewById(R.id.sceneRoot);
showPopup1();
}
private void showPopup1() {
ViewGroup popup1 = (ViewGroup) getLayoutInflater().inflate(R.layout.popup_1, mSceneRoot, false);
popup1.findViewById(R.id.btnGo).setOnClickListener(v -> {
showPopup2();
});
Scene scene = new Scene(mSceneRoot, popup1);
TransitionManager.go(scene, getTransition(false));
}
private void showPopup2() {
ViewGroup popup2 = (ViewGroup) getLayoutInflater().inflate(R.layout.popup_2, mSceneRoot, false);
popup2.findViewById(R.id.btnBack).setOnClickListener(v -> {
showPopup1();
});
Scene scene = new Scene(mSceneRoot, popup2);
TransitionManager.go(scene, getTransition(true));
}
}
activity_layout.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/sceneRoot"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="bottom|right"
android:orientation="vertical"
android:paddingBottom="150dp"
android:paddingRight="50dp"
android:clipToPadding="false"
android:clipChildren="false"/>
popup_1.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/popup1"
android:layout_width="250dp"
android:layout_height="wrap_content"
android:transitionName="bg"
app:cardElevation="10dp">
<Button
android:id="#+id/btnGo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="go"
android:transitionName="btn_go"/>
</androidx.cardview.widget.CardView>
popup_2.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/popup2"
android:layout_width="wrap_content"
android:layout_height="250dp"
android:transitionName="bg"
app:cardElevation="10dp">
<Button
android:id="#+id/btnBack"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="back"
android:transitionName="btn_back"/>
</androidx.cardview.widget.CardView>
Last thing here is getTransition method. You can just use AutoTransition, it can handle easy layout changes.
private Transition getTransition(boolean open) {
return new AutoTransition();
}
Result:
Also just for demostration I wrote more complex transition where button on first viewgroup appear/dissapear with Slide animation.
private Transition getTransition(boolean open) {
Slide btnGo = new Slide(Gravity.RIGHT);
btnGo.addTarget("btn_go");
ChangeBounds bgBounds = new ChangeBounds();
bgBounds.addTarget("bg");
Fade btnBack = new Fade();
btnBack.addTarget("btn_back");
TransitionSet set = new TransitionSet();
set.setOrdering(TransitionSet.ORDERING_SEQUENTIAL);
if (open) {
set.addTransition(btnGo);
set.addTransition(bgBounds);
set.addTransition(btnBack);
} else {
set.addTransition(btnBack);
set.addTransition(bgBounds);
set.addTransition(btnGo);
}
return set;
}
Result:
Note that transitionName for background should be same in both layouts.
All transition classes here are from androix package so code is backward compatible. But if you need support pre Lollipop devices you should set transitionName via ViewCompat.setTransitionName method.
You can check my another answer with more difficult/custom transition.
I have a basic app working, but now I am focusing on formatting the app and running into difficulty laying things out as I want them.
I have a list of images that the user can switch from one to the next with using a next button. Both the images and the next button are added programmatically to the page (I clear out anything in the layout, and then add the ImageView and Button). Now, instead of laying them out one on top of the other, I am trying to lay them out next to each other, so the image will take up most of the space, and then the next button will be to its right.
Looking through the documentation I was leaning towards using a RelativeLayout to accomplish this. However, I ran into some questions while using RelativeLayouts programmatically.
Activity.xml
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/container"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:fillViewport="true">
<RelativeLayout
android:orientation="vertical"
android:id="#+id/activity_training_package_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:context="com.example.xxx.PackageActivity"
tools:ignore="MergeRootFrame">
</RelativeLayout>
</ScrollView>
Attempt to programmatically add the button:
public void addNextButton(final int currentFile, final RelativeLayout layout) {
Button next = new Button(this);
next.setWidth(100);
int id = layout.getChildAt(0).getId(); // the image is the only thing there
RelativeLayout.LayoutParams lay = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
lay.addRule(RelativeLayout.RIGHT_OF, id);
next.setLayoutParams(lay);
next.setText("NEXT >>");
next.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
showNextFile(currentFile, layout);
}
//layout.setLayoutParams(lay);
layout.addView(next);
...
I am just wondering which LayoutParams I am supposed to be setting for this, the LayoutParams of the layout, or of the view? When I try to set it to the layout, I get a cast exception (it is expecting a FrameLayout.LayoutParams, not a RelativeLayout.LayoutParams for some reason).
Could someone please point me in the right direction to figure out how layouts are used? I cannot seem to find resources that explain which LayoutParams I should be setting.
TL;DR How do you use RelativeLayouts and LayoutParams programmatically?
The simplest solution is to use the HorizontalSrollView with a LinearLayout.
activity_test.xml
<HorizontalScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<LinearLayout
android:id="#+id/container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal" />
</HorizontalScrollView>
TestActivity.java
public class TestActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
LinearLayout container = (LinearLayout)findViewById(R.id.container);
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
String next = getResources().getString(R.string.next);
for(int i=0;i<5;i++){
ImageView imgView = new ImageView(mActivity);
imgView.setLayoutParams(params);
imgView.setImageResource(R.drawable.photo);
container.addView(imgView);
Button button = new Button(mActivity);
button.setLayoutParams(params);
button.setText(next);
container.addView(button);
}
}
}
set Linear Layout weight Property in your XML file and assign weight to the imageview and button
main_activity.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="fill_parent"
android:layout_height="fill_parent"
android:gravity="center_vertical"
android:orientation="horizontal"
android:weightSum="1" />
MainActivity.java
package com.example.stackoverflowdemos;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.TableLayout;
public class MainActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LinearLayout container = (LinearLayout)findViewById(R.id.container);
//Dynamically generate imageview and button
ImageView imgView = new ImageView(this);
imgView.setLayoutParams(new TableLayout.LayoutParams(0, LayoutParams.FILL_PARENT, .2f)); //set imageview height and width using weight
imgView.setImageResource(R.drawable.ic_launcher);
container.addView(imgView);
Button button = new Button(this);
button.setLayoutParams(new TableLayout.LayoutParams(0, LayoutParams.WRAP_CONTENT, .8f)); //set Button height and width using weight
button.setText("next");
container.addView(button);
}
}
I am trying to add the button dynamically when list is empty i.e no data to populate the list. I tried the below code and it not working
public class TableDemoActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
LinearLayout linearLayout = (LinearLayout) findViewById(R.id.linear);
Button test = new Button(this);
test.setText("Hello Android");
test.setId(5);
test.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.WRAP_CONTENT));
linearLayout.addView(test);
}
}
Here is the layout file contents
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/linear"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TableLayout
android:id="#+id/TblLyt"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TableRow
android:id="#+id/AcctHeader"
>
</TableRow>
<ExpandableListView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/BankExpandableListView"
android:layout_width="fill_parent"
android:layout_height="443dp"
android:layout_weight="1.32"
>
</ExpandableListView>
</TableLayout>
</LinearLayout>
You can put your button in xml layout file and do visible & invisible as per your condition
if(your condition)
{
button.setVisibility(View.VISIBLE);
}
else
{
button.setVisibility(View.GONE);
}
I solved your problem. Follow these steps. Your code is right but you have made a small mistake. You are adding your view or button in linear layout but your table layout is holding the entire area of your screen by using width and height being fill parent, so just add your button in table layout like this:
import android.app.Activity;
import android.os.Bundle;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.TableLayout;
public class TableDemoActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
LinearLayout linearLayout = (LinearLayout) findViewById(R.id.linear);
TableLayout table=(TableLayout) findViewById(R.id.TblLyt);
Button test = new Button(this);
test.setText("Hello Android");
test.setId(5);
test.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.WRAP_CONTENT));
table.addView(test);
//linearLayout.addView(test);
}
}
Now you can add button dynamically.
It's there, you just can't see it because of this:
<TableLayout
android:id="#+id/TblLyt"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
You are telling table to fill the entire layout. You could set the TableLayout to GONE and then add the button, or you can change the layout_height to wrap_content.
I need to create a button where there is a icon in the left and a text in the right. After pressing the button, I want to see there is an animation of rotating image at the place of the left icon in the button.
I know how to rotate a image with ImageView, but it is not helpful to my current requirement.
I tried to use AnimationDrawable, but it did not work either, there is no animation but only the first png file shown. It is then same whatever I use the background or leftDrawable of the button to run the AnimationDrawable. The code is as below:
package com.example.layout;
import android.app.Activity;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.widget.Button;
public class TestLinearlayoutActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
#Override
public void onStart() {
super.onStart();
Button locationTitleButton = (Button) findViewById(R.id.LocationTitleButton);
//locationTitleButton.setBackgroundResource(R.drawable.loading);
locationTitleButton.setCompoundDrawablesWithIntrinsicBounds(R.drawable.loading, 0, 0, 0);
Drawable[] locationTitleButtonDrawables = locationTitleButton.getCompoundDrawables();
AnimationDrawable animDrawable = (AnimationDrawable) locationTitleButtonDrawables[0];
//AnimationDrawable animDrawable = (AnimationDrawable) locationTitleButton.getBackground();
animDrawable.start();
}
}
//loading.xml:
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<item android:drawable="#drawable/loc1" android:duration="200" />
<item android:drawable="#drawable/loc2" android:duration="200" />
<item android:drawable="#drawable/loc3" android:duration="200" />
<item android:drawable="#drawable/loc4" android:duration="200" />
</animation-list>
// layout file, main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:orientation="horizontal" android:padding="0dp"
android:layout_height="wrap_content" android:gravity="fill_horizontal" android:layout_margin="0dp">
<Button android:id="#+id/LocationTitleButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="0dip"
android:layout_gravity="center_vertical"
android:gravity="center_vertical"
android:layout_weight="1"
android:ellipsize="end"
android:scrollHorizontally="true"
android:singleLine="true"
android:text="Add location"
android:textStyle="bold" />
<Button android:textColor="#FF000000"
android:layout_weight="0"
android:id="#+id/AddLocationButton"
android:text="Search"
android:gravity="center_vertical"
android:layout_gravity="center_vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="-8dp" />
</LinearLayout>
You can try using an AnimationDrawable.
I have also face this issue and I have tried all above solution but no one have worked for me. I have found solution here. Android document says that don't call start() in the onCreate(Bundle) method of activity call it in onWindowFocusChanged(boolean) function. So I do it like this :
#Override
public void onWindowFocusChanged(boolean hasFocus){
if(hasFocus){
final AnimationDrawable d=(AnimationDrawable) mBtnView.getCompoundDrawables()[0];
d.start();
}
}
Use a LinearLayout (orientation horizontal). Treat that as your button by giving it a button drawable selector as it's background drawable. Inside it, put an ImageView and a TextView. Use an OnClickListner on the LinearLayout, as if it were a button. Then animate the ImageView.