So, situation is this:
I need to implement AppBar scroll behaviour in my main activity, but, I already have CoordinatorLayout and AppBarLayout in my fragment with the same scroll behaviour.
Here is the xml from both of the layouts:
activity_main:
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#EBEDEC">
<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/ThemeOverlay.AppCompat.Light">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/toolbar_open_nav"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:src="#drawable/filter_icon" />
<RelativeLayout
android:id="#+id/main_activity_images_relative"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/toolbar_fencity_image"
android:layout_width="200dp"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:layout_margin="#dimen/layout_padding"
android:src="#drawable/toolbarimg"
android:visibility="gone" />
</RelativeLayout>
</RelativeLayout>
</android.support.v7.widget.Toolbar>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<FrameLayout
android:id="#+id/main_content"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#android:color/transparent" />
<com.bitage.carlo.fencity.ui.view.BottomMenuView
android:id="#+id/bottom_menu"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" />
</LinearLayout>
</RelativeLayout>
and a fragment 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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="?attr/actionBarSize"
android:orientation="vertical">
<android.support.design.widget.AppBarLayout
android:id="#+id/novita_app_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout
android:id="#+id/novita_search_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/background"
app:layout_scrollFlags="scroll|enterAlways|snap">
<EditText
android:id="#+id/search_edit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="#dimen/layout_padding"
android:background="#null"
android:hint="#string/search"
android:imeOptions="actionDone"
android:paddingEnd="#dimen/layout_padding"
android:paddingLeft="#dimen/padding_start"
android:paddingRight="#dimen/layout_padding"
android:paddingStart="#dimen/padding_start"
android:singleLine="true" />
<ImageView
android:id="#+id/search_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="#dimen/layout_padding"
android:layout_marginStart="#dimen/layout_padding"
android:src="#drawable/ic_search" />
</RelativeLayout>
</android.support.design.widget.AppBarLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<android.support.v7.widget.RecyclerView
android:id="#+id/places_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="#android:color/transparent"
android:src="#drawable/nav_shadow" />
</RelativeLayout>
</android.support.design.widget.CoordinatorLayout>
Now, I need this to stay the same if possible, just somehow to add the scroll behavior app:layout_scrollFlags="scroll|enterAlways|snap" on toolbar only in this fragment, while search from the fragment still has the same behaviour.
How can I achieve this?
So, you can do next:
in your Fragment class, you have recyclerview. Now, what you want to do is put the recyclerView.addOnScrollListener(new YourScrollListenerClass(context, toolbar, coordinatorLayout));
Coordinator layout is the one of the fragment, please bear that in mind.
Now, create a new class YourScrollListenerClass:
public class YourScrollListenerClass extends RecyclerView.OnScrollListener {
private Context mContext;
private Toolbar mToolbar;
private CoordinatorLayout mCoordinatorLayout;
private int mToolbarHeight;
private int mCoordinatorLayoutTopMargin;
public YourScrollListenerClass(Context context, #Nullable Toolbar toolbar, #Nullable final CoordinatorLayout mCoordinatorLayout) {
this.mContext = context;
mToolbar = toolbar;
this.mCoordinatorLayout = mCoordinatorLayout;
if (mToolbar != null && mCoordinatorLayout != null) {
mToolbar.post(new Runnable() {
#Override
public void run() {
mToolbarHeight = mToolbar.getHeight();
}
});
mCoordinatorLayout.post(new Runnable() {
#Override
public void run() {
mCoordinatorLayoutTopMargin = ((FrameLayout.LayoutParams) mCoordinatorLayout.getLayoutParams()).topMargin;
}
});
}
}
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
if (recyclerView != null) {
if (mToolbar != null) {
float offset = mToolbar.getTranslationY() - dy;
if (offset <= 0 && offset >= -(mToolbar.getHeight())) {
mToolbar.setTranslationY(mToolbar.getTranslationY() - dy);
FrameLayout.LayoutParams params1 = (FrameLayout.LayoutParams) mCoordinatorLayout.getLayoutParams();
params1.setMargins(0, params1.topMargin - dy, 0, 0);
mCoordinatorLayout.setLayoutParams(params1);
}
}
}
}
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (RecyclerView.SCROLL_STATE_IDLE == newState) {
if(mToolbar != null) {
if (Math.abs(mToolbar.getTranslationY()) <= mToolbar.getHeight() / 2) {
ObjectAnimator animator = ObjectAnimator.ofFloat(mToolbar, View.TRANSLATION_Y, mToolbar.getTranslationY(), 0);
animator.setDuration(300);
animator.start();
MarginAnimation animation = new MarginAnimation(mCoordinatorLayout, ((FrameLayout.LayoutParams) mCoordinatorLayout.getLayoutParams()).topMargin, mCoordinatorLayoutTopMargin);
mCoordinatorLayout.startAnimation(animation);
} else {
ObjectAnimator animator = ObjectAnimator.ofFloat(mToolbar, View.TRANSLATION_Y, mToolbar.getTranslationY(), -mToolbarHeight);
animator.setDuration(300);
animator.start();
MarginAnimation animation = new MarginAnimation(mCoordinatorLayout, ((FrameLayout.LayoutParams) mCoordinatorLayout.getLayoutParams()).topMargin, 0);
mCoordinatorLayout.startAnimation(animation);
}
}
}
}
}
And for the margin animation, create new Class
public class MarginAnimation extends Animation {
private View mView;
private float mToMargin;
private float mFromMargin;
private Context mContext;
public MarginAnimation(View v, float fromTop, float toTop) {
mFromMargin = fromTop;
mToMargin = toTop;
mView = v;
setDuration(300);
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
float topMargin = (mToMargin - mFromMargin) * interpolatedTime + mFromMargin;
Log.d("TopMargin", String.valueOf(topMargin));
FrameLayout.LayoutParams p = (FrameLayout.LayoutParams) mView.getLayoutParams();
p.setMargins(0, (int) topMargin, 0, 0);
mView.setLayoutParams(p);
mView.requestLayout();
}
#Override
public void initialize(int width, int height, int parentWidth, int parentHeight) {
super.initialize(width, height, parentWidth, parentHeight);
}
#Override
public boolean willChangeBounds() {
return true;
}
}
Hope this helps...
Related
Trying to make the avatar pic get smaller until disappear by using OnOffsetChanged but it is not working in the fragment. I tried the same way with an activity it worked.
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/white"
android:fitsSystemWindows="true">
<android.support.design.widget.AppBarLayout
android:id="#+id/app_bar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.design.widget.CollapsingToolbarLayout
android:id="#+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:contentScrim="?attr/colorPrimary"
app:expandedTitleTextAppearance="#style/TextAppearance.AppCompat.Title"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
app:titleEnabled="false">
<ImageView
android:layout_width="match_parent"
android:layout_height="220dp"
android:fitsSystemWindows="true"
android:scaleType="centerCrop"
android:src="#drawable/bg_polygon"
app:layout_collapseMode="parallax" />
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:contentInsetStartWithNavigation="0dp"
app:layout_collapseMode="pin"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light" />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView>
**some code**
</android.support.v4.widget.NestedScrollView>
<com.mikhaellopez.circularimageview.CircularImageView
android:id="#+id/profileImage"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="#drawable/photo_female_6"
app:civ_border="true"
app:civ_border_width="2dp"
app:layout_anchor="#id/app_bar_layout"
app:layout_anchorGravity="bottom|center" />
I tried to use OnOffsetChangedListener using two ways non of them worked
the first is calling the (AppBarLayout) v.findViewById(R.id.app_bar_layout)).addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener()) to override the method
and the second is by implementing the appbarlayout in the fragmet class
public class ProfileFragment extends Fragment implements
AppBarLayout.OnOffsetChangedListener {
public ProfileFragment() {
// Required empty public constructor
}
public static ProfileFragment newInstance() {
ProfileFragment fragment = new ProfileFragment();
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AppBarLayout appBarLayout = (AppBarLayout) getActivity().findViewById(R.id.app_bar_layout);
}
#Override
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_profile, container, false);
return inflater.inflate(R.layout.fragment_profile, container, false);
}
private void initComponent(View v) {
final CircularImageView image = v.findViewById(R.id.profileImage);
final CollapsingToolbarLayout collapsing_toolbar = v.findViewById(R.id.collapsing_toolbar);
((AppBarLayout) v.findViewById(R.id.app_bar_layout)).addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
#Override
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
int min_height = ViewCompat.getMinimumHeight(collapsing_toolbar) * 2;
float scale = (float) (min_height + verticalOffset) / min_height;
image.setScaleX(scale >= 0 ? scale : 0);
image.setScaleY(scale >= 0 ? scale : 0);
}
});
}
#Override
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
final CircularImageView image;
image = (CircularImageView) getActivity().findViewById(R.id.profileImage);
final CollapsingToolbarLayout collapsing_toolbar = (CollapsingToolbarLayout) getActivity().findViewById(R.id.collapsing_toolbar);
int min_height = ViewCompat.getMinimumHeight(collapsing_toolbar) * 2;
float scale = (float) (min_height + verticalOffset) / min_height;
image.setScaleX(scale >= 0 ? scale : 0);
image.setScaleY(scale >= 0 ? scale : 0);
}
}
and when I debugged the code I found that the method was never called even when I used the CollapsingToolbarLayout.
i solved this problem by adding an "onactivitycreated" method so when i try to get the view i will exist
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
AppBarLayout mAppBarLayout = getView().findViewById(R.id.app_bar_layout);
final CollapsingToolbarLayout collapsing_toolbar = getView().findViewById(R.id.collapsing_toolbar);
final CircularImageView image = getView().findViewById(R.id.profileImage);
mAppBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
#Override
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
int min_height = ViewCompat.getMinimumHeight(collapsing_toolbar) * 2;
float scale = (float) (min_height + verticalOffset) / min_height;
image.setScaleX(scale >= 0 ? scale : 0);
image.setScaleY(scale >= 0 ? scale : 0);
}
});
}
I have a frame layout call view_snap_tabs.xml that have image and view like below
<?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="184dp"
xmlns:tools="http://schemas.android.com/tools"
tools:layout_gravity="bottom"
tools:background="#color/light_purple">
<ImageView
android:id="#+id/vst_bottom_image"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginBottom="48dp"
android:layout_gravity="center|bottom"
android:src="#drawable/small_circle"/>
<View
android:id="#+id/vst_indicator"
android:layout_width="48dp"
android:layout_height="4dp"
android:layout_gravity="bottom|center"
android:layout_marginBottom="44dp"
android:background="#drawable/indicator_background"/>
</FrameLayout>
I have included this layout in my activity_main.xml like below
<include
layout="#layout/view_snap_tabs"
android:id="#+id/am_snap_tabs"
android:layout_alignParentBottom="true"
android:layout_height="wrap_content"
android:layout_width="match_parent"/>
I have created a method call SetUpViewPager and I'm trying to add that method in main activity like below
SnapTabView snapTabView = findViewById(R.id.am_snap_tabs);
snapTabView.setUpWithViewPager(viewPager);
But when I run the application It will crash from there and give a ClassCastExeception how can I fix this?
EDITED====================================================================
public class SnapTabView extends FrameLayout implements ViewPager.OnPageChangeListener {
private ImageView mCenterImage;
private ImageView mStartImage;
private ImageView mBottomImage;
private ImageView mEndImage;
private View mIndicator;
private ArgbEvaluator mArgbEvaluator;
private int mCenterColor;
private int mSideColor;
private int mEndViewsTranslationX;
private int mIndicatorTranslationX;
private int mCenterTransationY;
public SnapTabView(#NonNull Context context) {
this(context, null);
}
public SnapTabView(#NonNull Context context, #Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public SnapTabView(#NonNull Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
LayoutInflater.from(getContext()).inflate(R.layout.view_snap_tabs, this, false);
mCenterImage = (ImageView) findViewById(R.id.vst_center_image);
mBottomImage = (ImageView) findViewById(R.id.vst_bottom_image);
mEndImage = (ImageView) findViewById(R.id.vst_end_image);
mStartImage = (ImageView) findViewById(R.id.vst_start_image);
mIndicator = (View) findViewById(R.id.vst_indicator);
mCenterColor = ContextCompat.getColor(getContext(), R.color.white);
mSideColor = ContextCompat.getColor(getContext(), R.color.dark_grey);
mArgbEvaluator = new ArgbEvaluator();
mIndicatorTranslationX = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 80, getResources().getDisplayMetrics());
mBottomImage.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
mEndViewsTranslationX = (int) ((mBottomImage.getX() - mStartImage.getX()) - mIndicatorTranslationX);
mBottomImage.getViewTreeObserver().removeOnGlobalLayoutListener(this);
mCenterTransationY = getHeight() - mBottomImage.getBottom();
}
});
}
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
if(position == 0) {
setColor(1 - positionOffset);
moveViews(1 - positionOffset);
mIndicator.setTranslationX((positionOffset - 1) * mIndicatorTranslationX);
moveAndScaleCenter(1 - positionOffset);
} else if(position == 1) {
setColor(positionOffset);
moveViews(positionOffset);
mIndicator.setTranslationX(positionOffset * mIndicatorTranslationX);
moveAndScaleCenter(positionOffset);
}
}
public void setUpWithViewPager(final ViewPager viewPager) {
viewPager.addOnPageChangeListener(this);
mStartImage.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
if(viewPager.getCurrentItem() != 0)
viewPager.setCurrentItem(0);
}
});
mEndImage.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
if(viewPager.getCurrentItem() != 2)
viewPager.setCurrentItem(2);
}
});
}
#Override
public void onPageSelected(int position) {
}
#Override
public void onPageScrollStateChanged(int state) {
}
private void setColor(float fractionFromCenter) {
int color = (int) mArgbEvaluator.evaluate(fractionFromCenter, mCenterColor, mSideColor);
mCenterImage.setColorFilter(color);
mStartImage.setColorFilter(color);
mEndImage.setColorFilter(color);
}
private void moveViews(float fractionFromCenter) {
mStartImage.setTranslationX(fractionFromCenter * mEndViewsTranslationX);
mEndImage.setTranslationX(-fractionFromCenter * mEndViewsTranslationX);
mIndicator.setAlpha(fractionFromCenter);
mIndicator.setScaleX(fractionFromCenter);
}
private void moveAndScaleCenter(float fractionFromCenter) {
float scale = .7f + ((1 - fractionFromCenter) * .3f);
mCenterImage.setScaleX(scale);
mCenterImage.setScaleY(scale);
int translation = (int) (fractionFromCenter * mCenterTransationY);
mCenterImage.setTranslationY(translation);
mBottomImage.setTranslationY(translation);
mBottomImage.setAlpha(1 - fractionFromCenter);
}
}
view_snap_tabs.xml file like below
<?xml version="1.0" encoding="utf-8"?>
<com.example.crowderia.chat.view.SnapTabView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="184dp"
tools:layout_gravity="bottom"
tools:background="#color/light_purple"
android:id="#+id/snaps">
<ImageView
android:id="#+id/vst_center_image"
android:layout_width="88dp"
android:layout_height="88dp"
android:layout_gravity="center|bottom"
android:src="#drawable/large_circle"
android:layout_marginBottom="96dp"/>
<ImageView
android:id="#+id/vst_start_image"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginBottom="56dp"
android:layout_marginStart="24dp"
android:layout_gravity="start|bottom"
android:src="#drawable/ic_chat_bubble_24dp"/>
<ImageView
android:id="#+id/vst_end_image"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginBottom="56dp"
android:layout_marginEnd="24dp"
android:layout_gravity="end|bottom"
android:src="#drawable/ic_group_work_24dp"/>
<ImageView
android:id="#+id/vst_bottom_image"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginBottom="48dp"
android:layout_gravity="center|bottom"
android:src="#drawable/small_circle"/>
<View
android:id="#+id/vst_indicator"
android:layout_width="48dp"
android:layout_height="4dp"
android:layout_gravity="bottom|center"
android:layout_marginBottom="44dp"
android:background="#drawable/indicator_background"/>
</com.example.crowderia.chat.view.SnapTabView>
do this:
<?xml version="1.0" encoding="utf-8"?>
<com.example.crowderia.chat.view.SnapTabView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="184dp"
android:id="#+id/snaps"
xmlns:tools="http://schemas.android.com/tools">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="184dp"
tools:layout_gravity="bottom"
tools:background="#color/light_purple">
<ImageView
android:id="#+id/vst_bottom_image"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginBottom="48dp"
android:layout_gravity="center|bottom"
android:src="#drawable/small_circle"/>
<View
android:id="#+id/vst_indicator"
android:layout_width="48dp"
android:layout_height="4dp"
android:layout_gravity="bottom|center"
android:layout_marginBottom="44dp"
android:background="#drawable/indicator_background"/>
</FrameLayout>
</com.example.crowderia.chat.view.SnapTabView>
in the activity do this:
View view=findViewById(R.id.am_snap_tabs);
SnapTabView snap=(SnapTabView)view.findViewById(R.id.snaps);
snap.setUpWithViewPager(viewPager);
//am_snap_tabs it is the id of the include in the question
It's because you are trying to assign a view with FrameLayout to SnapTabView, modify your xml as below
view_snap_tabs.xml
<?xml version="1.0" encoding="utf-8"?>
<com.example.crowderia.chat.view.SnapTabView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="184dp"
xmlns:tools="http://schemas.android.com/tools">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="184dp"
tools:layout_gravity="bottom"
tools:background="#color/light_purple">
<ImageView
android:id="#+id/vst_bottom_image"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginBottom="48dp"
android:layout_gravity="center|bottom"
android:src="#drawable/small_circle"/>
<View
android:id="#+id/vst_indicator"
android:layout_width="48dp"
android:layout_height="4dp"
android:layout_gravity="bottom|center"
android:layout_marginBottom="44dp"
android:background="#drawable/indicator_background"/>
</FrameLayout>
</com.example.crowderia.chat.view.SnapTabView>
I have a CustomListView where I'm showing some text and getting an image displayed using Picasso's library. I created a xml file inside the drawable folder and for drawable-21 folder for the Ripple Effect but for some reason the effect is not going above the ImageView.
Here's my files:
drawable:
listview_item_background.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<solid
android:color="#ffdadada"/>
</shape>
</item>
<item>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<solid
android:color="#ffffff"/>
</shape>
</item>
</selector>
drawable-v21:
listview_item_background.xml
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#ffdadada">
<item android:drawable="#android:color/white"/>
</ripple>
activity_main:
<?xml version="1.0"?>
<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=".MainActivity">
<android.support.design.widget.AppBarLayout
android:id="#+id/app_bar_layout"
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/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="150dp"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
app:expandedTitleMarginStart="20dp"
app:expandedTitleMarginEnd="20dp"
app:contentScrim="#color/colorPrimary"
android:background="#color/colorPrimary">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="150dp"
android:gravity="start|bottom"
app:layout_collapseMode="parallax"
android:background="#color/colorPrimary"
android:orientation="vertical">
...
</LinearLayout>
<android.support.v7.widget.Toolbar
android:layout_height="?attr/actionBarSize"
android:layout_width="match_parent"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light"
app:layout_collapseMode="pin"
app:theme="#style/ToolbarTheme"
android:background="#android:color/transparent"
android:id="#+id/main_toolbar">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start"
android:id="#+id/toolbar_title"
android:textSize="20sp"
android:textColor="#ffffff"/>
</android.support.v7.widget.Toolbar>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:id="#+id/scroll"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
android:background="#eeeeee">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
tools:ignore="UselessParent">
<packagename.NestedListView
android:id="#android:id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:divider="#eeeeee"
android:drawSelectorOnTop="true"/>
</LinearLayout>
</FrameLayout>
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>
NestedListView:
public class NestedListView extends ListView implements View.OnTouchListener, AbsListView.OnScrollListener {
private int listViewTouchAction;
private static final int MAXIMUM_LIST_ITEMS_VIEWABLE = 99;
public NestedListView(Context context, AttributeSet attrs) {
super(context, attrs);
listViewTouchAction = -1;
setOnScrollListener(this);
setOnTouchListener(this);
}
#Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
if (getAdapter() != null && getAdapter().getCount() > MAXIMUM_LIST_ITEMS_VIEWABLE) {
if (listViewTouchAction == MotionEvent.ACTION_MOVE) {
scrollBy(0, -1);
}
}
}
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
#SuppressLint("DrawAllocation")
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int newHeight = 0;
final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
if (heightMode != MeasureSpec.EXACTLY) {
ListAdapter listAdapter = getAdapter();
if (listAdapter != null && !listAdapter.isEmpty()) {
int listPosition;
for (listPosition = 0; listPosition < listAdapter.getCount()
&& listPosition < MAXIMUM_LIST_ITEMS_VIEWABLE; listPosition++) {
View listItem = listAdapter.getView(listPosition, null, this);
//now it will not throw a NPE if listItem is a ViewGroup instance
if (listItem instanceof ViewGroup) {
listItem.setLayoutParams(new LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
}
listItem.measure(widthMeasureSpec, heightMeasureSpec);
newHeight += listItem.getMeasuredHeight();
}
newHeight += getDividerHeight() * listPosition;
}
if ((heightMode == View.MeasureSpec.AT_MOST) && (newHeight > heightSize)) {
if (newHeight > heightSize) {
newHeight = heightSize;
}
}
} else {
newHeight = getMeasuredHeight();
}
setMeasuredDimension(getMeasuredWidth(), newHeight);
}
#Override
public boolean onTouch(View v, MotionEvent event) {
if (getAdapter() != null && getAdapter().getCount() > MAXIMUM_LIST_ITEMS_VIEWABLE) {
if (listViewTouchAction == MotionEvent.ACTION_MOVE) {
scrollBy(0, 1);
}
}
return false;
}
MainActivity:
NestedListView list = (NestedListView)findViewById(android.R.id.list);
CustomList adapter = new CustomList(MainActivity.this, myRssFeed.getList());
adapter.addAll();
list.setAdapter(adapter);
custom_listview_item:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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="wrap_content">
<android.support.v7.widget.CardView
android:id="#+id/card_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardCornerRadius="2dp"
app:cardElevation="2dp"
android:layout_marginBottom="#dimen/cardMarginVertical"
android:layout_marginLeft="#dimen/cardMarginHorizontal"
android:layout_marginRight="#dimen/cardMarginHorizontal"
android:layout_marginTop="#dimen/cardMarginVertical"
app:cardPreventCornerOverlap="false"
app:contentPadding="0dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="#drawable/listview_item_background"
android:id="#+id/ln">
<ImageView
android:layout_width="match_parent"
android:layout_height="170dp"
android:background="#d6d6d6"
android:contentDescription="#null"
android:id="#+id/image"
android:scaleType="centerCrop" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingRight="16dp"
android:paddingLeft="16dp"
android:layout_marginBottom="8dp"
android:textSize="18sp"
android:fontFamily="sans-serif"
tools:ignore="HardcodedText,UnusedAttribute"
android:id="#+id/title"/>
<Button
android:layout_width="match_parent"
android:layout_height="36dp"
android:layout_marginTop="16dp"
android:paddingEnd="6dp"
android:paddingRight="6dp"
android:background="#drawable/listview_item_background"
android:text="#string/condividi"
android:textStyle="bold"
android:textSize="16sp"
android:textColor="#color/material_text_dialogs"
android:gravity="center|center_vertical|center_horizontal"
android:stateListAnimator="#null"
tools:ignore="RtlHardcoded,RtlSymmetry,UnusedAttribute"
android:id="#+id/condividi"/>
</LinearLayout>
</android.support.v7.widget.CardView>
</FrameLayout>
CustomList class:
public class CustomList extends ArrayAdapter<RSSItem> {
private static Activity context = null;
private final List<RSSItem> web;
public CustomList(Activity context, List<RSSItem> web) {
super(context, R.layout.new_listview, web);
CustomList.context = context;
this.web = web;
}
#Override
public View getView(final int position, View view, ViewGroup parent) {
LayoutInflater inflater = context.getLayoutInflater();
#SuppressLint({"ViewHolder", "InflateParams"}) final View rowView = inflater.inflate(R.layout.new_listview, null, true);
ImageView imageView = (ImageView)rowView.findViewById(R.id.image);
Picasso.with(context).load(web.get(position).getImage()).into(imageView);
TextView textView = (TextView)rowView.findViewById(R.id.title);
textView.setText(Html.fromHtml(web.get(position).getTitle()));
LinearLayout linearLayout = (LinearLayout)rowView.findViewById(R.id.notizia);
linearLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String url = web.get(position).getLink();
if (!url.startsWith("http://") && !url.startsWith("https://"))
url = "http://" + url;
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
String title = "Completa azione usando:";
Intent chooser = Intent.createChooser(browserIntent, title);
context.startActivity(chooser);
}
});
Button button = (Button)rowView.findViewById(R.id.condividi);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}
});
return rowView;
}
}
That's how I display the ImageView.
Could you help me please?
I managed to fix the issue without an extra layout in my case.:
<CardView ...>
<RelativeLayout
...
android:clickable="true"
android:focusable="true"
android:foreground="?attr/selectableItemBackground">
<ImageView .../>
</RelativeLayout>
</CardView>
Few days back I was also facing same issue. I solved my issue by wrapping ImageView inside FrameLayout and applying android:foreground property on FrameLayout. You also have to set android:clickable property of FrameLayout to true or should set onClickListener to FrameLayout.
Please check my answer in following thread in following link.
Let me know if it helps.
With Google’s recent release of the Design Support Library several cool new views have been introduced. Using some of the new components (e.g. CoordinatorLayout ) might (!) enable you to achieve the scrolling behavior.
I was tryed with some built in scrolling behavior but nothing is working for me,
I have a bottombar(LinearLayout) in my layout in place of FloatingActionButton
Here what I want.
OnLaunch of this screen bottom bar should appear.
On scrollup of recyclerview bottom bar should scrolldown.
On scrolldown of recyclerview bottom bar should scrollup
Is there any builtin mechanism to achieve this ? or We need write java code?
Here is my code:
main_activty.xml
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar">
<include layout="#layout/toolbar_srp" />
<android.support.design.widget.TabLayout
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:elevation="5dp"
app:tabGravity="fill"
app:tabIndicatorColor="#android:color/white"
app:tabMode="fixed" />
</android.support.design.widget.AppBarLayout>
<!-- All Scrollable Views -->
<android.support.v4.view.ViewPager
android:id="#+id/viewpager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
<!-- Bottom bar-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:background="#a0000000"
android:orientation="horizontal"
android:paddingBottom="#dimen/padding_small"
android:paddingTop="#dimen/padding_small">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.33"
android:gravity="center"
android:paddingBottom="#dimen/padding_small"
android:paddingTop="#dimen/padding_small"
android:text="AC"
android:textColor="#color/white" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.33"
android:gravity="center"
android:paddingBottom="#dimen/padding_small"
android:paddingTop="#dimen/padding_small"
android:text="Sleeper"
android:textColor="#color/white" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.33"
android:gravity="center"
android:paddingBottom="#dimen/padding_small"
android:paddingTop="#dimen/padding_small"
android:text="Premium"
android:textColor="#color/white" />
</LinearLayout>
</android.support.design.widget.CoordinatorLayout>
fragment.xml (here I was putted my recyclerview code)
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/white"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingBottom="#dimen/padding_small"
android:paddingTop="#dimen/padding_small"
android:weightSum="1">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.33"
android:background="#drawable/bg_srp_sorter"
android:clickable="true"
android:gravity="center"
android:paddingBottom="#dimen/padding_small"
android:paddingTop="#dimen/padding_small"
android:text="Departure" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.33"
android:background="#drawable/bg_srp_sorter"
android:gravity="center"
android:paddingBottom="#dimen/padding_small"
android:paddingTop="#dimen/padding_small"
android:text="Duration" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.33"
android:gravity="center"
android:paddingBottom="#dimen/padding_small"
android:paddingTop="#dimen/padding_small"
android:text="Price" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#color/lite_gray"></View>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:weightSum="1">
<android.support.v7.widget.RecyclerView
android:id="#+id/bus_list_recycler_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>
</LinearLayout>
toolbar.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways"
android:minHeight="?attr/actionBarSize">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:weightSum="1">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.10">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/abc_ic_ab_back_mtrl_am_alpha" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.78"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="1">
<TextView
android:id="#+id/toolbar_title_source"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.47"
android:ellipsize="end"
android:singleLine="true"
android:text="Thiruvananthapuram "
android:textColor="#color/white"
android:textSize="#dimen/label_text_size_large" />
<TextView
android:id="#+id/toolbar_title_arrow"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.08"
android:text="#string/char_right"
android:textColor="#color/white"
android:textSize="#dimen/label_text_size_large"
android:textStyle="bold" />
<TextView
android:id="#+id/toolbar_title_destination"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.47"
android:ellipsize="end"
android:singleLine="true"
android:text=" Cochin"
android:textColor="#color/white"
android:textSize="#dimen/label_text_size_large" />
</LinearLayout>
<TextView
android:id="#+id/toolbar_sub_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="2 Seat(s)"
android:textColor="#color/lite_gray"
android:textSize="#dimen/label_text_size_normal" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.13">
<ImageView
android:layout_width="30dp"
android:layout_height="30dp"
android:scaleType="fitCenter"
android:src="#drawable/filter" />
</LinearLayout>
</LinearLayout>
</android.support.v7.widget.Toolbar>
This how I did it:
mRecylerView.addOnScrollListener(new HideShowScrollListener() {
#Override
public void onHide() {
//fab.animate().setInterpolator(new AccelerateDecelerateInterpolator()).scaleX(0).scaleY(0);
// do your hiding animation here
}
#Override
public void onShow() {
// fab.animate().setInterpolator(new AccelerateDecelerateInterpolator()).scaleX(1).scaleY(1);
// do your showing animation here
}
});
You will be needing HideShowScrollListener.class
/**
* This class is a ScrollListener for RecyclerView that allows to show/hide
* views when list is scrolled.
* */
public abstract class HideShowScrollListener extends RecyclerView.OnScrollListener {
private static final int HIDE_THRESHOLD = 20;
private int scrolledDistance = 0;
private boolean controlsVisible = true;
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if (scrolledDistance > HIDE_THRESHOLD && controlsVisible) {
onHide();
controlsVisible = false;
scrolledDistance = 0;
} else if (scrolledDistance < -HIDE_THRESHOLD && !controlsVisible) {
onShow();
controlsVisible = true;
scrolledDistance = 0;
}
if((controlsVisible && dy>0) || (!controlsVisible && dy<0)) {
scrolledDistance += dy;
}
}
public abstract void onHide();
public abstract void onShow();
}
since you are using CoordinatorLayout you could create a custom Behaviour that can achieve what you requested follow example below:
create a class that extends CoordinatorLayout.Behavior<View> follow example below:
public class QuickReturnFloaterBehavior extends CoordinatorLayout.Behavior<View> {
private int distance;
public QuickReturnFloaterBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) {
return (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;
}
#Override public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dx, int dy, int[] consumed) {
if (dy > 0 && distance < 0 || dy < 0 && distance > 0) {
child.animate().cancel();
distance = 0;
}
distance += dy;
final int height = child.getHeight() > 0 ? (child.getHeight()) : 600/*update this accordingly*/;
if (distance > height && child.isShown()) {
hide(child);
} else if (distance < 0 && !child.isShown()) {
show(child);
}
}
private void hide(View view) {
view.setVisibility(View.GONE);// use animate.translateY(height); instead
}
private void show(View view) {
view.setVisibility(View.VISIBLE);// use animate.translateY(-height); instead
}
}
now to apply this behaviour add this to your layout
app:layout_behavior="com.example.QuickReturnFloaterBehavior"
Visibility and Hide with Animation in Your Fragment:
recyclerView.addOnScrollListener(new HideShowScrollListener() {
final Fragment parentFragment = getParentFragment();
#Override
public void onHide() {
bottomLayout.animate().setDuration(200).translationYBy(-bottomLayout.getHeight()).setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
bottomLayout.setVisibility(View.GONE);
}
});
}
#Override
public void onShow() {
bottomLayout.animate().setDuration(200).translationY(0).setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
bottomLayout.setVisibility(View.VISIBLE);
}
});
}
#Override
public void onScrolled() {
// To load more data
}
});
HideShowScrollListener.java
public abstract class HideShowScrollListener extends RecyclerView.OnScrollListener {
private static final int HIDE_THRESHOLD = 20;
private int scrolledDistance = 0;
private boolean controlsVisible = true;
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
onScrolled();
if (scrolledDistance > HIDE_THRESHOLD && controlsVisible) {
onHide();
controlsVisible = false;
scrolledDistance = 0;
} else if (scrolledDistance < -HIDE_THRESHOLD && !controlsVisible) {
onShow();
controlsVisible = true;
scrolledDistance = 0;
}
if((controlsVisible && dy>0) || (!controlsVisible && dy<0)) {
scrolledDistance += dy;
}
}
public abstract void onHide();
public abstract void onShow();
public abstract void onScrolled();
}
package com.keshav.hideactionbarandfooterexample;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.View;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import java.util.ArrayList;
import java.util.List;
import adapters.RecyclerAdapter;
import listners.HidingScrollListener;
public class MainActivity extends AppCompatActivity {
private Toolbar mToolbar;
private Toolbar toolbar_bottom;
private ImageButton mFabButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
setTheme(R.style.AppThemeRed);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.e("keshav", "MainActivity called");
initToolbar();
mFabButton = (ImageButton) findViewById(R.id.fabButton);
initRecyclerView();
}
private void initToolbar() {
mToolbar = (Toolbar) findViewById(R.id.toolbar);
toolbar_bottom = (Toolbar) findViewById(R.id.toolbar_bottom);
setSupportActionBar(mToolbar);
setSupportActionBar(toolbar_bottom);
setTitle(getString(R.string.app_name));
mToolbar.setTitleTextColor(getResources().getColor(android.R.color.white));
toolbar_bottom.setTitleTextColor(getResources().getColor(android.R.color.white));
toolbar_bottom.setVisibility(View.GONE);
}
private void initRecyclerView() {
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
RecyclerAdapter recyclerAdapter = new RecyclerAdapter(createItemList());
recyclerView.setAdapter(recyclerAdapter);
recyclerView.addOnScrollListener(new HidingScrollListener() {
#Override
public void onHide() {
hideViews();
}
#Override
public void onShow() {
showViews();
}
});
}
private void hideViews() {
// TODO (-mToolbar) plus means 2 view above ho jaye or not visible to user
mToolbar.animate().translationY(-mToolbar.getHeight()).setInterpolator(new AccelerateInterpolator(2));
// TODO uncomment this Hide Footer in android when Scrolling
// TODO (+mToolbar) plus means 2 view forward ho jaye or not visible to user
toolbar_bottom.animate().translationY(+toolbar_bottom.getHeight()).setInterpolator(new AccelerateInterpolator(2));
// TODO keshav Hide Also Floatng Button In Android
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mFabButton.getLayoutParams();
int fabBottomMargin = lp.bottomMargin;
mFabButton.animate().translationY(mFabButton.getHeight() + fabBottomMargin).setInterpolator(new AccelerateInterpolator(2)).start();
// TODO keshav Hide Also Floatng Button In Android
}
private void showViews() {
mToolbar.animate().translationY(0).setInterpolator(new DecelerateInterpolator(2));
// TODO uncomment this Hide Footer in android when Scrolling
toolbar_bottom.animate().translationY(0).setInterpolator(new DecelerateInterpolator(2));
mFabButton.animate().translationY(0).setInterpolator(new DecelerateInterpolator(2)).start();
}
private List<String> createItemList() {
List<String> itemList = new ArrayList<>();
for (int i = 0; i < 20; i++) {
itemList.add("Item " + i);
}
return itemList;
}
}
=============================================
RecyclerAdapter
=============================================
package adapters;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.keshav.hideactionbarandfooterexample.R;
import java.util.List;
/*
* RecyclerView Adapter that allows to add a header view.
* */
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final int TYPE_HEADER = 2;
private static final int TYPE_ITEM = 1;
private List<String> mItemList;
public RecyclerAdapter(List<String> itemList) {
mItemList = itemList;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Context context = parent.getContext();
if (viewType == TYPE_ITEM) {
final View view = LayoutInflater.from(context).inflate(R.layout.recycler_item, parent, false);
return RecyclerItemViewHolder.newInstance(view);
} else if (viewType == TYPE_HEADER) {
final View view = LayoutInflater.from(context).inflate(R.layout.recycler_header, parent, false);
return new RecyclerHeaderViewHolder(view);
}
throw new RuntimeException("There is no type that matches the type " + viewType + " + make sure your using types correctly");
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
if (!isPositionHeader(position)) {
RecyclerItemViewHolder holder = (RecyclerItemViewHolder) viewHolder;
String itemText = mItemList.get(position - 1); // header
holder.setItemText(itemText);
}
}
public int getBasicItemCount() {
return mItemList == null ? 0 : mItemList.size();
}
#Override
public int getItemViewType(int position) {
if (isPositionHeader(position)) {
return TYPE_HEADER;
}
return TYPE_ITEM;
}
#Override
public int getItemCount() {
return getBasicItemCount() + 1; // header
}
private boolean isPositionHeader(int position) {
return position == 0;
}
}
=====================================================
RecyclerHeaderViewHolder
=====================================================
package adapters;
import android.support.v7.widget.RecyclerView;
import android.view.View;
public class RecyclerHeaderViewHolder extends RecyclerView.ViewHolder {
public RecyclerHeaderViewHolder(View itemView) {
super(itemView);
}
}
=====================================================
RecyclerItemViewHolder
=====================================================
package adapters;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.TextView;
import com.keshav.hideactionbarandfooterexample.R;
public class RecyclerItemViewHolder extends RecyclerView.ViewHolder {
private final TextView mItemTextView;
public RecyclerItemViewHolder(final View parent, TextView itemTextView) {
super(parent);
mItemTextView = itemTextView;
}
public static RecyclerItemViewHolder newInstance(View parent) {
TextView itemTextView = (TextView) parent.findViewById(R.id.itemTextView);
return new RecyclerItemViewHolder(parent, itemTextView);
}
public void setItemText(CharSequence text) {
mItemTextView.setText(text);
}
}
===================================================
activity_main.xml
===================================================
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"/>
<ImageButton
android:id="#+id/fabButton"
android:layout_width="56dp"
android:layout_height="56dp"
android:layout_gravity="bottom|right"
android:layout_marginBottom="16dp"
android:layout_marginRight="16dp"
android:background="#drawable/fab_bcg"
android:src="#drawable/ic_favorite_outline_white_24dp"
android:contentDescription="#string/fab_description"/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar_bottom"
android:layout_width="match_parent"
android:layout_alignParentBottom="true"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"/>
</RelativeLayout>
</FrameLayout>
==================================================
recycle_header.xml in layout folder
==================================================
<?xml version="1.0" encoding="utf-8"?>
<View xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"/>
==================================================
recycle_item.xml in layout folder
==================================================
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="8dp"
card_view:cardCornerRadius="4dp">
<TextView
android:id="#+id/itemTextView"
android:layout_width="match_parent"
android:layout_height="?attr/listPreferredItemHeight"
android:gravity="center_vertical"
android:padding="8dp"
style="#style/Base.TextAppearance.AppCompat.Body2"/>
</android.support.v7.widget.CardView>
=================================================
styles.xml
=================================================
<resources>
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
</style>
<style name="AppThemeRed" parent="AppTheme">
<item name="colorPrimary">#color/color_primary_red</item>
<item name="colorPrimaryDark">#color/color_primary_red_dark</item>
</style>
<style name="AppThemeGreen" parent="AppTheme">
<item name="colorPrimary">#color/color_primary_green</item>
<item name="colorPrimaryDark">#color/color_primary_green_dark</item>
</style>
<style name="AppThemeBlue" parent="AppTheme">
<item name="colorPrimary">#color/color_primary_blue</item>
<item name="colorPrimaryDark">#color/color_primary_blue_dark</item>
<item name="colorAccent">#color/color_accent_pink</item>
</style>
</resources>
build.gradle Dependency
compile 'com.android.support:appcompat-v7:25.3.1'
compile 'com.android.support:recyclerview-v7:25.3.1'
compile 'com.android.support:cardview-v7:25.3.1'
compile 'com.android.support:design:25.3.1'
#k0sh gave a fine solution. I want to update it to get a smooth animation
while showing and hiding the layout. Replace complete code inside
onNestedPreScroll() with the below code:
if (dy > 0) {
CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) child.getLayoutParams();
int viewBottomMargin = layoutParams.bottomMargin;
child.animate().translationY(child.getHeight() + viewBottomMargin).setInterpolator(new LinearInterpolator()).start();
} else if (dy < 0) {
child.animate().translationY(0).setInterpolator(new LinearInterpolator()).start();
}
#k0sh's QuickReturnFloaterBehavior works but it sometimes not listen to the slight scrolls.
I am having contents in NestedScrollView with a LinearLayout as a bottom bar & didn't have the recycler view. so, I can't use other suggested answers.
Those who are having the same situation can use the BottomNavigationBehavior from this post Bottom Navigation Behavior. it works perfectly & useful.
When the current top-level view has a scrolling content, the bottom
navigation should hide when it is scrolled down and retract back when
the content is scrolled up. For this purpose, we need to be aware of
the direction of the scroll. VerticalScrollingBehavior is a generic
layout behavior that it is somehow an extension to the
CoordinatorLayout.Behavior that dispatches events on for direction of
scrolling.
source code for BottomNavigationBehavior - https://gist.github.com/NikolaDespotoski/1d6fef4949eb9be05a46#file-bottomnavigationbehavior-java
snippet from BottomNavigationBehavior
#Override
public void onDirectionNestedPreScroll(CoordinatorLayout coordinatorLayout, V child, View target, int dx, int dy, int[] consumed, #ScrollDirection int scrollDirection) {
handleDirection(child, scrollDirection);
}
#Override
protected boolean onNestedDirectionFling(CoordinatorLayout coordinatorLayout, V child, View target, float velocityX, float velocityY, #ScrollDirection int scrollDirection) {
handleDirection(child, scrollDirection);
return true;
}
private void handleDirection(V child, #ScrollDirection int scrollDirection) {
if (!scrollingEnabled) return;
if (scrollDirection == ScrollDirection.SCROLL_DIRECTION_DOWN && hidden) {
hidden = false;
animateOffset(child, 0);
} else if (scrollDirection == ScrollDirection.SCROLL_DIRECTION_UP && !hidden) {
hidden = true;
animateOffset(child, child.getHeight());
}
}
I am using JakeWharton's ViewPageIndicator. I want the height of the pager and the indicator to span around 300dp so that i can more content below it and it can scroll.
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/scrollView"
android:fillViewport="true" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="300dp"
android:orientation="vertical" >
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:paddingTop="2dp" />
<com.viewpagerindicator.CirclePageIndicator
android:id="#+id/indicator"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:padding="10dip" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Testing something cool" />
</LinearLayout>
</LinearLayout>
</ScrollView>
Things Work Perfect. But i am not able to Slide the Viewpagper and it gets really stuck and doesnt slide to the next one. Any one know how to make it work in a confined height ?
******Edit******
Trying to use the solution from Here. Am not very sure if its the right way to Sub-Class Scroll View.
public class PlaceDetailsFragment extends SherlockFragment {
PlaceSlidesFragmentAdapter mAdapter;
ViewPager mPager;
PageIndicator mIndicator;
public static final String TAG = "detailsFragment";
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_place_details,
container, false);
mAdapter = new PlaceSlidesFragmentAdapter(getActivity()
.getSupportFragmentManager());
mPager = (ViewPager) view.findViewById(R.id.pager);
mPager.setAdapter(mAdapter);
mIndicator = (CirclePageIndicator) view.findViewById(R.id.indicator);
mIndicator.setViewPager(mPager);
// ((CirclePageIndicator) mIndicator).setSnap(true);
mIndicator
.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageSelected(int position) {
Toast.makeText(PlaceDetailsFragment.this.getActivity(),
"Changed to page " + position,
Toast.LENGTH_SHORT).show();
}
#Override
public void onPageScrolled(int position,
float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
return view;
}
public class CustomScrollView extends ScrollView {
private GestureDetector mGestureDetector;
View.OnTouchListener mGestureListener;
public CustomScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
mGestureDetector = new GestureDetector(context, new YScrollDetector());
setFadingEdgeLength(0);
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return super.onInterceptTouchEvent(ev) && mGestureDetector.onTouchEvent(ev);
}
// Return false if we're scrolling in the x direction
class YScrollDetector extends SimpleOnGestureListener {
#Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
if(Math.abs(distanceY) > Math.abs(distanceX)) {
return true;
}
return false;
}
}
}
}
Have to create a Custom Scroll View and use that
public class VerticalScrollView extends ScrollView {
View.OnTouchListener mGestureListener;
private VelocityTracker mVelocityTracker;
private int mMaximumVelocity;
public VerticalScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
setFadingEdgeLength(0);
final ViewConfiguration configuration = ViewConfiguration.get(context);
mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
}
private boolean doNotInterceptUntilUp = false;
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
// System.out.println("onInterceptTouchEvent");
int action = ev.getAction();
int index = MotionEventCompat.getActionIndex(ev);
int mActivePointerId = MotionEventCompat.getPointerId(ev, index);
if (action == MotionEvent.ACTION_DOWN) {
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
}
mVelocityTracker.addMovement(ev);
} else if (action == MotionEvent.ACTION_MOVE) {
if (doNotInterceptUntilUp) {
return false;
}
mVelocityTracker.addMovement(ev);
mVelocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
int initialVelocity = (int) VelocityTrackerCompat.getXVelocity(
mVelocityTracker, mActivePointerId);
int initialYVelocity = (int) VelocityTrackerCompat.getYVelocity(
mVelocityTracker, mActivePointerId);
if (Math.abs(initialVelocity) > 100) {
// 140 is the minimum threshold it seems.
if (!(Math.abs(initialYVelocity) > 140))
doNotInterceptUntilUp = true;
return false;
}
} else if (action == MotionEvent.ACTION_UP) {
doNotInterceptUntilUp = false;
if (mVelocityTracker != null) {
mVelocityTracker.clear();
}
}
boolean val = super.onInterceptTouchEvent(ev);
return val;
}
}
XML
<?xml version="1.0" encoding="utf-8"?>
<com.m7.nomad.VerticalScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res/com.m7.nomad"
android:id="#+id/scrollView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:fillViewport="true" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="300dp"
android:orientation="vertical" >
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<com.viewpagerindicator.CirclePageIndicator
android:id="#+id/indicator"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:paddingBottom="10dip"
android:paddingLeft="10dip"
android:paddingTop="1dip" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Testing something cool" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Testing something cool" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Testing something cool" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Testing something cool" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Testing something cool" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Testing something cool" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Testing something cool" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Testing something cool" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Testing something cool" />
</LinearLayout>
</LinearLayout>
</com.m7.nomad.VerticalScrollView>