Snackbar with CoordinatorLayout disable dismiss - android

I am using the support
FloatingActionButton
Snackbar
CoordinatorLayout
I need the CoordinatorLayout so that if SnackBar is shown the FloatingActionButton moves up to make room for the Snackbar. For better understanding check this video.
I am using SnackBar for double-back to exit the application, but the SnackBar can be dismissed.
Is there a way to disable the dismiss on the SnackBar?
Snackbar snackbar = Snackbar.make(view, R.string.press_back_again_to_exit, Snackbar.LENGTH_SHORT);
snackbar.setAction(R.string.ok, new View.OnClickListener() {
#Override
public void onClick(View v)
{
}
});
snackbar.setActionTextColor(getResources().getColor(R.color.white));
View view = snackbar.getView();
view.setBackgroundColor(getResources().getColor(R.color.orange_warning));
snackbar.show();
Layout
<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.support.v4.widget.DrawerLayout
android:id="#+id/drawer_layout"
xmlns:sothree="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/white"
android:fitsSystemWindows="true">
<com.sothree.slidinguppanel.SlidingUpPanelLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="bottom"
sothree:umanoFadeColor="#android:color/transparent"
sothree:umanoPanelHeight="100dp"
sothree:umanoShadowHeight="4dp">
<!-- Toolbar and main content -->
<LinearLayout
android:id="#+id/toolbar_and_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<include layout="#layout/toolbar"/>
<!-- Your content layout -->
<FrameLayout
android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"/>
</LinearLayout>
<!-- Sliding up panel layout -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/darker_grey"
android:orientation="vertical">
...
</LinearLayout>
</com.sothree.slidinguppanel.SlidingUpPanelLayout>
<!-- Navigation drawer -->
<ExpandableListView
android:id="#+id/lv_left_drawer"
android:layout_width="280dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="#color/white"
android:childDivider="#android:color/transparent"
android:clickable="true"
android:divider="#color/divider_color"
android:dividerHeight="0.6dp"
android:fadeScrollbars="true"
android:groupIndicator="#null"
android:listSelector="#drawable/button_drawer_child_selector"
android:scrollbarSize="0dp"/>
</android.support.v4.widget.DrawerLayout>
<android.support.design.widget.FloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right|bottom"
android:layout_marginBottom="#dimen/floating_action_button_margin"
android:layout_marginRight="#dimen/floating_action_button_margin"
android:src="#drawable/ic_add"
android:visibility="invisible"
app:backgroundTint="#color/orange"
app:borderWidth="0dp"
app:elevation="6dp"
app:fabSize="normal"/>
</android.support.design.widget.CoordinatorLayout>
P.S.
I am aware of this GitHub library, that has this functionality, but is there a 'native' way to do it?

Snackbar now has actual support disabling swipe to dismiss using the setBehavior method. The great thing here is that before you would always lose some behaviors which are now preserved. You'll also want to use Snackbar.LENGTH_INDEFINITE
Note that the package moved so you have to import the "new" Snackbar in the snackbar package.
Snackbar.make(view, stringId, Snackbar.LENGTH_INDEFINITE)
.setBehavior(new NoSwipeBehavior())
.show();
class NoSwipeBehavior extends BaseTransientBottomBar.Behavior {
#Override
public boolean canSwipeDismissView(View child) {
return false;
}
}

You can alter the duration of Snackbar to be shown. It will be similar to disable dismiss.
int LENGTH_INDEFINITE Show the Snackbar indefinitely.
Check docs.
if it does not work
For this then there is only one way, Implement Your custom Snackbar and override dismiss() method and in that do nothing. :) As dismiss() is a public API.

The answer about just using LENGTH_INDEFINITE is not sufficient.
It is only non-dismissable when the Snackbar is no child of CoordinatorLayout.
When it is a child, you can still swipe away the SnackBar.
What you can do in that case is listen for the dismiss swipe and simply re-show the Snackbar.
public void showAnnoyingSnackBar(View root, String text) {
Snackbar.make(root, text, Snackbar.LENGTH_INDEFINITE)
.setCallback(new Snackbar.Callback() {
#Override public void onDismissed(Snackbar snackbar, int event) {
// recursively call this method again when the snackbar was dismissed through a swipe
if (event == DISMISS_EVENT_SWIPE) showAnnoyingSnackBar(root, text);
}
})
.show();
}

