I have following view inside my layout
<RelativeLayout
android:id="#+id/wrapper"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true">
<LinearLayout
android:id="#+id/header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true">
<!-- some child views here -->
</LinearLayout>
<LinearLayout
android:id="#+id/footer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/header"
android:visibility="gone">
<!-- some other child views here -->
</LinearLayout>
</RelativeLayout>
The wrapper RelativeLayout is aligned to bottom of its parent. And initialy footer view is not displayed (View.GONE). When header view is tapped, then footer should be shown to user with slide up animation from bottom of screen and when user taps again footer should be slide down to bottom. When i start an slide up animation on footer view, it does not push header view simultaneously with animation. If i first set footer view visibility to View.INVISIBLE first and then start animation, header view is pushed up immediately (not together with animation or footer view), and footer view comes with animation.
Here is the code to call animation
footer.setVisibility(View.INVISIBLE);
Animation animation = AnimationUtils.loadAnimation(activity, R.anim.slide_up_from_bottom);
animation.setDuration(animDuration);
footer.startAnimation(animation);
footer.postDelayed(new Runnable() {
#Override
public void run()
{
footer.setVisibility(View.VISIBLE);
}
}, animDuration);
and this is the animation file content:
How can i make this animation to push header view, while footer view sliding up?
Hope i made myself clear. All i want is both views moves up/down together.
If i apply animation to wrapper view then it slides up from bottom (not from current location).
If you want your header to push along with footer animation, you can do it manually as follows
public class MainActivity extends Activity {
private LinearLayout header,footer;
private RelativeLayout wrapper;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
header = (LinearLayout) findViewById(R.id.header);
footer = (LinearLayout) findViewById(R.id.footer);
wrapper = (RelativeLayout) findViewById(R.id.wrapper);
header.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(footer.getVisibility() == View.VISIBLE){
int footerHeight = footer.getMeasuredHeight();
float initialWrapperY = wrapper.getY();
ObjectAnimator oa=ObjectAnimator.ofFloat(wrapper, "y", initialWrapperY,initialWrapperY+footerHeight);
oa.setDuration(400);
oa.start();
oa.addListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(android.animation.Animator animation) {
footer.setVisibility(View.INVISIBLE);
};
});
}
else{
final float initialWrapperY = wrapper.getY();
footer.setVisibility(View.VISIBLE);
wrapper.setY(initialWrapperY);
ViewTreeObserver vto=wrapper.getViewTreeObserver();
vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
wrapper.getViewTreeObserver().removeOnPreDrawListener(this);
final int footerHeight = footer.getMeasuredHeight();
ObjectAnimator oa=ObjectAnimator.ofFloat(wrapper, "y", initialWrapperY,(initialWrapperY-footerHeight));
oa.setDuration(400);
oa.start();
return true;
}
});
}
}
});
}
}
Related
I am trying to expand and collapse my view with the help of TransitionManager animation. Following is the output,
See the overlapping layout while collapsing top view. How to avoid that ? I set "detailedView" (one with icons) visibility GONE and use following code for animation,
topView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
TransitionManager.beginDelayedTransition(topView);
TransitionManager.beginDelayedTransition(bottomView);
if (detailsView.getVisibility() == View.VISIBLE) {
detailsView.setVisibility(View.GONE);
cardText.setText("Collapse Title");
} else {
detailsView.setVisibility(View.VISIBLE);
cardText.setText("Expanded Title");
}
}
});
I would build the animation differently. I would make a LinearLayout with the top cell with wrap_content, and when clicking I would do something like:
valueAnimator = ValueAnimator.ofInt(titleContainer.getHeight(),titleContainer.getHeight() + newHeight );
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
titleContainer.setHeight(animation.getAnimatedValue());
}
});
valueAnimator.setDuration(270);
valueAnimator.start();
I had the same problem.
The first argument that the TransitionManager.beginDelayedTransition() function takes must be the parent of all the views that will interact in the transition e.g:
I have the next layout:
<!-- The scene root -->
<LinearLayout
android:id="#+id/transition_container" >
<!-- First card -->
<androidx.cardview.widget.CardView
android:id="#+id/expandableCard1">
<LinearLayout
android:id="#+id/staticHeader1">
</LinearLayout>
<LinearLayout
android:id="#+id/expandableContent1">
</LinearLayout>
</androidx.cardview.widget.CardView>
<!-- Second card -->
<androidx.cardview.widget.CardView
android:id="#+id/expandableCard2">
<LinearLayout
android:id="#+id/staticHeader2">
</LinearLayout>
<LinearLayout
android:id="#+id/expandableContent2">
</LinearLayout>
</androidx.cardview.widget.CardView>
</LinearLayout>
And my code (kotlin):
// toggle
if( expandableContent1.visibility == View.GONE ){
// apply to the root scene
TransitionManager.beginDelayedTransition(transition_container )
// change the visibility of the expandable content
expandableContent1.visibility = View.VISIBLE
arrowBtn.setImageResource( R.drawable.ic_arrow_up_24)
} else {
// apply to the root scene
TransitionManager.beginDelayedTransition(transition_container )
// change the visibility of the expandable content
expandableContent1.visibility = View.GONE
arrowBtn.setImageResource( R.drawable.ic_arrow_down_24)
}
I want to make this, but I didn't find any tuts or anything how to make it. (It's called Morph on google website) Can anybody tell me how or send some reference pls?
EDIT:
I want to set the layout from gone to visible... Don't you know when I should do shape.setVisibility(View.VISIBLE)? I tried but animation won't start until second click on button. (On first click layout is just set visible without animation)
Fragment layout:
<EditText
android:id="#+id/editText"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusable="true"
android:gravity="top"
android:padding="15dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:id="#+id/circle"
android:visibility="gone">
</LinearLayout>
<ImageButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:background="#color/transparent"
android:contentDescription="share"
android:padding="15dp"
android:src="#drawable/ic_share_55x55px" />
Fragment:
ImageButton fab = (ImageButton) view.findViewById(R.id.share);
fab.setOnClickListener(new View.OnClickListener() {
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
#Override
public void onClick(View view) {
LinearLayout shape = (LinearLayout) getActivity().findViewById(R.id.circle);
// Create a reveal {#link Animator} that starts clipping the view from
// the top left corner until the whole view is covered.
Animator animator = ViewAnimationUtils.createCircularReveal(
shape,
shape.getWidth() - 130,
shape.getHeight()- 130,
0,
(float) Math.hypot(shape.getWidth(), shape.getHeight()));
// Set a natural ease-in/ease-out interpolator.
animator.setInterpolator(new AccelerateDecelerateInterpolator());
animator.setDuration(400);
// Finally start the animation
animator.start();
}
});
Your would need to Animate a view (in this example a LinearLayout). Set the x and y values of the createCircularReveal to the fab button.
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
LinearLayout shape = (LinearLayout) rootView.findViewById(R.id.circle);
// Create a reveal {#link Animator} that starts clipping the view from
// the top left corner until the whole view is covered.
Animator animator = ViewAnimationUtils.createCircularReveal(
shape,
0,
0,
0,
(float) Math.hypot(shape.getWidth(), shape.getHeight()));
// Set a natural ease-in/ease-out interpolator.
animator.setInterpolator(new AccelerateDecelerateInterpolator());
// Finally start the animation
animator.start();
}
});
This is the information on the createCircleReveal
createCircularReveal(View view,
int centerX, int centerY, float startRadius, float endRadius);
Example Project:
https://github.com/googlesamples/android-RevealEffectBasic/
UPDATE
Instead of setting the view to GONE, set it to INVISIBLE. Also make the view setEnabled(false) to prevent it from being touched etc.
LinearLayout shape;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.reveal_effect_basic, container, false);
shape = (LinearLayout) view.findViewById(R.id.circle);
shape.setVisibility(View.INVISIBLE);
shape.setEnabled(false);
ImageButton fab = (ImageButton) view.findViewById(R.id.share);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Animator animator = ViewAnimationUtils.createCircularReveal(
shape,
shape.getWidth() - 130,
shape.getHeight() - 130,
0,
(float) Math.hypot(shape.getWidth(), shape.getHeight()));
shape.setVisibility(View.VISIBLE);
animator.setInterpolator(new AccelerateDecelerateInterpolator());
if (shape.getVisibility() == View.VISIBLE) {
animator.setDuration(400);
animator.start();
shape.setEnabled(true);
}
}
});
Having a text displayed initially at screen bottom. When clicking on it, the list view below it should sliding up. Clicking on the text again the list view sliding down.
Made it work with the snippet below except the first time clicking on the text the list does not do the animation sliding up. After that it will animate sliding up/down as expected.
It is because in the first clicking and call of showListView(true); since the list view’s visibility was “gone”, so it has not had height. The “y” == 0 translate does not do anything. It is just the list view’s visibility change to “visible”, which push the titleRow change its position.
But if to begin with the list view’s visibility to “visible”, the initial showListView(false); in setupListViewAdapter() does not push the list view down to initial state (outside of screen bottom) since it does not have the height until the list row are filled in from the adapter by mListView.setAdapter(mListAdapter).
Is there better way to do sidling up/down the list view?
<TextView
android:id="#+id/titleRow”
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=“title row”
/>
<ListView
android:id="#+id/list_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility=“gone”
>
</ListView>
initial state list view collapsed(outside screen bottom)
+++++++++++++++++++++++++++
+ mTitleRow + ^ +
+++++ screen bottom +++++
listview expanded
+++++++++++++++++++++++++++
+ mTitleRow + ^ +
+++++++++++++++++++++++++++
+ +
+ mListView +
+ +
+++++ screen bottom +++++
void setupListViewAdapter(){
mTitleRow.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (mTitleRow.getTag() == STATE_COLLAPSED)
{
mListView.setVisibility(View.VISIBLE);
showListView(true);
} else {
showListView(false);
}
}
});
mListView.setAdapter(mListAdapter);
showListView(false);
}
private static final int STATE_EXPANDED = 1;
private static final int STATE_COLLAPSED = 2;
boolean mListInAnimation = false;
public void showListView(final boolean show) {
if (mListView != null && !mListInAnimation) {
mListInAnimation = true;
mTitleRow.setTag(show ? STATE_EXPANDED : STATE_COLLAPSED);
int translateY = show ? 0 : (listHeight);
mTitleRow.animate().translationY(translateY).setDuration(300).setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
mListInAnimation = false;
}
});
}
}
You can do this very easily using API 16's LayoutTransition.CHANGING.
Set animateLayoutChanges to true on the parent ViewGroup:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/parent"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="vertical"
android:animateLayoutChanges="true">
<TextView
android:id="#+id/titleRow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="title row"/>
<ListView
android:id="#+id/list_view"
android:layout_width="match_parent"
android:layout_height="0dp"/>
</LinearLayout>
Enable LayoutTransition.CHANGING; on click of the title, set the height of the list view:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LinearLayout linearLayout = (LinearLayout) findViewById(R.id.parent);
linearLayout.getLayoutTransition().enableTransitionType(LayoutTransition.CHANGING);
final View listView = findViewById(R.id.list_view);
View titleRow = findViewById(R.id.titleRow);
titleRow.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = params.height == 0 ? ViewGroup.LayoutParams.WRAP_CONTENT : 0;
listView.setLayoutParams(params);
}
});
}
I have 3 views: an ImageView, a RelativeLayout and a ListView. When the user scrolls down, I have to hide the ImageView first. When the top of the RelativeLayout touches the top of the screen it has to fix itself there and the scroll must be done by the ListView. Then when I scroll up, the top of the ListView must be visible before the ImageView starts to scroll down again.
Is there any component that does what I want without having to write my own component?
(Just to make things easier, it should work like the headers in Instagram, when the header reaches the top it stays there, but there should be only one header)
I have a very simple solution to this, hope it helps. I use one header added to the listView and the same header added to the page on top. There is a listener to toggle visibility of the fixed header. Everything is done in the onCreate method:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListView listView = (ListView) findViewById(R.id.list);
LayoutInflater inflater = getLayoutInflater();
// your image header
View headerImage = inflater.inflate(R.layout.header_image, listView, false);
listView.addHeaderView(headerImage);
// the header that scrolls with the listview
final View fixedHeader = inflater.inflate(R.layout.header_fixed, listView, false);
listView.addHeaderView(fixedHeader);
// the header that is fixed on top of the screen
final View secondFixedHeader = findViewById(R.id.fixed_header);
secondFixedHeader.setVisibility(View.GONE);
listView.setOnScrollListener(new AbsListView.OnScrollListener() {
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {}
#Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if (firstVisibleItem > 0) {
secondFixedHeader.setVisibility(View.VISIBLE);
} else {
secondFixedHeader.setVisibility(View.GONE);
}
}
});
listView.setAdapter(new ListAdapter(this));
}
there is the activity_main.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="#+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<include
android:id="#+id/fixed_header"
layout="#layout/header_fixed" />
</RelativeLayout>
there is the header_fixed.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:background="#android:color/darker_gray">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="This is a fixed header"
android:textAppearance="#android:style/TextAppearance.DeviceDefault.Large"/>
</RelativeLayout>
and there is the header_image.xml:
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:src="#drawable/android"/>
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