I'm using android:windowSoftInputMode="stateHidden|adjustResize" to push the EditText and RecyclerView up when keyboard appears, but it only works on the EditText. RecyclerView stays in the same position (thus some elements are not visible). What am I doing wrong?
<?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"
tools:context="co.bla.bla.ChatActivity"
android:id="#+id/chat_root">
<include android:id="#+id/toolbar" layout="#layout/toolbar"/>
<android.support.v7.widget.RecyclerView
android:id="#+id/chat_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="#+id/message_input_wrapper"
android:scrollbars="vertical"
android:paddingBottom="20dp"
android:layout_below="#id/toolbar"
/>
<LinearLayout
android:id="#+id/message_input_wrapper"
android:layout_width="match_parent"
android:layout_height="60dp"
android:padding="6dp"
android:orientation="horizontal"
android:weightSum="4"
android:background="#android:color/white"
android:layout_alignParentBottom="true">
<EditText
android:id="#+id/message_input"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:hint="#string/chat_input_hint"
android:layout_gravity="center_vertical"
android:layout_weight="3"
android:background="#android:color/transparent"/>
<Button
android:id="#+id/message_send_button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="#string/chat_button_text"
android:layout_weight="1"
android:onClick="onButtonClicked"/>
</LinearLayout>
</RelativeLayout>
I don't know how adjustResize exactly works, but I assume when using android:layout_above in this case, the RecyclerView and LinearLayout "stick" together and should be pushed up together?
In your activity manifest:
android:windowSoftInputMode="adjustResize"
Then add an OnLayoutChangeListener to yout recyclerView:
recyclerView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
#Override
public void onLayoutChange(View v, int left, int top, int right,int bottom, int oldLeft, int oldTop,int oldRight, int oldBottom)
{
recyclerView.scrollToPosition(recyclerView.getAdapter().getItemCount()-1);
}
});
This works for me :)
set a soft keyboard listener:
private boolean mLastKeyBoardVisible = false;
private void addOnSoftKeyBoardVisibleListener(final OnSoftKeyBoardVisibleListener listener) {
final View decorView = getWindow().getDecorView();
decorView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
Rect rect = new Rect();
decorView.getWindowVisibleDisplayFrame(rect);
int displayHight = rect.bottom - rect.top;
int hight = decorView.getHeight();
boolean visible = (double) displayHight / hight < 0.8;
if(visible != mLastKeyBoardVisible){
listener.onSoftKeyBoardVisible(visible);
}
mLastKeyBoardVisible = visible;
}
});
}
private OnSoftKeyBoardVisibleListener onSoftKeyBoardVisibleListener = new OnSoftKeyBoardVisibleListener() {
#Override
public void onSoftKeyBoardVisible(boolean visible) {
scrollToBottom(visible);
}
};
synchronized private void scrollToBottom(boolean visible) {
if (visible) {
if (mMessageList.size() != messageAdapter.getItemCount() && mMessageList.size() > 0) {
messageAdapter.notifyDataSetChanged();
messageListView.scrollToPosition(mMessageList.size() - 1);
} else if (mMessageList.size() > 0) {
messageListView.scrollToPosition(mMessageList.size() - 1);
}
}
}
Related
I know that this question has been asked many times, but the answers doesn't work for me. I am trying to use Horizontal placement. Here is my code:
public class CalendarDaysAdapter extends RecyclerView.Adapter<CalendarDaysAdapter.MyViewHolder> {
private ArrayList<String> list;
public CalendarDaysAdapter(ArrayList<String> list)
{
this.list = list;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.fragment_calendar_days_item, parent, false);
return new MyViewHolder(itemView);
}
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
String day = list.get(position);
holder.daystxt.setText(day);
}
#Override
public int getItemCount() {
return list.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder {
public TextView daystxt;
public MyViewHolder(View view) {
super(view);
daystxt = (TextView) view.findViewById(R.id.daystxt);
}
}
}
fragment_calendar_days_item xml:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="50dp"
android:gravity="center">
<TextView
android:id="#+id/daystxt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="MON"
android:textSize="20sp"/>
</RelativeLayout>
</LinearLayout>
I tried every combination of wrap_content - match_parent, also on the RecyclerView xml in parent Activity, but only the first item is showing. I have used breakpoints to see if the data of the list are there, and they are.
So what I am missing ?
Change your fragment_calendar_days_item height and width to android:layout_height="wrap_content" and android:layout_width="wrap_content"
it will solve your issue
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="50dp"
android:gravity="center">
<TextView
android:id="#+id/daystxt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="MON"
android:textSize="20sp"/>
</RelativeLayout>
</LinearLayout>
Try this for your
fragment_calendar_days_item xml:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="50dp"
android:gravity="center">
<TextView
android:id="#+id/daystxt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="MON"
android:textSize="20sp"/>
</RelativeLayout>
</LinearLayout>
I think what you want to do is show that "n" elements and the rest must be scrollable.
The solution of setting the hard value is not the best. it's not generic. I think that my solution will fit very well in any case. ;-)
For that I propose you a solution
First determine and create a MAX_ITEMS variable
Kotlin
recycler.addOnLayoutChangeListener { v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom ->
if (recycler.layoutManager.itemCount > maxItemVisible) {
val height = (0 until maxItemVisible).sumBy { recycler.layoutManager.findViewByPosition(it).height }
recycler.layoutParams = LayoutParams(recycler.width, height)
}
}
Java
mRecycler.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
#Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
if (mRecycler.getLayoutManager().getItemCount() > maxItemVisible) {
int height = 0;
for (int i = 0; i < maxItemVisible; i++){
height += mRecycler.getLayoutManager().findViewByPosition(i).getHeight()
}
mRecycler.setLayoutParams(new LinearLayout.LayoutParams(mRecycler.getWidth(), height));
}
}
});
Hoping to have answered your need
I have a working CollapsingToolbarLayout the only problem I am seeing is that the content being shown when expanded dissapears too quickly when scrolling down and was wondering if it possible to define at what point of the road the content should dissapear and the appbar appear. It seems like after collalsing ~25% it already hides the content and only shows the color of the appbar. In the Google Play App you can see that this happens really late when almost collapsing all.
i would give you and example of how i achieved what you need.
Since you want the content to start dessapearing after for example 60%, first, declare a variable like this
private static final int PERCENTAGE_TO_SHOW_ELEMENT = 60;
Then you have to declare a variable to know if your element have been hidden already and a variable to track the scroll percentage
private int mMaxScrollSize;
private boolean mIsElementHidden;
After that, you have to add to your appBarLayout the listener called addOnOffsetChangedListener like this and override the method onOffsetChanged:
yourAppBar.addOnOffsetChangedListener(this);
Inside the method onOffsetChanged, use this code:
#Override
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
if (mMaxScrollSize == 0)
mMaxScrollSize = appBarLayout.getTotalScrollRange();
int currentScrollPercentage = (Math.abs(verticalOffset)) * 100
/ mMaxScrollSize;
if (currentScrollPercentage >= PERCENTAGE_TO_SHOW_ELEMENT) {
if (!mIsElementHidden) {
mIsElementHidden= true;
ViewCompat.animate(yourView).scaleY(0).scaleX(0).start();
ViewCompat.animate(anotherView).scaleY(0).scaleX(0).start();
}
}
if (currentScrollPercentage < PERCENTAGE_TO_SHOW_ELEMENT) {
if (mIsElementHidden) {
mIsElementHidden= false;
ViewCompat.animate(yourView).scaleY(1).scaleX(1).start();
ViewCompat.animate(anotherView).scaleY(1).scaleX(1).start();
}
}
} else if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
//You can change something if your layout is different in LANDSCAPE
}
}
You can play with the variable PERCENTAGE_TO_SHOW_ELEMENT to decide when to make your view(s) appear or dissapear.
I found the solution. You don't obligatory need java code for this, you can define this with the style property scrimVisibleHeightTrigger but take in mind that the used value should be major than the size of the actionbar, sadly using ?acionBarSize did not work, so you must take into account the height of the appbar and add some DPs to it.
<android.support.design.widget.CollapsingToolbarLayout
android:id="#+id/collapsing_toolbar"
style="#style/Widget.MyCustomWidget.CollapsingHeader"
<style name="Widget.MyCustomWidget.CollapsingHeader" parent="#style/Widget.Design.CollapsingToolbar">
<item name="scrimAnimationDuration">200</item>
<item name="scrimVisibleHeightTrigger">1dp</item>
</style>
Create a class which implements AppBarLayout.OnOffsetChangedListener and override the onOffsetChanged method
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:ignore="RtlHardcoded"
>
<android.support.design.widget.AppBarLayout
android:id="#+id/main.appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"
>
<android.support.design.widget.CollapsingToolbarLayout
android:id="#+id/main.collapsing"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
>
<ImageView
android:id="#+id/main.imageview.placeholder"
android:layout_width="match_parent"
android:layout_height="300dp"
android:scaleType="centerCrop"
android:src="#drawable/quila2"
android:tint="#11000000"
app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="0.9"
/>
<FrameLayout
android:id="#+id/main.framelayout.title"
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_gravity="bottom|center_horizontal"
android:background="#color/primary"
android:orientation="vertical"
app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="0.3"
>
<LinearLayout
android:id="#+id/main.linearlayout.title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="vertical"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:gravity="bottom|center"
android:text="#string/quila_name"
android:textColor="#android:color/white"
android:textSize="30sp"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="4dp"
android:text="#string/quila_tagline"
android:textColor="#android:color/white"
/>
</LinearLayout>
</FrameLayout>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v7.widget.Toolbar
android:id="#+id/main.toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="#color/primary"
app:layout_anchor="#id/main.framelayout.title"
app:theme="#style/ThemeOverlay.AppCompat.Dark"
app:title=""
>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal"
>
<Space
android:layout_width="#dimen/image_final_width"
android:layout_height="#dimen/image_final_width"
/>
<TextView
android:id="#+id/main.textview.title"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginLeft="8dp"
android:gravity="center_vertical"
android:text="#string/quila_name2"
android:textColor="#android:color/white"
android:textSize="20sp"
/>
</LinearLayout>
</android.support.v7.widget.Toolbar>
</android.support.design.widget.CoordinatorLayout>
Change the PERCENTAGE_TO_SHOW_TITLE_AT_TOOLBAR and PERCENTAGE_TO_HIDE_TITLE_DETAILS to get the desired effect.
public class MainActivity extends AppCompatActivity implements AppBarLayout.OnOffsetChangedListener {
private static final float PERCENTAGE_TO_SHOW_TITLE_AT_TOOLBAR = 0.9f;
private static final float PERCENTAGE_TO_HIDE_TITLE_DETAILS = 0.3f;
private static final int ALPHA_ANIMATIONS_DURATION = 200;
private boolean mIsTheTitleVisible = false;
private boolean mIsTheTitleContainerVisible = true;
private LinearLayout mTitleContainer;
private TextView mTitle;
private AppBarLayout mAppBarLayout;
private Toolbar mToolbar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bindActivity();
mAppBarLayout.addOnOffsetChangedListener(this);
mToolbar.inflateMenu(R.menu.menu_main);
startAlphaAnimation(mTitle, 0, View.INVISIBLE);
}
private void bindActivity() {
mToolbar = (Toolbar) findViewById(R.id.main_toolbar);
mTitle = (TextView) findViewById(R.id.toolbar_title);
mTitleContainer = (LinearLayout) findViewById(R.id.linearlayout_title);
mAppBarLayout = (AppBarLayout) findViewById(R.id.appbar);
}
#Override
public void onOffsetChanged(AppBarLayout appBarLayout, int offset) {
int maxScroll = appBarLayout.getTotalScrollRange();
float percentage = (float) Math.abs(offset) / (float) maxScroll;
handleAlphaOnTitle(percentage);
handleToolbarTitleVisibility(percentage);
}
private void handleAlphaOnTitle(float percentage) {
if (percentage >= PERCENTAGE_TO_HIDE_TITLE_DETAILS) {
if(mIsTheTitleContainerVisible) {
startAlphaAnimation(mTitleContainer, ALPHA_ANIMATIONS_DURATION, View.INVISIBLE);
mIsTheTitleContainerVisible = false;
}
} else {
if (!mIsTheTitleContainerVisible) {
startAlphaAnimation(mTitleContainer, ALPHA_ANIMATIONS_DURATION, View.VISIBLE);
mIsTheTitleContainerVisible = true;
}
}
}
private void handleToolbarTitleVisibility(float percentage) {
if (percentage >= PERCENTAGE_TO_SHOW_TITLE_AT_TOOLBAR) {
if(!mIsTheTitleVisible) {
startAlphaAnimation(mTitle, ALPHA_ANIMATIONS_DURATION, View.VISIBLE);
mIsTheTitleVisible = true;
}
} else {
if (mIsTheTitleVisible) {
startAlphaAnimation(mTitle, ALPHA_ANIMATIONS_DURATION, View.INVISIBLE);
mIsTheTitleVisible = false;
}
}
}
public static void startAlphaAnimation (View v, long duration, int visibility) {
AlphaAnimation alphaAnimation = (visibility == View.VISIBLE) ? new AlphaAnimation(0f, 1f) : new AlphaAnimation(1f, 0f);
alphaAnimation.setDuration(duration);
alphaAnimation.setFillAfter(true);
v.startAnimation(alphaAnimation);
}
}
I have a "details" fragment which have a lot of textviews, relativelayouts etc. These are wrapped inside a NestedScrollView:
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?android:attr/windowBackground"
android:orientation="vertical"
android:paddingBottom="10dp">
<android.support.v4.widget.NestedScrollView
android:id="#+id/movie_details_scroll"
android:layout_width="match_parent"
android:layout_height="match_parent">
// Here are the textviews, relativelayouts etc...
</android.support.v4.widget.NestedScrollView>
<android.support.design.widget.FloatingActionButton
android:id="#+id/edit_movies_fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="#dimen/fab_margin"
android:src="#drawable/ic_edit_white_24dp"
/>
</android.support.design.widget.CoordinatorLayout>
Now i want to to add a FAB at the bottom of the screen (not at the bottom of the nestedscrollview) which also scroll down when i scroll through the nestedscrollview. But with my code the FAB is always at the bottom of the nestedscrollview. So when i scroll all the way down the FAB appears. I want that the FAB is always visible in the right bottom corner...
EDIT
I forgot to mention that i use fading action bar (https://github.com/ManuelPeinado/FadingActionBar) but a bit edited.
Relevant code:
m_FadingActionBarHelper.createView(getContext()); // this will create the view with header content etc.
The createView:
public final View createView(LayoutInflater inflater) {
//
// Prepare everything
mInflater = inflater;
if (mContentView == null) {
mContentView = inflater.inflate(mContentLayoutResId, null); // this will load my view which i already posted.
}
if (mHeaderView == null) {
mHeaderView = inflater.inflate(mHeaderLayoutResId, null, false);
}
// See if we are in a ListView, WebView or ScrollView scenario
ListView listView = (ListView) mContentView.findViewById(android.R.id.list);
View root;
if (listView != null) {
root = createListView(listView);
} else if (mContentView instanceof CDMObservableWebViewWithHeader){
root = createWebView();
} else {
root = createScrollView(); // this will be called in my example
}
if (mHeaderOverlayView == null && mHeaderOverlayLayoutResId != 0) {
mHeaderOverlayView = inflater.inflate(mHeaderOverlayLayoutResId, mMarginView, false);
}
if (mHeaderOverlayView != null) {
mMarginView.addView(mHeaderOverlayView);
}
// Use measured height here as an estimate of the header height, later on after the layout is complete
// we'll use the actual height
int widthMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.EXACTLY);
int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.EXACTLY);
mHeaderView.measure(widthMeasureSpec, heightMeasureSpec);
updateHeaderHeight(mHeaderView.getMeasuredHeight());
root.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
int headerHeight = mHeaderContainer.getHeight();
if ((!mFirstGlobalLayoutPerformed || (headerHeight != mLastHeaderHeight)) && headerHeight != 0) {
updateHeaderHeight(headerHeight);
mFirstGlobalLayoutPerformed = true;
}
}
});
return root;
}
The createScrollView:
private View createScrollView() {
ViewGroup scrollViewContainer = (ViewGroup) mInflater.inflate(R.layout.fab__scrollview_container, null);
CDMObservableScrollView scrollView = (CDMObservableScrollView) scrollViewContainer.findViewById(R.id.fab__scroll_view);
scrollView.setOnScrollChangedCallback(mOnScrollChangedListener);
ViewGroup contentContainer = (ViewGroup) scrollViewContainer.findViewById(R.id.fab__container);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
mContentView.setLayoutParams(layoutParams);
contentContainer.addView(mContentView);
mHeaderContainer = (FrameLayout) scrollViewContainer.findViewById(R.id.fab__header_container);
initializeGradient(mHeaderContainer);
mHeaderContainer.addView(mHeaderView, 0);
mMarginView = (FrameLayout) contentContainer.findViewById(R.id.fab__content_top_margin);
return scrollViewContainer;
}
The xml which will be loaded:
<denis.de.meperdia.fadingactionbar.CDMRootLayout
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">
<include layout="#layout/fab__header_container"/>
<denis.de.meperdia.fadingactionbar.CDMObservableScrollView
android:id="#+id/fab__scroll_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="#+id/fab__container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<FrameLayout
android:id="#+id/fab__content_top_margin"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#android:color/transparent"/>
</LinearLayout>
</denis.de.meperdia.fadingactionbar.CDMObservableScrollView>
</denis.de.meperdia.fadingactionbar.CDMRootLayout>
The class CDMRootLayout:
public class CDMRootLayout extends CoordinatorLayout {
private View mHeaderContainer;
private View mListViewBackground;
private boolean mInitialized = false;
public CDMRootLayout(Context context) {
super(context);
}
public CDMRootLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CDMRootLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
//at first find headerViewContainer and listViewBackground
if(mHeaderContainer == null)
mHeaderContainer = findViewById(R.id.fab__header_container);
if(mListViewBackground == null)
mListViewBackground = findViewById(R.id.fab__listview_background);
//if there's no headerViewContainer then fallback to standard FrameLayout
if(mHeaderContainer == null) {
super.onLayout(changed, left, top, right, bottom);
return;
}
if(!mInitialized) {
super.onLayout(changed, left, top, right, bottom);
//if mListViewBackground not exists or mListViewBackground exists
//and its top is at headercontainer height then view is initialized
if(mListViewBackground == null || mListViewBackground.getTop() == mHeaderContainer.getHeight())
mInitialized = true;
return;
}
//get last header and listViewBackground position
int headerTopPrevious = mHeaderContainer.getTop();
int listViewBackgroundTopPrevious = mListViewBackground != null ? mListViewBackground.getTop() : 0;
//relayout
super.onLayout(changed, left, top, right, bottom);
//revert header top position
int headerTopCurrent = mHeaderContainer.getTop();
if(headerTopCurrent != headerTopPrevious) {
mHeaderContainer.offsetTopAndBottom(headerTopPrevious - headerTopCurrent);
}
//revert listViewBackground top position
int listViewBackgroundTopCurrent = mListViewBackground != null ? mListViewBackground.getTop() : 0;
if(listViewBackgroundTopCurrent != listViewBackgroundTopPrevious) {
mListViewBackground.offsetTopAndBottom(listViewBackgroundTopPrevious - listViewBackgroundTopCurrent);
}
}
}
And the class CDMObservableScrollView:
public class CDMObservableScrollView extends ScrollView implements CDMObservableScrollable {
// Edge-effects don't mix well with the translucent action bar in Android 2.X
private boolean mDisableEdgeEffects = true;
private CDMOnScrollChangedCallback mOnScrollChangedListener;
public CDMObservableScrollView(Context context) {
super(context);
}
public CDMObservableScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CDMObservableScrollView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
if (mOnScrollChangedListener != null) {
mOnScrollChangedListener.onScroll(l, t);
}
}
#Override
protected float getTopFadingEdgeStrength() {
// http://stackoverflow.com/a/6894270/244576
if (mDisableEdgeEffects && Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
return 0.0f;
}
return super.getTopFadingEdgeStrength();
}
#Override
protected float getBottomFadingEdgeStrength() {
// http://stackoverflow.com/a/6894270/244576
if (mDisableEdgeEffects && Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
return 0.0f;
}
return super.getBottomFadingEdgeStrength();
}
#Override
public void setOnScrollChangedCallback(CDMOnScrollChangedCallback callback) {
mOnScrollChangedListener = callback;
}
}
EDIT 2
I can delimit the problem now:
If i these lines the FAB works as i want:
<denis.de.meperdia.fadingactionbar.CDMObservableScrollView
android:id="#+id/fab__scroll_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
But then the synchonization of my fading action bar is destroyed...
Sorry for that much code but it's really complicated to understand without this.
Import the app namespace, surround the NestedScrollView with a RelativeLayout and then set the RelativeLayout as anchor for FAB.
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" //Import app namespace
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?android:attr/windowBackground"
android:orientation="vertical"
android:paddingBottom="10dp">
<android.support.v4.widget.NestedScrollView
android:id="#+id/mainview"
android:layout_width="match_parent"
android:layout_height="match_parent">
// Here are the textviews, relativelayouts etc...
</android.support.v4.widget.NestedScrollView>
<android.support.design.widget.FloatingActionButton
android:id="#+id/edit_movies_fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="#dimen/fab_margin"
android:src="#drawable/ic_edit_white_24dp"
app:layout_anchor="#id/mainview" //attributes of app namespace
app:layout_anchorGravity="bottom|end"
/>
</android.support.design.widget.CoordinatorLayout>
Replace android:layout_gravity="bottom|end"
with this android:layout_gravity="bottom|right"
Add below line in NestedScrollView.
app:layout_behavior="#string/appbar_scrolling_view_behavior"
You can easily do it with Coordinate Layout anchor property to attach your fab to any of your view node
CoordinatorLayout and use the layout_anchor and layout_anchorGravity attributes.
<ListView
android:id="#+id/lvToDoList"
android:layout_width="match_parent"
android:layout_height="match_parent"></ListView>
<android.support.design.widget.FloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:layout_margin="16dp"
android:src="#drawable/ic_done"
app:layout_anchor="#id/lvToDoList"
app:layout_anchorGravity="bottom|right|end" />
This will make FAB to aatch to list view at bottom. You can do same with any other layout/View.
Finally i solved this problem by moving the FloatingActionButton from the content layout to the outside.
My container layout looks like this:
<?xml version="1.0" encoding="utf-8"?>
<denis.de.meperdia.fadingactionbar.CDMRootLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="#layout/fab__header_container"/>
<denis.de.meperdia.fadingactionbar.CDMObservableScrollView
android:id="#+id/fab__scroll_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="#+id/fab__container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<FrameLayout
android:id="#+id/fab__content_top_margin"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#android:color/transparent"/>
</LinearLayout>
</denis.de.meperdia.fadingactionbar.CDMObservableScrollView>
<android.support.design.widget.CoordinatorLayout
android:id="#+id/fab__floating_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.design.widget.CoordinatorLayout>
</denis.de.meperdia.fadingactionbar.CDMRootLayout>
I added a container for the FloatingActionButton which i fill dynamically by loading it from another file. The moving problem of the FloatingActionButton is solved now. There's a little other problem but i opened a new question for this.
EDIT
Changed my solution. I had the problem that if i want to show a snackbar, the FloatingActionButton didn't scroll correctly. I add the FloatingActionButton now programmatically to the root view. Now it works correctly.
try this example:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.internet.Main2Activity">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="#style/AppTheme.PopupOverlay" />
</android.support.design.widget.AppBarLayout>
<include
layout="#layout/content_main2"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<android.support.design.widget.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="#dimen/fab_margin"
app:srcCompat="#android:drawable/ic_dialog_email" />
</android.support.design.widget.CoordinatorLayout>
content_main2.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:context="com.internet.Main2Activity"
tools:showIn="#layout/activity_main2">
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:text="asdds" />
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:text="asdds" />
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:text="asdds" />
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:text="asdds" />
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:text="asdds" />
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:text="asdds" />
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:text="asdds" />
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:text="asdds" />
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:text="asdds" />
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:text="asdds" />
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
</LinearLayout>
I am looking to slide/up down a nested layout on its parent layout click.
Ie the parent layout will have a hidden child. On click I would like the parents height to animate down (slide down) to fit the child layout. On click again I would like the child to animate up (slide up). Basically just animating the parents height to show/hide the child.
I have found this which looks to work but seems like a lot of code:
http://gmariotti.blogspot.com/2013/09/expand-and-collapse-animation.html
I have seen a lot of things using 'animateLayoutChanges' to animate things however I cannot get that to work.
I have tried this:
<LinearLayout android:id="#+id/parent"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView android:id="#+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<LinearLayout android:id="#+id/child"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
android:animateLayoutChanges="true">
<TextView android:id="#+id/message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Some text to show/hide"/>
</LinearLayout>
</LinearLayout>
Then in code:
LinearLayout parent = (LinearLayout)findViewById(R.id.parent);
parent.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
LinearLayout child = (LinearLayout)findViewById(R.id.child);
child.setVisibility(child.getVisibility() == View.VISIBLE ? View.GONE : View.VISIBLE);
}
});
That sets the visibility of the child view correctly but there is absolutely no animation.
Well, first of all android:animateLayoutChanges effects the child elements. So, obviously, if you are changing the properties of the element itself, it will not be animated.
I think you can accomplish what you are trying to in API 16 by enabling the LayoutTransition.CHANGING animation.
<LinearLayout android:id="#+id/parent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:animateLayoutChanges="true">
<TextView android:id="#+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Title"/>
<TextView android:id="#+id/message"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:text="Some text to show/hide"/>
</LinearLayout>
LinearLayout parent = (LinearLayout)findViewById(R.id.parent);
parent.getLayoutTransition().enableTransitionType(LayoutTransition.CHANGING);
View text = findViewById(R.id.text);
text.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
View message = findViewById(R.id.message);
ViewGroup.LayoutParams params = message.getLayoutParams();
params.height = params.height == 0 ? ViewGroup.LayoutParams.WRAP_CONTENT : 0;
message.setLayoutParams(params);
}
});
Try to use SlidingDrawer
use this code
xml layout sideupdown.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<Button
android:id="#+id/bopen"
android:layout_width="90sp"
android:layout_height="wrap_content"
android:text="open" />
<Button
android:id="#+id/btogg"
android:layout_width="90sp"
android:layout_height="wrap_content"
android:text="change" />
<Button
android:id="#+id/bclose"
android:layout_width="90sp"
android:layout_height="wrap_content"
android:text="close" />
</LinearLayout>
<SlidingDrawer
android:id="#+id/slidingDrawer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:content="#+id/content"
android:handle="#+id/handle" >
<Button
android:id="#+id/handle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Handle" />
<LinearLayout
android:id="#+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<CheckBox
android:id="#+id/chkbok"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="false"
android:text="On/Off" />
</LinearLayout>
</SlidingDrawer>
</FrameLayout>
java class SlideUpDown.java
public class SlideUpDown extends Activity implements OnClickListener,
OnCheckedChangeListener, OnDrawerOpenListener, OnDrawerCloseListener {
Button opn, cloz, chng, hndl;
CheckBox chkbox;
SlidingDrawer sd;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.sideupdown);
refference();
opn.setOnClickListener(this);
cloz.setOnClickListener(this);
chng.setOnClickListener(this);
chkbox.setOnCheckedChangeListener(this);
sd.setOnDrawerOpenListener(this);
sd.setOnDrawerCloseListener(this);
}
private void refference() {
opn = (Button) findViewById(R.id.bopen);
cloz = (Button) findViewById(R.id.bclose);
chng = (Button) findViewById(R.id.btogg);
chkbox = (CheckBox) findViewById(R.id.chkbok);
sd = (SlidingDrawer) findViewById(R.id.slidingDrawer);
hndl = (Button) findViewById(R.id.handle);
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.bopen:
sd.open();
break;
case R.id.bclose:
sd.close();
break;
case R.id.btogg:
sd.toggle();
break;
}
}
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (chkbox.isChecked()) {
sd.lock();
hndl.setEnabled(false);
} else {
sd.unlock();
hndl.setEnabled(true);
}
}
#Override
public void onDrawerOpened() {
}
#Override
public void onDrawerClosed() {
}
#Override
protected void onDestroy() {
super.onDestroy();
}
}
In one of our applications we hide and show a header and footer. We do this by changing the height and visibility of the view.
It looks something like this
ValueAnimator va;
if (show)
va = ValueAnimator.ofInt(0, px);
else
va = ValueAnimator.ofInt(px, 0);
va.setDuration(400);
va.setInterpolator(new DecelerateInterpolator(2));
va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
public void onAnimationUpdate(ValueAnimator animation) {
Integer value = (Integer) animation.getAnimatedValue();
topicNavBar.getLayoutParams().height = value;
topicNavBar.requestLayout();
if (value == 0) {
if (show)
topicNavBar.setVisibility(View.VISIBLE);
else
topicNavBar.setVisibility(View.GONE);
}
if (show && value == px) {
animationInProgress = false;
}
if (!show && value == 0) {
animationInProgress = false;
}
}
});
va.start();
Hope this helps
Sorry for my English... I will try to explain what I want to do.
I have a project. It can be downloaded at the link:
https://drive.google.com/file/d/0Bxhi0uFKK3upcXJjNGtMVkg4TDQ/view?usp=sharing
As you can see the screenshot:
http://pixs.ru/showimage/Screenshot_9509352_15647059.png
The button "Hide/Show B layout" hides and shows the green container - "B layout". I want add animation top down when the container "B layout" is showing. And the animation from the bottom up when the container is hidden. Also, I want the blue container "C", gradually fell together with the container "B". And rising smoothly, together with the container "B". Please help me to do it.
Below duplicate my code:
MainActivity
public class MainActivity extends Activity {
View Layout;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Layout = findViewById(R.id.bLayout);
final View button2 = findViewById (R.id.button);
button2.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick (View v){
if ((Layout.getVisibility() == View.VISIBLE))
{
Layout.setVisibility(View.GONE);
}
else
{
// Animation animFadeIn = AnimationUtils.loadAnimation(getApplicationContext(), android.R.anim.slide_in_left);
// Layout.setAnimation(animFadeIn);
Layout.setVisibility(View.VISIBLE);
}
}
});
}
}
I found a solution to the problem. Full lesson and source code can be downloaded here: click here
Or use the code below:
activity_main.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="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<LinearLayout
android:id="#+id/header"
android:layout_width="match_parent"
android:layout_height="64dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginTop="16dp"
android:background="#FCF"
android:orientation="horizontal" >
<TextView
android:id="#+id/color"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
android:layout_marginTop="8dp"
android:background="#drawable/rectangle"
android:fontFamily="sans-serif-light"
android:gravity="center_vertical"
android:text=""
android:textAlignment="center"
android:textStyle="bold" />
<TextView
android:id="#+id/clickme"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="4dp"
android:fontFamily="sans-serif-light"
android:gravity="center_vertical"
android:text="click_here"
android:textStyle="bold" />
</LinearLayout>
<LinearLayout
android:id="#+id/expandable"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:background="#FFF"
android:orientation="vertical"
android:paddingLeft="4dp" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="text1" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="text2" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Слуга: text3" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="text4" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="text5" />
</LinearLayout>
MainActivity.java
public class MainActivity extends Activity {
LinearLayout mLinearLayout;
LinearLayout mLinearLayoutHeader;
ValueAnimator mAnimator;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setTitle("title");
mLinearLayout = (LinearLayout) findViewById(R.id.expandable);
// mLinearLayout.setVisibility(View.GONE);
mLinearLayoutHeader = (LinearLayout) findViewById(R.id.header);
// Add onPreDrawListener
mLinearLayout.getViewTreeObserver().addOnPreDrawListener(
new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
mLinearLayout.getViewTreeObserver()
.removeOnPreDrawListener(this);
mLinearLayout.setVisibility(View.GONE);
final int widthSpec = View.MeasureSpec.makeMeasureSpec(
0, View.MeasureSpec.UNSPECIFIED);
final int heightSpec = View.MeasureSpec
.makeMeasureSpec(0,
View.MeasureSpec.UNSPECIFIED);
mLinearLayout.measure(widthSpec, heightSpec);
mAnimator = slideAnimator(0,
mLinearLayout.getMeasuredHeight());
return true;
}
});
mLinearLayoutHeader.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mLinearLayout.getVisibility() == View.GONE) {
expand();
} else {
collapse();
}
}
});
}
private void expand() {
// set Visible
mLinearLayout.setVisibility(View.VISIBLE);
mAnimator.start();
}
private void collapse() {
int finalHeight = mLinearLayout.getHeight();
ValueAnimator mAnimator = slideAnimator(finalHeight, 0);
mAnimator.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationEnd(Animator animator) {
// Height=0, but it set visibility to GONE
mLinearLayout.setVisibility(View.GONE);
}
#Override
public void onAnimationStart(Animator animator) {
}
#Override
public void onAnimationCancel(Animator animator) {
}
#Override
public void onAnimationRepeat(Animator animator) {
}
});
mAnimator.start();
}
private ValueAnimator slideAnimator(int start, int end) {
ValueAnimator animator = ValueAnimator.ofInt(start, end);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
// Update Height
int value = (Integer) valueAnimator.getAnimatedValue();
ViewGroup.LayoutParams layoutParams = mLinearLayout
.getLayoutParams();
layoutParams.height = value;
mLinearLayout.setLayoutParams(layoutParams);
}
});
return animator;
}
}
I faced a similar issue and this is the easiest solution I could find:
setVisibility(View.GONE) on the view you wish to hide.
And make sure in the xml layout the parent has following attribute:
android:animateLayoutChanges="true"
I think you can easily do this by using the AlphaAnimation class. Here is a similar question with an answer.
So I think what you're looking for is how to hook up translate animations to show/hide a view as opposed to just setting the visibility instantly.
Take a look at Show and hide a View with a slide up/down animation. Instead of just setting the visibility, first you run the translate animations, then add the hooks to show or hide the view after they're finished.
If you find that the bottom view is not moving, jump into your Android developer options and enable "Show layout bounds" then you can see the borders for views (animations don't move the actual view bounds). To get the bottom view to animate as well it will also need an translate animation.