I noticed that when show() method is called, SnackbarLayout is not fully initialised yet.
To lock dissmiss we have to clear behavior after SnackbarLayout initialisation.
the best place to do this is for example in OnPreDrawListener of SnackbarLayout
final Snackbar snack = Snackbar.make(getView(), "I can't be dissmiss", Snackbar.LENGTH_INDEFINITE);
snack.show();
snack.getView().getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
snack.getView().getViewTreeObserver().removeOnPreDrawListener(this);
((CoordinatorLayout.LayoutParams) snack.getView().getLayoutParams()).setBehavior(null);
return true;
}
});

I was successful in disabling the swipe-sideways-to-dismiss snackbars with the following hack (after calling snackbar.show())
((android.support.design.widget.CoordinatorLayout.LayoutParams) snackbar.getView().getLayoutParams()).setBehavior(null);

Related

Call navigation icon click in toolbar (android)

I have code below:
setSupportActionBar(toolbar);
toolbar.setNavigationOnClickListener(onClickListener);
and XML:
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:elevation="0dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.appcompat.widget.Toolbar
android:id="#+id/app_bar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:paddingStart="0dp"
android:paddingEnd="12dp"
app:contentInsetStart="0dp"
app:navigationIcon="#drawable/ic_menu_black_24dp"
app:title="#string/app_name" />
</com.google.android.material.appbar.AppBarLayout>
I want to call click on navigation icon of toolbar, but i cant find method to do it.
I can't call onClickListener(null) because I change icon inside onClick.
Please try this by replacing 'number' with the index of the icon. (It could be 1-2-3-4 etc.)
toolbar.getChildAt(number).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//do whatever you want here
}
});
Try this,
Toolbar toolbar;
toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
#Override
public boolean onSupportNavigateUp() {
onBackPressed();
return true;
}
You can used setNavigationOnClickListener {} for this.
// I used private function here, you don't need to.
private fun onBackArrowPressed() {
// when user clicked the navigation icon (here is back arrow)
binding.toolbar.setNavigationOnClickListener {
// find the nav controller and pop backstack
findNavController().popBackStack()
}
}
Material Components Android Top AppBar

Android design Library AppBar scrolling behavior enterAlways

I am using the latest version of the design support library (23.1.1) and I am facing an issue when I use the CollapsingToolbarLayout with the enterAlways scroll flag. Basically, when you scroll back up, the view appears but if also leaves a empty white space at top.
Normal View:
After scrolling down and then back up (notice the whitespace below status bar):
MainActivity.java
public class MainActivity extends AppCompatActivity {
AppBarLayout appBar;
View expandedView;
Toolbar toolbar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
setTitle("");
initViews();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
private void initViews() {
appBar = (AppBarLayout) findViewById(R.id.appBar);
appBar.addOnOffsetChangedListener(appBarOffsetChangedListener);
expandedView = findViewById(R.id.expandedView);
RecyclerView rv = (RecyclerView) findViewById(R.id.rv);
rv.setLayoutManager(new LinearLayoutManager(this));
rv.setAdapter(new DummyAdapter());
}
private AppBarLayout.OnOffsetChangedListener appBarOffsetChangedListener = new AppBarLayout.OnOffsetChangedListener() {
#Override
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
int maxOffset = appBar.getTotalScrollRange();
verticalOffset = Math.abs(verticalOffset);
if(verticalOffset > maxOffset)
return;
float percentage = verticalOffset / (float) maxOffset;
if(expandedView!=null)
expandedView.setAlpha(1 - percentage);
}
};
}
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"
android:fitsSystemWindows="true"
tools:context="com.media2359.fragmenttoolbarchange.MainActivity">
<android.support.design.widget.AppBarLayout
android:id="#+id/appBar"
android:layout_width="match_parent"
android:layout_height="180dp"
android:background="#color/colorPrimaryDark"
android:fitsSystemWindows="true">
<android.support.design.widget.CollapsingToolbarLayout
android:id="#+id/collapsingToolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:layout_scrollFlags="scroll|exitUntilCollapsed|enterAlways">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin">
</android.support.v7.widget.Toolbar>
<RelativeLayout
android:id="#+id/expandedView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:paddingLeft="#dimen/toolbar_text_margin_left"
android:paddingTop="#dimen/toolbar_text_margin_top"
tools:background="#color/colorPrimaryDark">
<TextView
android:id="#+id/tvName"
style="#style/TextAppearance.AppCompat.Headline"
android:layout_width="#dimen/toolbar_text_width"
android:layout_height="wrap_content"
android:text="Hello" />
<TextView
android:id="#+id/tvTime"
style="#style/TextAppearance.AppCompat.Body1"
android:layout_width="#dimen/toolbar_text_width"
android:layout_height="wrap_content"
android:layout_below="#id/tvName"
android:layout_marginTop="7dp"
android:text="04 Feb, Tuesday evening" />
</RelativeLayout>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v7.widget.RecyclerView
android:id="#+id/rv"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:listitem="#layout/item_dummy" />
</android.support.design.widget.CoordinatorLayout>
Using enterAlwaysCollapsed along with enterAlways avoids this issue but I want the full view to come back because in the actual app, the expanded section is way smaller.
Another thing that I have noticed is that, the height of the whitespace is equal to the height to the toolbar.
EDIT 1
I replaced exitUntilCollapsed with snap and then there wasn't any white space but then the toolbar doesn't pin and scrolls away
EDIT 2
Looks like this is an issue with the Design Library: CollapsingToolbarLayout enterAlways not supported
Temporary Workaround: Cheesesquare: enterAlways produces wrong layout
Perhaps that's because of:
enterAlways
Which the codepath/android_guides says:
enterAlways: The view will become visible when scrolling up. This flag
is useful in cases when scrolling from the bottom of a list and
wanting to expose the Toolbar as soon as scrolling up takes place.
Maybe you wanna try this: (standard way)
app:layout_scrollFlags="scroll|exitUntilCollapsed"
Honestly, I didn't see somebody is using enterAlways in CollapsingToolbarLayout in my whole development life.Especially, with those two flags:
app:layout_scrollFlags="scroll|exitUntilCollapsed|enterAlways"
Otherwise, It could be a bug and needs the Google's staffs to answer about it.

