I have a LinearLayout, for which I apply android:animateLayoutChanges="true" in the parent LinearLayout. When the user clicks a toggle button, the LinearLayout "collapses" (I set the view's visibility as LinearLayout.GONE programmatically, and when they click it again, it expands by programmatically setting the visibility back to LinearLayout.VISIBLE.
The animation of it collapsing and expanding works correctly.
However, any items below the collapsable/expandable LinearLayout snap back to the top before the animation of the collapse is complete. The items that are snapping back are NOT inside the parent which has animateLayoutChanges set to true, and I don't think there is any way I can put them inside it.
Here is my layout hierarchy (I didn't mention the attributes to keep it short):
<!-- Top most LinearLayout-->
<LinearLayout>
<!-- LinearLayout containing android:animateLayoutChanges="true"-->
<LinearLayout>
<!-- RelativeLayout containing button to toggle LinearLayout visibility below-->
<RelativeLayout>
</RelativeLayout>
<!-- LinearLayout that has its visibility toggled -->
<LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
This entire layout is inserted programmatically into another LinearLayout (see below):
<LinearLayout
android:id="#+id/form_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<!-- This is where the previous XML layout containing the toggle-able LinearLayout
is inserted programmatically. -->
<!-- This button snaps back up to the top before the animation is complete. -->
<Button />
</LinearLayout>
I realize the problem would be solved if I added the Button that snaps up to the LinearLayout that has animateLayoutChanges as true. However, this isn't an options for a few reasons.
So is there any other work around?
Instead of using animateLayoutChanges try adding
TransitionManager.beginDelayedTransition(transitionsContainer); in your onClick method where transitionsContainer is parent of views that should be animated.
For example your parent layout is is
<LinearLayout android:id="#+id/transitions_container">
<!--add your widgets here-->
</LinearLayout>
And in code
final ViewGroup transitionsContainer = (ViewGroup) view.findViewById(R.id.transitions_container);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
TransitionManager.beginDelayedTransition(transitionsContainer);
// do your staff with changing children of transitionsContainer
}
});
Check https://medium.com/#andkulikov/animate-all-the-things-transitions-in-android-914af5477d50 for details.
Just a thought... What if you remove the 'animateLayoutChanges' from the embedded layout, and add it to the parent layout (second XML)? I suspect that this would animate everything. You may have to set the property to true in code since you're programmatically embedding the layout.
Here's how to do it programmatically
Stack-overflow
Another option would be to use the .animate property programmatically on the button that snaps back
myButton.animate().translationY(floatYposition).setDuration(300); //300 milliseconds
for linear layout try to manually enable 'changing' transition too
look at this for frame layout.. try that for your linear layout..
https://stackoverflow.com/a/51116293/2719243
Related
I have a fragment of this given layout hierarchy,
Inside the view pager I have a Edit text. When keyboard appears to type in the text to EditText the entire layout is not pushed up. Instead the contents inside ViewPager is pushed up. I want the entire content inside the Outer Linear Layout to be pushed up when keyboard appears.
How can I achieve this?
Thanks.
Put your Parent LinearLayout inside a scrollview. This fixed my issue.
put your base layout inside the ScrollView
<ScrollView
android:id="#+id/scrollView1"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="#+id/llPlayersName"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
// do here the layout work
</LinearLayout>
</ScrollView>
remember scrollView cannon be used as the base layout, so you have to put the scrollView inside the LinearLayout or RelativeLayout.
In your activity's manifest entry, add
<activity ...
android:windowSoftInputMode="adjustPan">
So the initial layout consists of a large circular "parent" button and multiple circular "child" buttons that are centered behind the parent button. So all the child buttons share the same center as the parent button. The reason for this layout is so during runtime, I can move the child buttons in and out of the parent button using translateX and translateY.
However, I'm stuck on the initial layout. How can I center the child buttons to the center of the parent button without hardcoding any child attributes?
Make the views the same size and add padding to the children so they get reduced. If the views are all in the same position the layout will look as you wish. Anyways, you can always change the properties in code.
I solved this myself using a container RelativeLayout as an anchor, with the parent button and all child buttons given android:layout_centerInParent. Then, to solve the issue of the child buttons disappearing when leaving the container, I gave the container android:clipChildren(false) and also set clipChildren to false on all of its ancestors as well.
Note that the container has to be bigger than all of its child elements, or all the child elements will be clipped to the same dimensions, even when they move outside of the container! To solve this, I gave the container a width and height of wrap_content.
Thus, all my child buttons were centered in the parent button no matter where I positioned the parent, and the child buttons were free to move around as well.
EDIT
A major flaw in this is that buttons can't recieve touch events if they are outside of their parent. To fix this, you can either use event coordinates or make the parent container big enough to always encompass the child elements (maybe twice the screen width/height?)
Here is the code:
res/layout/listfragment.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false" >
<ListView
android:id="#android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<RelativeLayout
android:onClick="onButterflyMenuClicked"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:layout_marginBottom="20sp"
android:layout_marginRight="15sp"
android:clipChildren="false" >
<Button
android:id="#+id/btn_north_1"
style="#style/PeekabooButton"
android:text="1st"
android:translationY="-65sp" />
<Button
android:id="#+id/btn_north_2"
style="#style/PeekabooButton"
android:text="2nd"
android:translationY="-115sp" />
<Button
android:id="#+id/kingbutton"
android:layout_width="65sp"
android:layout_height="65sp"
android:layout_centerInParent="true"
android:gravity="center_vertical|center_horizontal"
android:textSize="16sp"
android:text="KING" />
</RelativeLayout>
</FrameLayout>
res/values/styles.xml
<style name="PeekabooButton">
<item name="android:layout_width">45sp</item>
<item name="android:layout_height">45sp</item>
<item name="android:layout_centerInParent">true</item>
<item name="android:textSize">10sp</item>
</style>
Use android:gravity="center" on all views after putting them all inside a FrameLayout (possibly nesting the FrameLayout inside another layout). You can then offset each Button's position in its parent by changing the layout_margin* values. Or you could translate the parent FrameLayout that holds all the Buttons however you wish.
To make the button circular, change your button's android:background value to point to a custom selector.
I have a fragment containing several layout that I want to move the focus between. The app is operated with a remote containing a D-Pad (up,down,left,right & enter).
Both "view groups" are wrapped in a FrameLayout because the second one i overlapping the first one which is stretching the whole page. The views layout looks like this:
<FrameLayout android:id="contentSurfaceWrapper">
<HorizontalScrollView android:id="contentSurfaceScroll">
<LinearLayout android:id="contentSurface">
<!-- This layout is populated with child layouts (LinearLayout) programmatically -->
<!-- Those layouts are: clickable, focusable & focusableInTouchMode -->
</LinearLayout>
</HorizontalScrollView>
</FrameLayout>
<FrameLayout android:id="navButtonsWrapper">
<ScrollView android:id="navButtonsScroll">
<LinearLayout android:id="navButtons">
<!-- This layout is populated with child layouts (LinearLayout) programmatically -->
</LinearLayout>
</ScrollView>
</FrameLayout>
Image of how it looks:
I'm able to navigate to the view: contentSurface and between all its childs with the remote from the action bar in the top of the app. But, now I want to navigate from the first view (contentSurface) and its childs to the second view (navButtons) and its childs. But I doesn't seem to be able to move the focus some how. I want the focus to be moved when reaching bottom in the first layout and back when reaching top in the second layout.
I've tried to make the children in the second layout also clickable, focusable and focusableInTouch but it doesn't seem to work.
So.. I solved it this way:
For the first child in both views, which I append programmatically, I'm setting an ID.
This ID is then used with android:setNextFocusDownId on the items in last row in top layout and in android:setNextFocusUpId on items in bottom layout on first row.
This way I can switch focus in between the childs in both views.
More info about android:setNextFocusUpId etc.
http://developer.android.com/reference/android/view/View.html
I wanna put image in top of View and a listview bottom of it.
what's best and correct way?
LinearLayout?RelativeLayout?
and with which attribute?
layout_gravity="top"?
layout_alignParentTop="true"?
please give me a snipped code and a brief description about:
what's different between layout_gravity="top" and android:layout_alignParentTop="true"?
I wanna put image in top of View and a listview bottom of it. what's
best and correct way?
If you want to place a ListView below an ImageView positioned at the top of the current view then you could use both layouts, it isn't any real difference.
The layour_gravityis used to place the children relative within its parent bounds(the Relativelayout doesn't have this attribute). For example you could use a LinearLayout with orientation vertical which will stack your two children one on top of the other like you want. Also layout_gravity="top" is ignored for a vertical orientated LinearLayout as it doesn't make sense, so you could remove it from the layout completely:
<LinearLayout android:orientation="vertical">
<!-- the layout_gravity is useless int this case and could be removed-->
<ImageView android:layout_gravity="top"/>
<ListView />
</LinearLayout>
layout_alignParentTop is a placement rule for children of RelativeLayout(only for this type of layout!) which tells them to position aligning the top of the children with the top of the parent RelativeLayout. In this case, to stack the children you would do:
<RelativeLayout>
<!-- you could remove the layout_alignParentTop attribute because by default the Relativelayout will position it's children there -->
<ImageView android:id="#+id/imageId" android:layout_alingParentTop="true" />
<!-- Position this child below the other -->
<ListView android:layout_below="#id/imageId"/>
</RelativeLayout>
What I want to do is show a "frame" (or new layout) on top of "2" (second LinearLayout), when a button would be pressed. How should I do it? Precreate it and make it somehow hidden if button not pressed?
I have this type of layout:
XML:
<LinearLayout>
<LinearLayout>
</LinearLayout>
<LinearLayout>
//here would be another view, only shown when a button is clicked
<ViewFlipper>
</ViewFlipper>
</LinearLayout>
<RelativeLayout
</RelativeLayout>
</LinearLayout>
Use FrameLayout to show view over-lapping another view. You can keep the view as INVISIBLE or using GONE in the xml and then just make it visible when the Button is Clicked.
Yes...you should prepare it in xml and give it an id.then you can easily manage its visibility on button click using mLinearLayout.setVisibility(View.GONE); and mLinearLayout.setVisibility(View.VISIBLE); like:
Button mButton=(Button)findViewById(R.id.button);
LinearLayout ll=(LinearLayout)findViewById(R.id.frame_layout);
static int count=0;
mButton.setOnClick.... (new OnClick...()
public void onClick(){
count++;
if(count==1)
ll.setVisibility(View.VISIBLE);
else
{
count=0;
ll.setVisibility(View.GONE);
}
}
);
Here you have two options:
As you said pre-create layouts and set visibility to Visibility_Gone to layouts initially, not to be shown, set Visibitlity to View.Visible to display the layouts.
Another approach is to create views dynamically, and adding to parent on specified index, like to add on top of linearlayout use:
linearLayout.addView(view, 0);
If you want to show any view on button click then first put that view inside xml and make its visibility gone, and on button click make it visible. I have put imageview inside your code which visibility is set as gone so it wont show in layout.
<LinearLayout>
<LinearLayout>
</LinearLayout>
<LinearLayout>
//here would be another view, only shown when a button is clicked
<ImageView
android:id="#+id/image1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/icon"
android:visibility="gone" />
</LinearLayout>
<RelativeLayout
</RelativeLayout>
</LinearLayout>
For making image view visible,
imag1.seVisibility(View.VISIBLE);