Toolbar is invisible on some devices

I have a quite simple layout and I animate the showing/hiding of the toolbars with the appended functions. I'm using AppCompat and Toolbars...
PROBLEM
One person reported that the top toolbar is never shown. Any ideas why? What could be the reason? It's working fine on my phone and others...
Function
public void showHideToolbar(boolean forceHide, boolean animate)
{
L.d(this, "showHideToolbar: " + mShowToolbar);
toolbar.clearAnimation();
toolbar2.clearAnimation();
if (mShowToolbar || forceHide)
{
if (animate) {
toolbar.animate().translationY(-toolbar.getBottom()).setInterpolator(new AccelerateInterpolator()).start();
toolbar2.animate().translationY(toolbar2.getBottom()).setInterpolator(new AccelerateInterpolator()).start();
}
else
{
toolbar.setTranslationY(-toolbar.getBottom());
toolbar2.setTranslationY(toolbar2.getBottom());
}
mShowToolbar = false;
}
else
{
if (animate) {
toolbar.animate().translationY(0).setInterpolator(new DecelerateInterpolator()).start();
toolbar2.animate().translationY(0).setInterpolator(new DecelerateInterpolator()).start();
}
else
{
toolbar.setTranslationY(0);
toolbar2.setTranslationY(0);
}
mShowToolbar = true;
}
}
Layout
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/flMain"
android:background="?attr/main_background_color"
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"
android:elevation="4dp"
app:theme="?actionBarThemeStyle"
app:popupTheme="?actionBarPopupThemeStyle" />
<android.support.v4.view
android:id="#+id/vpSlides"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar2"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/bottom_bar_background"
android:elevation="0dp"
android:layout_alignParentBottom="true"
android:gravity="top|start"
app:theme="?actionBarThemeStyle"
app:popupTheme="?actionBarPopupThemeStyle" >
</android.support.v7.widget.Toolbar>
</RelativeLayout>
It seems like, even if you make a toolbar to an actionbar, you have to respect layout ordering in the xml. setSupportActionBar won't bring the action bar on top of the main layout...
So the simple solution was to reorder the toolbar to being under the content...
I never ad problems yet as normally I show the content underneath the toolbar, here I didn't want to that and therefore faced the problem

NavigationDrawer isDrawerOpened always returns true

I have faced with weird problem. I am using navigation drawer from support library in my app.
Here is layout
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/navigation_drawer"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/linear_layout_main_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar_main"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
android:minHeight="?attr/actionBarSize"
android:visibility="gone" />
</LinearLayout>
<ScrollView
android:id="#+id/layout_drawer_left"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fillViewport="true">
</ScrollView>
<ScrollView
android:id="#+id/layout_drawer_right"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_gravity="end"
android:fillViewport="true" />
</android.support.v4.widget.DrawerLayout>
And I find all views after setting content view.
private FrameLayout mLeftDrawerContainer, mRightDrawerContainer;
private DrawerLayout mDrawerMainLayout;
mDrawerMainLayout = (DrawerLayout) rootBaseView.findViewById(R.id.navigation_drawer);
mLeftDrawerContainer = (ScrollView) rootBaseView.findViewById(R.id.layout_drawer_left);
mRightDrawerContainer = (ScrollView) rootBaseView.findViewById(R.id.layout_drawer_right);
I have tried a lot of ways in order to close drawer, it closes it visually, I mean everything is ok, drawer slowly left the screen and stays closed, but from perspective of code it always return true.
protected boolean isDrawersOpened() {
boolean rightDrawerOpened = mDrawerMainLayout.isDrawerOpen(mRightDrawerContainer);
boolean leftDrawerOpened = mDrawerMainLayout.isDrawerOpen(mLeftDrawerContainer);
return rightDrawerOpened || leftDrawerOpened ;
}
Always true
public void closeDrawer() {
mDrawerMainLayout.closeDrawer(GravityCompat.END);
mDrawerMainLayout.closeDrawer(GravityCompat.START);
mDrawerMainLayout.closeDrawer(mRightDrawerContainer);
mDrawerMainLayout.closeDrawer(mLeftDrawerContainer);
mDrawerMainLayout.closeDrawers();
}
So it should work, but returns always true.
If it is bug in suppor library, no problems I will wait and use boolean variable inside activity to indicate this, but maybe someone dealt with the same problem.
Thank for any help and ideas in advance.
Sorry, for my inattention.
I have made a mistake in my code
if (hasLeftDrawer) {
setupLeftDrawer();
} else {
mDrawerMainLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_OPEN, mLeftDrawerContainer);
}
if (hasRightDrawer) {
setupRightDrawer();
} else {
mDrawerMainLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_OPEN, mRightDrawerContainer);
}
Should be
if (hasLeftDrawer) {
setupLeftDrawer();
} else {
mDrawerMainLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED, mLeftDrawerContainer);
}
if (hasRightDrawer) {
setupRightDrawer();
} else {
mDrawerMainLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED, mRightDrawerContainer);
}

Profile Not Showing on material-drawer

I've recently tried to implement a Material Design overhaul in one of my apps, and came across this library from HeinrichReimer (material-design) on implementing the Navigation Drawer for Material Design.
However, I'm getting a problem with showing the Profile part of the Drawer. I've implemented it as shown in the guide:
drawer.setProfile(
new DrawerProfile()
.setAvatar(getResources().getDrawable(R.drawable.zild))
.setBackground(getResources().getDrawable(R.drawable.zild))
.setName(getString(R.string.app_name))
.setDescription(getString(R.string.hello_blank_fragment))
.setOnProfileClickListener(new DrawerProfile.OnProfileClickListener() {
#Override
public void onClick(DrawerProfile drawerProfile) {
// do nothing yet
}
})
);
.. and I've also added some drawer items
drawer.addItem(
new DrawerItem()
.setImage(getResources().getDrawable(R.drawable.ic_launcher))
.setTextPrimary("My Entries")
.setTextSecondary("Yay Entries!")
.setOnItemClickListener(new DrawerItem.OnItemClickListener() {
#Override
public void onClick(DrawerItem drawerItem, int i) {
Toast.makeText(HomeActivity.this, "Clicked first item", Toast.LENGTH_LONG).show();
}
})
);
drawer.addDivider();
drawer.addItem(new DrawerItem()
.setImage(getResources().getDrawable(R.drawable.ic_launcher))
.setTextPrimary("Settings")
.setTextSecondary("Woohoo Settings!")
.setOnItemClickListener(new DrawerItem.OnItemClickListener() {
#Override
public void onClick(DrawerItem drawerItem, int i) {
Toast.makeText(HomeActivity.this, "Clicked second item", Toast.LENGTH_LONG).show();
}
})
);
Below is my layout xml:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<android.support.v7.widget.Toolbar
android:id="#+id/timelog_toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/timelog_primary"
android:minHeight="?attr/actionBarSize"
app:theme="#style/ThemeOverlay.AppCompat.ActionBar" />
<android.support.v4.widget.DrawerLayout
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".HomeActivity">
<!-- The main content view -->
<FrameLayout
android:id="#+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
<!-- The navigation drawer -->
<com.heinrichreimersoftware.material_drawer.DrawerView
android:id="#+id/drawer"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true" />
</android.support.v4.widget.DrawerLayout>
</LinearLayout>
I'm not able to post images yet (reputation too low), so below is a screenshot of my app uploaded to IMGUR:
http://i.imgur.com/IaFPzD1.png
Would anybody happen to implement this library? And were you able to show the profile part?
This is indeed an issue with current Version, i have solved it by updating the code with this pull request:
https://github.com/HeinrichReimer/material-drawer/pull/8

Categories

Resources