I'm trying to show a SnackBar on top below of the ToolBar in my MainActivity,
I've tried this code :
mToolbar = (Toolbar) findViewById(R.id.toolbar);
Snackbar snack = Snackbar.make(findViewById(android.R.id.content), "Had a snack at Snackbar", Snackbar.LENGTH_LONG);
View view = snack.getView();
FrameLayout.LayoutParams params =(FrameLayout.LayoutParams)view.getLayoutParams();
params.gravity = Gravity.TOP;
view.setLayoutParams(params);
snack.show();
but the SnackBar is showing on the top, but not below the Toolbar.
I want something similar to Hangout application like :
Main Activity:
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/Coordinator"
xmlns:fab="http://schemas.android.com/apk/res-auto"
tools:context=".MainActivity">
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar">
<ImageView
android:layout_width="75dp"
android:layout_height="28dp"
android:src="#drawable/athena"/>
</android.support.v7.widget.Toolbar>
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/progressBar5"
android:layout_marginTop="10dp"
android:layout_gravity="center_horizontal" />
<android.support.v4.widget.SwipeRefreshLayout
android:id="#+id/swipeRefreshLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="#+id/my_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="vertical" />
</android.support.v4.widget.SwipeRefreshLayout>
</LinearLayout>
<com.melnykov.fab.FloatingActionButton
android:id="#+id/add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
android:layout_margin="16dp"
fab:fab_colorNormal="#color/colorPrimary"
android:src="#drawable/ic_action_name9" />
</android.support.design.widget.CoordinatorLayout>
I'm using TSnackbar, the SnackBar is showing over the toolbar
TSnackbar.make(findViewById(android.R.id.content),"Hello from TSnackBar.",TSnackbar.LENGTH_LONG).show();
set margin on top of snackbar
Snackbar snack = Snackbar.make(findViewById(android.R.id.content), "Had a snack at Snackbar", Snackbar.LENGTH_LONG);
View view = snack.getView();
FrameLayout.LayoutParams params =(FrameLayout.LayoutParams)view.getLayoutParams();
params.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;
// calculate actionbar height
TypedValue tv = new TypedValue();
int actionBarHeight=0;
if (getTheme().resolveAttribute(R.attr.actionBarSize, tv, true))
{
actionBarHeight = TypedValue.complexToDimensionPixelSize(tv.data,getResources().getDisplayMetrics());
}
// set margin
params.setMargins(0, actionBarHeight, 0, 0);
view.setLayoutParams(params);
snack.show();
use PopupWindow using handler as
if(!topPopupWindow.isShowing()){
topPopupWindow.showAsDropDown(toolbar);
}
handler.removeMessages(0);
handler.sendEmptyMessageDelayed(0,2500);
This worked for me,
set top margin for your snackbar, consider your toolbar size:
View view = snack.getView();
CoordinatorLayout.LayoutParams params2 =(CoordinatorLayout.LayoutParams)view.getLayoutParams();
params2.setMargins(0,50,0,0);
I am giving below the code that I have used in my app and which is working properly for range of devices
Complie : compile 'com.androidadvance:topsnackbar:1.1.1'
define view :
private CoordinatorLayout CSnakbarLayout;
CSnakbarLayout = (CoordinatorLayout) rootView.findViewById(R.id.snackbar_event_mesg);
XML :
<android.support.design.widget.CoordinatorLayout
android:id="#+id/snackbar_event_mesg"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true">
</RelativeLayout>
</android.support.design.widget.CoordinatorLayout>
Below code in the activity / Fragment you want to implement the Snackbar from top :
/**
* Method to display message for on going Event
*/
private void displaySnackbar() {
int duration = 4000;
final TSnackbar snackbar = TSnackbar.make(CSnakbarLayout, getString(R.string.on_going_event_mesg), TSnackbar.LENGTH_INDEFINITE);
snackbar.setActionTextColor(Color.WHITE);
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
try {
snackbar.dismiss();
} catch (Exception e) {
e.printStackTrace();
}
}
}, duration);
snackbar.setAction("Ok", new View.OnClickListener() {
#Override
public void onClick(View view) {
snackbar.dismiss();
}
});
View snackbarView = snackbar.getView();
ViewGroup.LayoutParams params = snackbarView.getLayoutParams();
params.height = 300;
snackbarView.setLayoutParams(params);
snackbarView.setBackgroundColor(Color.BLACK);
TextView textView = (TextView) snackbarView.findViewById(com.androidadvance.topsnackbar.R.id.snackbar_text);
textView.setTextColor(Color.WHITE);
textView.setMaxLines(5);
snackbar.show();
}
Thank you :)
Got a solution in Kotlin, Give a try :)
val mainLayout: ConstraintLayout = root.findViewById(R.id.main_layout)
val button: Button = root.findViewById(R.id.button)
button.setOnClickListener {
val snackBar = TSnackbar.make(mainLayout, "Snacking with VectorDrawable", TSnackbar.LENGTH_INDEFINITE)
snackBar.setActionTextColor(Color.WHITE)
snackBar.setIconLeft(R.drawable.ic_announcement_black_24dp, 24f)
val snackBarView = snackBar.view
val tv = TypedValue()
if (activity!!.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true)) {
val actionBarHeight = TypedValue.complexToDimensionPixelSize(tv.data, resources.displayMetrics)
val params = view!!.getLayoutParams() as FrameLayout.LayoutParams
params.setMargins(0, actionBarHeight, 0, 0)
params.height = 70
snackBarView.setLayoutParams(params)
}
snackBarView.setBackgroundColor(Color.parseColor("#CC00CC"))
val textView = snackBarView.findViewById(com.androidadvance.topsnackbar.R.id.snackbar_text) as TextView
textView.setTextColor(Color.YELLOW)
snackBar.setIconPadding(10)
snackBar.show()
}
Thanks to #Shijil solution i've managed to display MinimalKSnack below the toolbar.
MinimalKSnack minimalKSnack = new MinimalKSnack(MainActivity.this);
minimalKSnack.setMessage(getResources().getString(R.string.notification))
.setStyle(MinimalKSnackStyle.STYLE_SUCCESS)
.setBackgroundColor(R.color.metallic_blue)
.setAnimation(Fade.In.getAnimation(), Fade.Out.getAnimation())
.setDuration(2000);
View view = minimalKSnack.getMinimalSnackView();
LinearLayout.LayoutParams params =(LinearLayout.LayoutParams)view.getLayoutParams();
params.gravity = Gravity.CENTER_VERTICAL | Gravity.TOP;
TypedValue typedValue = new TypedValue();
int actionBarHeight =0;
if(getTheme().resolveAttribute(R.attr.actionBarSize,typedValue,true)){
actionBarHeight = TypedValue.complexToDimensionPixelOffset(typedValue.data,getResources().getDisplayMetrics());
}
params.setMargins(0,actionBarHeight,0,0);
view.setLayoutParams(params);
minimalKSnack.show();
Github Library link onurkagan /
KSnack
Related
I have a linear layout like this:
<LinearLayout
android:id="#+id/linearLayoutImages"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal"
android:weightSum="1">
</LinearLayout>
The following function gets a bitmap, sets it to an image view that has been created programmatically, then creates a trash can icon and puts the whole things into a relative layout and finally puts it into the linear layout. But there is a problem, I want the result to be like this:
but the result becomes like this:
Code:
fun setImage(bitmap: Bitmap){
try {
val params = RelativeLayout.LayoutParams(375, 375)
params.addRule(RelativeLayout.ALIGN_PARENT_TOP)
params.setMargins(9,0,9,0)
val imageViewShowPic = ImageView(this)
imageViewShowPic.setLayoutParams(params)
imageViewShowPic.id = View.generateViewId()
imageViewShowPic.requestLayout()
val params2 = RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT,RelativeLayout.LayoutParams.WRAP_CONTENT)
val relativeLayout = RelativeLayout(this)
relativeLayout.setLayoutParams(params2)
relativeLayout.requestLayout()
val params3 = RelativeLayout.LayoutParams(75,75)
params3.addRule(RelativeLayout.BELOW,imageViewShowPic.id)
params3.addRule(RelativeLayout.CENTER_VERTICAL)
val imageButtonDelete = ImageButton(this)
imageButtonDelete.setLayoutParams(params3)
imageButtonDelete.requestLayout()
relativeLayout.addView(imageViewShowPic)
relativeLayout.addView(imageButtonDelete)
linearLayoutImages.addView(relativeLayout)
imageViewShowPic.setImageBitmap(bitmap)
imageButtonDelete.setImageResource(R.drawable.ic_delete)
imageButtonDelete.setOnClickListener {
linearLayoutImages.removeView(relativeLayout)
}
}
catch (ex:Exception)
{
Toast.makeText(this,ex.message,Toast.LENGTH_SHORT).show()
}
}
Update
The linear layout itself is in a horizontal scroll view, if it makes any difference.
<HorizontalScrollView
android:id="#+id/horizontalScrollViewImages"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:padding="10dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/buttonAddPic">
<LinearLayout
android:id="#+id/linearLayoutImages"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:weightSum="1"></LinearLayout>
</HorizontalScrollView>
(Posted solution on behalf of the question author).
I finally found the solution myself! I changed the relative layout to a vertical linear layout (I don't know if it matters or not):
val params2 = LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT)
val linearLayout = LinearLayout(this)
linearLayout.setLayoutParams(params2)
linearLayout.orientation = LinearLayout.VERTICAL
linearLayout.requestLayout()
and then set the width of imageButtonDelete to match parent.
val params3 = LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)
val imageButtonDelete = ImageButton(this)
imageButtonDelete.setLayoutParams(params3)
imageButtonDelete.requestLayout()
imageButtonDelete.setBackgroundColor(Color.TRANSPARENT)
Set (RelativeLayout.CENTER_VERTICAL) to (RelativeLayout.CENTER)
val params3 = RelativeLayout.LayoutParams(75,75)
params3.addRule(RelativeLayout.BELOW,imageViewShowPic.id)
params3.addRule(RelativeLayout.CENTER)
and
android:layout_width="wrap_content" to android:layout_width="match_parent"
<LinearLayout
android:id="#+id/linearLayoutImages"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:weightSum="1"></LinearLayout>
With the below code you can achieve the desired output.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/linearLayoutImages"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="horizontal"
android:weightSum="1"></LinearLayout>
In Your activity.
try {
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(375, 375);
params.addRule(RelativeLayout.ALIGN_PARENT_TOP);
params.setMargins(9, 0, 9, 0);
ImageView imageViewShowPic = new ImageView(this);
imageViewShowPic.setLayoutParams(params);
imageViewShowPic.setId(View.generateViewId());
imageViewShowPic.requestLayout();
RelativeLayout.LayoutParams params2 = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
RelativeLayout relativeLayout = new RelativeLayout(this);
relativeLayout.setLayoutParams(params2);
relativeLayout.requestLayout();
RelativeLayout.LayoutParams params3 = new RelativeLayout.LayoutParams(75, 75);
params3.addRule(RelativeLayout.BELOW, imageViewShowPic.getId());
params3.topMargin = 30;
params3.addRule(RelativeLayout.CENTER_HORIZONTAL);
ImageButton imageButtonDelete = new ImageButton(this);
imageButtonDelete.setLayoutParams(params3);
imageButtonDelete.requestLayout();
relativeLayout.addView(imageViewShowPic);
relativeLayout.addView(imageButtonDelete);
linearLayoutImages.addView(relativeLayout);
imageViewShowPic.setImageResource(R.drawable.ic_launcher_background);
imageButtonDelete.setImageResource(R.drawable.ic_launcher_background);
} catch (Exception ex) {
Toast.makeText(this, ex.getMessage(), Toast.LENGTH_SHORT).show();
}
OUTPUT
I am creating an android application in which i want to use Snack Bar,
In a that snack bar i want 2 different words on which we have to perform 2 different actions.
From the Google design specifications:
Each snackbar may contain a single action, neither of which may be “Dismiss” or “Cancel.”
For multiple actions, use a dialog.
Thanks Shailesh, I had to modify the code in order to make it work for me.
my_snackbar.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:id="#+id/my_snackbar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/dark_grey"
android:padding="15dp">
<TextView
android:id="#+id/message_text_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight=".6"
android:gravity="center_vertical"
android:text="Two button snackbar"
android:textColor="#color/white"/>
<TextView
android:id="#+id/first_text_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight=".2"
android:gravity="center"
android:text="ONE"
android:textColor="#FFDEAD"/>
<TextView
android:id="#+id/second_text_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight=".2"
android:gravity="center"
android:text="TWO"
android:textColor="#FFDEAD"/>
</LinearLayout>
In your activity call this method whenever you want to show the snackbar:
private void showTwoButtonSnackbar() {
// Create the Snackbar
LinearLayout.LayoutParams objLayoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
snackbar = Snackbar.make(this.findViewById(android.R.id.content), message, Snackbar.LENGTH_INDEFINITE);
// Get the Snackbar layout view
Snackbar.SnackbarLayout layout = (Snackbar.SnackbarLayout) snackbar.getView();
// Set snackbar layout params
int navbarHeight = getNavBarHeight(this);
FrameLayout.LayoutParams parentParams = (FrameLayout.LayoutParams) layout.getLayoutParams();
parentParams.setMargins(0, 0, 0, 0 - navbarHeight + 50);
layout.setLayoutParams(parentParams);
layout.setPadding(0, 0, 0, 0);
layout.setLayoutParams(parentParams);
// Inflate our custom view
View snackView = getLayoutInflater().inflate(R.layout.my_snackbar, null);
// Configure our custom view
TextView messageTextView = (TextView) snackView.findViewById(R.id.message_text_view);
messageTextView.setText(message);
TextView textViewOne = (TextView) snackView.findViewById(R.id.first_text_view);
textViewOne.setText("ALLOW");
textViewOne.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d("Allow", "showTwoButtonSnackbar() : allow clicked");
snackbar.dismiss();
}
});
TextView textViewTwo = (TextView) snackView.findViewById(R.id.second_text_view);
textViewTwo.setText("DENY");
textViewTwo.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d("Deny", "showTwoButtonSnackbar() : deny clicked");
snackbar.dismiss();
}
});
// Add our custom view to the Snackbar's layout
layout.addView(snackView, objLayoutParams);
// Show the Snackbar
snackbar.show();
}
To get nav bar height:
public static int getNavBarHeight(Context context) {
int result = 0;
int resourceId = context.getResources().getIdentifier("navigation_bar_height", "dimen", "android");
if (resourceId > 0) {
result = context.getResources().getDimensionPixelSize(resourceId);
}
return result;
}
As #Elias N answer's each Snackbar may contain a single action. If you want to set more then action in Snackbar then you need to create your own layout. Please try this i hope this will help you.
Create one xml file my_snackbar.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#000000">
<TextView
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_weight=".7"
android:gravity="center_vertical"
android:text="Please select any one"
android:textColor="#color/white"/>
<TextView
android:id="#+id/txtOne"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_weight=".1"
android:gravity="center"
android:text="ONE"
android:textColor="#color/red"/>
<TextView
android:id="#+id/txtTwo"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_weight=".1"
android:gravity="center"
android:text="TWO"
android:textColor="#color/red"/>
</LinearLayout>
Now in your activity file do the following code.
public void myCustomSnackbar()
{
// Create the Snackbar
LinearLayout.LayoutParams objLayoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
Snackbar snackbar = Snackbar.make(llShow, "", Snackbar.LENGTH_LONG);
// Get the Snackbar's layout view
Snackbar.SnackbarLayout layout = (Snackbar.SnackbarLayout) snackbar.getView();
layout.setPadding(0,0,0,0);
// Hide the text
TextView textView = (TextView) layout.findViewById(android.support.design.R.id.snackbar_text);
textView.setVisibility(View.INVISIBLE);
LayoutInflater mInflater = (LayoutInflater)getSystemService(LAYOUT_INFLATER_SERVICE);
// Inflate our custom view
View snackView = getLayoutInflater().inflate(R.layout.my_snackbar, null);
// Configure the view
TextView textViewOne = (TextView) snackView.findViewById(R.id.txtOne);
textViewOne.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.i("One", "First one is clicked");
}
});
TextView textViewTwo = (TextView) snackView.findViewById(R.id.txtTwo);
textViewTwo.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.i("Two", "Second one is clicked");
}
});
// Add the view to the Snackbar's layout
layout.addView(snackView, objLayoutParams);
// Show the Snackbar
snackbar.show();
}
For more detail please read this documentation and here.
You can use BottomSheetDialog and disguise it as a SnackBar. Only difference would be that it will be dismissed by swiping down instead of right and it can stay there until user dismissed it while SnackBar eventually fades away.
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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:id="#+id/fragment_history_menu_bottom"
style="#style/Widget.Design.BottomNavigationView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:orientation="horizontal"
android:background="#color/cardview_dark_background"
app:layout_behavior="android.support.design.widget.BottomSheetBehavior">
<android.support.v7.widget.AppCompatTextView
android:id="#+id/appCompatTextView"
android:layout_width="wrap_content"
android:layout_height="19dp"
android:layout_gravity="center_vertical"
android:layout_marginStart="8dp"
android:layout_weight="0.6"
android:text="Load More ?"
android:textAppearance="#style/TextAppearance.Design.Snackbar.Message"
android:textColor="#color/cardview_light_background"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:id="#+id/fragment_history_bottom_sheet_delete"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right|end"
android:layout_weight="0.4"
android:clickable="true"
android:focusable="true"
android:foreground="?android:attr/selectableItemBackground"
android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<android.support.v7.widget.AppCompatButton
style="#style/Widget.AppCompat.Button.Borderless.Colored"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Yes" />
<android.support.v7.widget.AppCompatButton
style="#style/Widget.AppCompat.Button.Borderless"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="No"
android:textColor="#color/cardview_light_background" />
</LinearLayout>
</android.support.constraint.ConstraintLayout>
and use it as following (Kotlin)
val dialog = BottomSheetDialog(this)
dialog.setContentView(this.layoutInflater.inflate(R.layout.bottom_sheet_load_prompt,null))
dialog.show()
result will be similar to SnackBar
Here is a proper solution with Kotlin I first deployed it when working on Fulguris.
Using Kotlin extension we expand our Snackbar class as follows:
/**
* Adds an extra action button to this snackbar.
* [aLayoutId] must be a layout with a Button as root element.
* [aLabel] defines new button label string.
* [aListener] handles our new button click event.
*/
fun Snackbar.addAction(#LayoutRes aLayoutId: Int, #StringRes aLabel: Int, aListener: View.OnClickListener?) : Snackbar {
addAction(aLayoutId,context.getString(aLabel),aListener)
return this;
}
/**
* Adds an extra action button to this snackbar.
* [aLayoutId] must be a layout with a Button as root element.
* [aLabel] defines new button label string.
* [aListener] handles our new button click event.
*/
fun Snackbar.addAction(#LayoutRes aLayoutId: Int, aLabel: String, aListener: View.OnClickListener?) : Snackbar {
// Add our button
val button = LayoutInflater.from(view.context).inflate(aLayoutId, null) as Button
// Using our special knowledge of the snackbar action button id we can hook our extra button next to it
view.findViewById<Button>(R.id.snackbar_action).let {
// Copy layout
button.layoutParams = it.layoutParams
// Copy colors
(button as? Button)?.setTextColor(it.textColors)
(it.parent as? ViewGroup)?.addView(button)
}
button.text = aLabel
/** Ideally we should use [Snackbar.dispatchDismiss] instead of [Snackbar.dismiss] though that should do for now */
//extraView.setOnClickListener {this.dispatchDismiss(BaseCallback.DISMISS_EVENT_ACTION); aListener?.onClick(it)}
button.setOnClickListener {this.dismiss(); aListener?.onClick(it)}
return this;
}
We then need to define our button resource:
<?xml version="1.0" encoding="utf-8"?>
<!--
Used to create and extra button in our snackbar popup messages.
Though most properties including layout params and colors are overridden at runtime.
They are just copied from the standard snackbar action button to make sure they both lookalike.
-->
<Button xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/snackbar_extra_action"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="0dp"
android:layout_marginStart="0dp"
android:layout_gravity="center_vertical|right|end"
android:paddingTop="14dp"
android:paddingBottom="14dp"
android:paddingLeft="12dp"
android:paddingRight="12dp"
android:textColor="?attr/colorAccent"
style="?attr/borderlessButtonStyle"/>
Here is how you use it:
Snackbar.make(aView, aMessage, aDuration).setAction(R.string.button_one) {
// Do your thing after regular button press
}.addAction(R.layout.snackbar_extra_button, R.string.button_two){
//Do your thing after extra button push
}.show()
Another hacky workaround you could try (works in my case).
final Snackbar snackbar = Snackbar.make(view, "UNDO MARKED AS READ", Snackbar.LENGTH_LONG);
snackbar.setAction("DISMISS", new View.OnClickListener() {
#Override
public void onClick(View v) {
if (snackbar != null)
snackbar.dismiss();
}
});
View snackbarView = snackbar.getView();
int snackbarTextId = android.support.design.R.id.snackbar_text;
TextView textView = (TextView) snackbarView.findViewById(snackbarTextId);
textView.setTextColor(Color.WHITE);
textView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (snackbar != null)
snackbar.dismiss();
// undo mark as unread code
}
});
snackbar.show();
Following Shaileshs solution:
snackbar class
public class SnackbarOfflineErrorNotification {
/**
* A view from the content layout.
*/
#NonNull
private final View view;
#NonNull
private Context context;
/**
* The snack bar being shown.
*/
#Nullable
private Snackbar snackbar = null;
/**
* Construct a new instance of the notification.
*
* #param view A view from the content layout, used to seek an appropriate anchor for the
* Snackbar.
*/
public SnackbarOfflineErrorNotification(#NonNull final View view, #NonNull Context context) {
this.view = view;
this.context = context;
}
public void showOfflineError (){
if (snackbar == null){
//create snackbar
snackbar = Snackbar.make(this.view, R.string.offline_text, LENGTH_INDEFINITE);
// Create the Snackbar
LinearLayout.LayoutParams objLayoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
// Get the Snackbar's layout view
Snackbar.SnackbarLayout layout = (Snackbar.SnackbarLayout) snackbar.getView();
layout.setPadding(0,0,0,0);
// Hide the text
TextView textView = (TextView) layout.findViewById(android.support.design.R.id.snackbar_text);
textView.setVisibility(View.INVISIBLE);
// Inflate our custom view
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View snackView = inflater.inflate(R.layout.snackbar_offline, null);
// Configure the view
Button btnOne = (Button) snackView.findViewById(R.id.btnOne);
btnOne.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// action 1
}
});
Button btnTwo = (Button) snackView.findViewById(R.id.btnTwo);
btnTwo.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// action 2
}
});
// Add the view to the Snackbar's layout
layout.addView(snackView, objLayoutParams);
// Show the Snackbar
snackbar.show();
}
}
/**
* Hides the currently displayed error.
*/
public void hideError() {
if (snackbar != null) {
snackbar.dismiss();
snackbar = null;
}
}
}
snackbar xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#000000">
<TextView
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_weight=".7"
android:gravity="center_vertical"
android:text="offline"
android:textColor="#color/white"
android:paddingLeft="16dp"/>
<Button
android:id="#+id/btnOne"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_weight=".1"
android:gravity="center"
android:text="one" />
<Button
android:id="#+id/btnTwo"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_weight=".1"
android:gravity="center"
android:text="two"/>
</LinearLayout>
target activity
constructor(){
snackbarOfflineErrorNotification = new SnackbarOfflineErrorNotification(findViewById(R.id.coordinator_layout), getApplicationContext());
}
public void hideSnackbar(){
snackbarOfflineErrorNotification.hideError();
}
public showSnackbar(){
snackbarOfflineErrorNotification.showOfflineError();
}
You can use "dismiss" as another actions
Snackbar snackbar = Snackbar.make(requireView(), "Marked as read", BaseTransientBottomBar.LENGTH_SHORT);
snackbar.setAction("undo", view -> {
//undo action
});
snackbar.addCallback(new Snackbar.Callback() {
#Override
public void onDismissed(Snackbar transientBottomBar, int event) {
//dismiss action
}
});
snackbar.show();
I have problem with setting Snackbar on tablet (API 22), on phones (API 23 and 22) it works fine (from edge to edge), even when horizontal.
Result is such Snackbar as below:
FloatingActionButton (support library) also doesn't move (when on phone it does).
My layout:
<?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:id="#+id/snackParent"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="#+id/frame"
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|right"
android:layout_marginBottom="#dimen/margin_fab"
android:layout_marginRight="#dimen/margin_fab"
app:pressedTranslationZ="12dp" />
</android.support.design.widget.CoordinatorLayout>
And using in MainActivity
private void showMessage(String msg) {
if(snackParent != null) {
snackbar = Snackbar.make(snackParent, msg, Snackbar.LENGTH_SHORT);
snackbar.setAction("OK", new View.OnClickListener() {
#Override
public void onClick(View v) {
snackbar.dismiss();
}
});
snackbar.show();
}
}
I have only other resources file with dimensions (fab margin) for tablets (w820dp), styles folder is same between phone and tablet. I have also tried invalidating Android Studio cache.
I use com.android.support:design:23.0.1 targetSdkVersion=23 and compileSdkVersion=23, buildToolsVersion=23.0.1.
I think this is the default behavior of snackbar on tablets. check this out .
You can do whatever you want with your snackbar. We had the same issue with tablets and we solved like this (e.g. code below is positioning snackbar at top and gives it the full width of the parent)
View view = snackbar.getView();
// Position snackbar at top
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams)view.getLayoutParams();
params.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL;
params.width = FrameLayout.LayoutParams.MATCH_PARENT;
view.setLayoutParams(params);
ViewGroup.LayoutParams layoutParams = snackbarView.getLayoutParams();
if (layoutParams instanceof FrameLayout.LayoutParams) {
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) layoutParams;
params.gravity = Gravity.TOP;
params.width = FrameLayout.LayoutParams.MATCH_PARENT;
snackbarView.setLayoutParams(params);
} else if (layoutParams instanceof CoordinatorLayout.LayoutParams) {
CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) layoutParams;
params.gravity = Gravity.TOP;
params.width = FrameLayout.LayoutParams.MATCH_PARENT;
snackbarView.setLayoutParams(params);
} else {
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) layoutParams;
params.gravity = Gravity.TOP;
params.width = FrameLayout.LayoutParams.MATCH_PARENT;
snackbarView.setLayoutParams(params);
}
After digging into code from github. I found one workaround. You just need to add below lines into styles.xml. Change the width as per your requirement
<style name="Widget.Design.Snackbar" parent="android:Widget">
<item name="maxActionInlineWidth">500dp</item>
</style>
If you want to change number of lines of default textview of Snackbar, you can change following style.
<style name="Widget.MaterialComponents.Snackbar.TextView" parent="Widget.AppCompat.TextView">
<item name="android:maxLines">3</item>
</style>
As the Android documentation says
Snackbars provide lightweight feedback about an operation. They show a brief message at the bottom of the screen on mobile and lower left on larger devices.
Is there any alternative by which we can show snackbars at top of the screen instead of the bottom?
Right now I am doing something like this which shows a snackbar at the bottom of the screen.
Snackbar.make(findViewById(android.R.id.content), "Hello this is a snackbar!!!",
Snackbar.LENGTH_LONG).setAction("Undo", mOnClickListener)
.setActionTextColor(Color.RED)
.show();
It is possible to make the snackbar appear on top of the screen using this:
Snackbar snack = Snackbar.make(parentLayout, str, Snackbar.LENGTH_LONG);
View view = snack.getView();
FrameLayout.LayoutParams params =(FrameLayout.LayoutParams)view.getLayoutParams();
params.gravity = Gravity.TOP;
view.setLayoutParams(params);
snack.show();
From the OP:
I had to change the first line:
Snackbar snack = Snackbar.make(findViewById(android.R.id.content), "Had a snack at Snackbar", Snackbar.LENGTH_LONG);
CoordinatorLayout coordinatorLayout=(CoordinatorLayout)findViewById(R.id.coordinatorLayout);
Snackbar snackbar = Snackbar.make(coordinatorLayout, "Text", Snackbar.LENGTH_LONG);
View view = snackbar.getView();
CoordinatorLayout.LayoutParams params=(CoordinatorLayout.LayoutParams)view.getLayoutParams();
params.gravity = Gravity.TOP;
view.setLayoutParams(params);
snackbar.show();
Kotlin-
val snackBarView = Snackbar.make(view, "SnackBar Message" , Snackbar.LENGTH_LONG)
val view = snackBarView.view
val params = view.layoutParams as FrameLayout.LayoutParams
params.gravity = Gravity.TOP
view.layoutParams = params
view.background = ContextCompat.getDrawable(context,R.drawable.custom_drawable) // for custom background
snackBarView.animationMode = BaseTransientBottomBar.ANIMATION_MODE_FADE
snackBarView.show()
below line will resolve the animation issue.
snackBarView.animationMode = BaseTransientBottomBar.ANIMATION_MODE_FADE
Alternate solution-
snackBarView.anchorView = mention viewId above whom you want to show SnackBar
You can do the following to position a SnackBar anywhere inside a layout (This method has No Animation Issues)
1) According to:
https://developer.android.com/reference/android/support/design/widget/Snackbar.html#make(android.view.View, java.lang.CharSequence, int)
Snackbar make (View view,
CharSequence text,
int duration)
Make a Snackbar to display a message Snackbar will try and find a parent view to hold Snackbar's view from
the value given to view. Snackbar will walk up the view tree trying to
find a suitable parent, which is defined as a CoordinatorLayout or the
window decor's content view, whichever comes first.
So, one can position a snackBar anywhere inside a layout simply by adding a Coordinator Layout in the desired location and using that Coordinator Layout as the view argument inside Snackbar.make method above.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".MainActivity"
android:orientation="vertical"
android:id="#+id/rl"
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Coordinator Layout used to position the SnackBar -->
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/cl"
android:layout_alignParentTop="true"
android:background="#android:color/transparent">
</android.support.design.widget.CoordinatorLayout>
<!-- add your layout here -->
</RelativeLayout>
2) The Coordinator Layout used to display the SnackBar should be on top of all other views (highest elevation). In order to do that, one might either call bringToFront() on the coordinator layout or elevate the coordinator layout (add
android:elevation="10dp" for example)
3) At this point the snackBar will show up in the desired location, but the snackBar is displayed with a bottom to top animation (default behavior). In order to achieve a top to bottom animation, you can do the following:
Rotate Coordinator layout used inside Snackbar.make method by 180 degrees
4) After step 3, the snackBar will be displayed with a top to bottom animation, but the message and action text are rotated and the gravity is reversed, so as a final step, I did the following:
Got SnackBar View, found the LinearLayout holding the TextView responsible about displaying the message and the TextView responsible about the action, and rotated the parent LinearLayout by 180 degress
5) Example:
public class MainActivity extends AppCompatActivity {
private final String TAG = MainActivity.class.getSimpleName();
private RelativeLayout rl;
private CoordinatorLayout cl;
private CoordinatorLayout cl1;
private CoordinatorLayout cl2;
private CoordinatorLayout cl3;
private CoordinatorLayout cl4;
private Snackbar snackbar_updated;
private Snackbar snackbar_updated1;
private Snackbar snackbar_updated2;
private Snackbar snackbar_updated3;
private Snackbar snackbar_updated4;
private Snackbar snackbar_ordinary;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
rl = (RelativeLayout) findViewById(R.id.rl);
cl = (CoordinatorLayout) findViewById(R.id.cl);
cl1 = (CoordinatorLayout) findViewById(R.id.cl1);
cl2 = (CoordinatorLayout) findViewById(R.id.cl2);
cl3 = (CoordinatorLayout) findViewById(R.id.cl3);
cl4 = (CoordinatorLayout) findViewById(R.id.cl4);
cl.bringToFront();
cl1.bringToFront();
cl2.bringToFront();
cl3.bringToFront();
cl4.bringToFront();
snackbar_updated = Snackbar.make(cl, "Message", Snackbar.LENGTH_INDEFINITE);
snackbar_updated.setAction("Ok", new View.OnClickListener() {
#Override
public void onClick(View view) {
}
});
/** Snackbar message and action TextViews are placed inside a LinearLayout
*/
final Snackbar.SnackbarLayout snackBarLayout = (Snackbar.SnackbarLayout) snackbar_updated.getView();
for (int i = 0; i < snackBarLayout.getChildCount(); i++) {
View parent = snackBarLayout.getChildAt(i);
if (parent instanceof LinearLayout) {
((LinearLayout) parent).setRotation(180);
break;
}
}
snackbar_updated1 = Snackbar.make(cl1, "Message", Snackbar.LENGTH_INDEFINITE);
snackbar_updated1.setAction("Ok", new View.OnClickListener() {
#Override
public void onClick(View view) {
}
});
/** Snackbar message and action TextViews are placed inside a LinearLayout
*/
final Snackbar.SnackbarLayout snackBarLayout1 = (Snackbar.SnackbarLayout) snackbar_updated1.getView();
for (int i = 0; i < snackBarLayout1.getChildCount(); i++) {
View parent = snackBarLayout1.getChildAt(i);
if (parent instanceof LinearLayout) {
((LinearLayout) parent).setRotation(180);
break;
}
}
snackbar_updated2 = Snackbar.make(cl2, "Message", Snackbar.LENGTH_INDEFINITE);
snackbar_updated2.setAction("Ok", new View.OnClickListener() {
#Override
public void onClick(View view) {
}
});
snackbar_updated3 = Snackbar.make(cl3, "Message", Snackbar.LENGTH_INDEFINITE);
snackbar_updated3.setAction("Ok", new View.OnClickListener() {
#Override
public void onClick(View view) {
}
});
/** Snackbar message and action TextViews are placed inside a LinearLayout
*/
Snackbar.SnackbarLayout snackBarLayout3 = (Snackbar.SnackbarLayout) snackbar_updated3.getView();
for (int i = 0; i < snackBarLayout3.getChildCount(); i++) {
View parent = snackBarLayout3.getChildAt(i);
if (parent instanceof LinearLayout) {
((LinearLayout) parent).setRotation(180);
break;
}
}
snackbar_updated4 = Snackbar.make(cl4, "Message", Snackbar.LENGTH_INDEFINITE);
snackbar_updated4.setAction("Ok", new View.OnClickListener() {
#Override
public void onClick(View view) {
}
});
snackbar_ordinary = Snackbar.make(rl, "Message", Snackbar.LENGTH_INDEFINITE);
snackbar_ordinary.setAction("Ok", new View.OnClickListener() {
#Override
public void onClick(View view) {
}
});
rl.post(new Runnable() {
#Override
public void run() {
snackbar_updated.show();
rl.postDelayed(new Runnable() {
#Override
public void run() {
snackbar_updated1.show();
rl.postDelayed(new Runnable() {
#Override
public void run() {
snackbar_updated2.show();
rl.postDelayed(new Runnable() {
#Override
public void run() {
snackbar_updated3.show();
rl.postDelayed(new Runnable() {
#Override
public void run() {
snackbar_updated4.show();
rl.postDelayed(new Runnable() {
#Override
public void run() {
snackbar_ordinary.show();
}
}, 2000);
}
}, 2000);
}
}, 2000);
}
}, 2000);
}
}, 2000);
}
});
}
}
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".MainActivity"
android:orientation="vertical"
android:id="#+id/rl"
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Coordinator Layout used to position the SnackBar -->
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/cl"
android:rotation="180"
android:layout_alignParentTop="true"
android:background="#android:color/transparent">
</android.support.design.widget.CoordinatorLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentTop="true"
android:orientation="vertical">
<android.support.design.widget.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:itemIconTint="#333"
app:itemTextColor="#333"
app:layout_collapseMode="pin"
app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="#style/ThemeOverlay.AppCompat.Dark"
app:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"/>
</android.support.design.widget.AppBarLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_below="#id/appbar"
android:layout_gravity="bottom">
<TextView
android:layout_width="match_parent"
android:layout_height="30dp"
android:id="#+id/tv_top"
android:text="Layout Top"
android:gravity="center"
android:textSize="15sp"
android:textColor="#android:color/white"
android:layout_alignParentTop="true"
android:background="#color/colorAccent">
</TextView>
<!-- Coordinator Layout used to position the SnackBar -->
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/cl1"
android:rotation="180"
android:layout_below="#id/tv_top"
android:background="#android:color/transparent">
</android.support.design.widget.CoordinatorLayout>
<!-- Coordinator Layout used to position the SnackBar -->
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/cl2"
android:paddingBottom="75dp"
android:layout_centerInParent="true"
android:background="#android:color/transparent">
</android.support.design.widget.CoordinatorLayout>
<!-- Coordinator Layout used to position the SnackBar -->
<TextView
android:layout_width="match_parent"
android:layout_height="30dp"
android:id="#+id/tv_center"
android:text="Center"
android:gravity="center"
android:textSize="15sp"
android:layout_centerInParent="true"
android:textColor="#android:color/white"
android:background="#color/colorAccent">
</TextView>
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/cl3"
android:rotation="180"
android:paddingBottom="75dp"
android:layout_centerInParent="true"
android:background="#android:color/transparent">
</android.support.design.widget.CoordinatorLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="30dp"
android:id="#+id/tv_bottom"
android:text="Layout Bottom"
android:gravity="center"
android:textSize="15sp"
android:textColor="#android:color/white"
android:layout_alignParentBottom="true"
android:background="#color/colorAccent">
</TextView>
<!-- Coordinator Layout used to position the SnackBar -->
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/cl4"
android:layout_above="#id/tv_bottom"
android:background="#android:color/transparent">
</android.support.design.widget.CoordinatorLayout>
</RelativeLayout>
</RelativeLayout>
</RelativeLayout>
6) Result:
Combined solution from the above ones:
final ViewGroup.LayoutParams params = snackbar.getView().getLayoutParams();
if (params instanceof CoordinatorLayout.LayoutParams) {
((CoordinatorLayout.LayoutParams) params).gravity = Gravity.TOP;
} else {
((FrameLayout.LayoutParams) params).gravity = Gravity.TOP;
}
snackbar.getView().setLayoutParams(params);
Still suffers from the improper animation.
This makes the Snackbar appears on Top without the strange slide in transition.
Best simple solution in Kotlin:
val snackbar = Snackbar.make(view, string, Snackbar.LENGTH_LONG)
val layoutParams = LayoutParams(snackbar.view.layoutParams)
layoutParams.gravity = Gravity.TOP
snackbar.view.setPadding(0, 10, 0, 0)
snackbar.view.layoutParams = layoutParams
snackbar.animationMode = BaseTransientBottomBar.ANIMATION_MODE_FADE
snackbar.show()
Idiomatic Kotlin version
snackbar.view.layoutParams = (snackbar.view.layoutParams as FrameLayout.LayoutParams).apply {
gravity = Gravity.TOP
}
Kotlin extension
/** Kotlin extension that adds this snackbar at the top of the screen. */
fun Snackbar.gravityTop() {
this.view.layoutParams = (this.view.layoutParams as FrameLayout.LayoutParams).apply {
gravity = Gravity.TOP
}
}
Then just call:
snackbar.gravityTop()
Before displaying the Snackbar, please add the following code
View snackbarView = snackbar.getView();
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) snackbarView.getLayoutParams();
params.gravity = Gravity.TOP;
snackbarView.setLayoutParams(params);
snackbarView.startAnimation(AnimationUtils.loadAnimation(host, R.anim.slide_in_snack_bar));
And when dismiss()
View snackbarView = snackbar.getView();
snackbarView.startAnimation(AnimationUtils.loadAnimation(_snackbar.getContext(), R.anim.slide_out_snack_bar));
snackbar.dismiss()
slide_in_snack_bar.xml
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="#android:integer/config_longAnimTime"
android:fromYDelta="-100%p"
android:toYDelta="0%p" />
slide_out_snack_bar.xml
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="#android:integer/config_longAnimTime"
android:fromYDelta="0%p"
android:toYDelta="-100%p" />
if you are using Constraintlayoutas as the root parent, with the help of Guidelines and CoordinatorLayout you can try this:
changing the value of: layout_constraintGuide_end="Your bottom margin value" inside Guideline as below example.
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="#+id/coordinator"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="#id/guideline3" />
<androidx.constraintlayout.widget.Guideline
android:id="#+id/guideline3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_end="150dp" />
in the activty you can pass CoordinatorLayout as the view for the snackbar
mSnackBar = Snackbar.make(
coordinator,
getString(R.string.no_internet_connection),
Snackbar.LENGTH_INDEFINITE
)
mSnackBar.show()
why not anchor it to some other view say you have other views in layout just anchor the snackbar to some view so that it displays there for example:
<LinearLayout>
......<Button>
<LinearLayout>
<TextView>
</LinearLayout>
</LinearLayout>
in code:
Snackbar snackbar = Snackbar.make(view,message, snackbar.LENGTH_SHORT).setAnchorView(R.id.reg_button);
R.id.reg_button is the button in the layout it can be anywhere snackbar will show up right there
No need to use any frame etc app will function as expected will not crash
2 years later, here's my solution..
Setting the Top and Bottom Margin changes the effect result,... I have tried to add as much customization options as i could, Overriding the animation is another option not written here.
Thanks to everyone's answers on several questions...
{
// usage for setSnackBar
int view = R.id.toolbar;
String snackMessage = "";
boolean useAction = false;
Runnable ifUseActionRunnable = null;
String actionText = "";
int leftMargin = 0;
int topMargin = 0;
int rightMargin = 0;
int bottomMargin = 0;
int backgroundColour = Color.BLACK;
int textColor = Color.WHITE;
int duration = Snackbar.LENGTH_LONG;
setSnackBar(view, snackMessage, useAction, ifUseActionRunnable, actionText, leftMargin, topMargin, rightMargin, bottomMargin, backgroundColour, textColor, duration);
}
Snackbar snb;
public void setSnackBar(int targetView, String snackMessage, boolean useAction, final Runnable ifUseActionRunnable, String actionText , int leftMargin, int topMargin, int rightMargin, int bottomMargin, int backgroundColour, int textColor, int duration)
{
snb = Snackbar.make(findViewById(targetView), snackMessage, duration);
View view = snb.getView();
view.setBackgroundColor(backgroundColour);
snb.setActionTextColor(textColor);
FrameLayout.LayoutParams params =(FrameLayout.LayoutParams)view.getLayoutParams();
params.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;
params.setMargins(leftMargin, topMargin, rightMargin, bottomMargin);
view.setLayoutParams(params);
if (useAction)
{
snb.setAction(actionText, new View.OnClickListener(){
#Override
public void onClick(View p1)
{
ifUseActionRunnable.run();
}
});
}
if (snb.isShown())
{
snb.dismiss();
snb.show();
}
else
{
snb.show();
}
}
to show Snackbar at top of the screen (kotlin)
// Custom snackbar : banner model
val customSnackBar = Snackbar.make(snackbar_id, "", Snackbar.LENGTH_INDEFINITE)
val view = customSnackBar.view
val params = view.layoutParams as CoordinatorLayout.LayoutParams
params.gravity = Gravity.TOP
view.layoutParams = params
val layout = customSnackBar.view as Snackbar.SnackbarLayout
val customSnackView = layoutInflater.inflate(R.layout.snackbar_banner, null)
val actionButton1 = customSnackView.findViewById(R.id.action_button_1) as MaterialButton
actionButton1.setOnClickListener {
customSnackBar.dismiss()
}
val actionButton = customSnackView.findViewById(R.id.action_button_2) as MaterialButton
actionButton.setOnClickListener {
customSnackBar.dismiss()
}
// We can also customize the above controls
layout.setPadding(0, 0, 0, 0)
layout.addView(customSnackView, 0)
customSnackBar.show()
XML:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="#android:color/white"
>
<TextView
android:padding="16dp"
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/snackbar_banner_message"
android:textColor="#android:color/black"
android:textSize="16sp" />
<LinearLayout
android:gravity="end"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:orientation="horizontal">
<com.google.android.material.button.MaterialButton
android:id="#+id/action_button_1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_weight="1"
android:background="#android:color/black"
android:text="Close"
style="#style/Widget.MaterialComponents.Button.TextButton"
/>
<com.google.android.material.button.MaterialButton
android:id="#+id/action_button_2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="#android:color/black"
android:text="Fix it"
android:textStyle="bold"
style="#style/Widget.MaterialComponents.Button.TextButton"
/>
</LinearLayout>
</LinearLayout>
I am trying to use the following code to center the text in the ActionBar, but it aligns itself to the left.
How do you make it appear in the center?
ActionBar actionBar = getActionBar();
actionBar.setDisplayShowTitleEnabled(true);
actionBar.setTitle("Canteen Home");
actionBar.setHomeButtonEnabled(true);
actionBar.setIcon(R.drawable.back);
To have a centered title in ABS (if you want to have this in the default ActionBar, just remove the "support" in the method names), you could just do this:
In your Activity, in your onCreate() method:
getSupportActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
getSupportActionBar().setCustomView(R.layout.abs_layout);
abs_layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="vertical">
<androidx.appcompat.widget.AppCompatTextView
android:id="#+id/tvTitle"
style="#style/TextAppearance.AppCompat.Widget.ActionBar.Title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:textColor="#FFFFFF" />
</LinearLayout>
Now you should have an Actionbar with just a title. If you want to set a custom background, set it in the Layout above (but then don't forget to set android:layout_height="match_parent").
or with:
getSupportActionBar().setBackgroundDrawable(getResources().getDrawable(R.drawable.yourimage));
I haven't had much success with the other answers... below is exactly what worked for me on Android 4.4.3 using the ActionBar in the support library v7. I have it set up to show the navigation drawer icon ("burger menu button")
XML
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:id="#+id/actionbar_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:maxLines="1"
android:clickable="false"
android:focusable="false"
android:longClickable="false"
android:textStyle="bold"
android:textSize="18sp"
android:textColor="#FFFFFF" />
</LinearLayout>
Java
//Customize the ActionBar
final ActionBar abar = getSupportActionBar();
abar.setBackgroundDrawable(getResources().getDrawable(R.drawable.actionbar_background));//line under the action bar
View viewActionBar = getLayoutInflater().inflate(R.layout.actionbar_titletext_layout, null);
ActionBar.LayoutParams params = new ActionBar.LayoutParams(//Center the textview in the ActionBar !
ActionBar.LayoutParams.WRAP_CONTENT,
ActionBar.LayoutParams.MATCH_PARENT,
Gravity.CENTER);
TextView textviewTitle = (TextView) viewActionBar.findViewById(R.id.actionbar_textview);
textviewTitle.setText("Test");
abar.setCustomView(viewActionBar, params);
abar.setDisplayShowCustomEnabled(true);
abar.setDisplayShowTitleEnabled(false);
abar.setDisplayHomeAsUpEnabled(true);
abar.setIcon(R.color.transparent);
abar.setHomeButtonEnabled(true);
Define your own custom view with title text, then pass LayoutParams to setCustomView(), as Sergii says.
ActionBar actionBar = getSupportActionBar()
actionBar.setDisplayShowCustomEnabled(true);
actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
actionBar.setCustomView(getLayoutInflater().inflate(R.layout.action_bar_home, null),
new ActionBar.LayoutParams(
ActionBar.LayoutParams.WRAP_CONTENT,
ActionBar.LayoutParams.MATCH_PARENT,
Gravity.CENTER
)
);
EDITED: At least for width, you should use WRAP_CONTENT or your navigation drawer, app icon, etc. WON'T BE SHOWN (custom view shown on top of other views on action bar). This will occur especially when no action button is shown.
EDITED: Equivalent in xml layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center_horizontal"
android:orientation="vertical">
This doesn't require LayoutParams to be specified.
actionBar.setCustomView(getLayoutInflater().inflate(R.layout.action_bar_home, null);
Just a quick addition to Ahmad's answer. You can't use getSupportActionBar().setTitle anymore when using a custom view with a TextView. So to set the title when you have multiple Activities with this custom ActionBar (using this one xml), in your onCreate() method after you assign a custom view:
TextView textViewTitle = (TextView) findViewById(R.id.mytext);
textViewTitle.setText(R.string.title_for_this_activity);
Code here working for me.
// Activity
public void setTitle(String title){
getSupportActionBar().setHomeButtonEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
TextView textView = new TextView(this);
textView.setText(title);
textView.setTextSize(20);
textView.setTypeface(null, Typeface.BOLD);
textView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
textView.setGravity(Gravity.CENTER);
textView.setTextColor(getResources().getColor(R.color.white));
getSupportActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
getSupportActionBar().setCustomView(textView);
}
// Fragment
public void setTitle(String title){
((AppCompatActivity)getActivity()).getSupportActionBar().setHomeButtonEnabled(true);
((AppCompatActivity)getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(true);
TextView textView = new TextView(getActivity());
textView.setText(title);
textView.setTextSize(20);
textView.setTypeface(null, Typeface.BOLD);
textView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
textView.setGravity(Gravity.CENTER);
textView.setTextColor(getResources().getColor(R.color.white));
((AppCompatActivity)getActivity()).getSupportActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
((AppCompatActivity)getActivity()).getSupportActionBar().setCustomView(textView);
}
Without customview its able to center actionbar title.
It's perfectly working for navigation drawer as well
int titleId = getResources().getIdentifier("action_bar_title", "id", "android");
TextView abTitle = (TextView) findViewById(titleId);
abTitle.setTextColor(getResources().getColor(R.color.white));
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
abTitle.setGravity(Gravity.CENTER);
abTitle.setWidth(metrics.widthPixels);
getActionBar().setTitle("I am center now");
OK. After a lot of research, combined with the accepted answer above, I have come up with a solution that also works if you have other stuff in your action bar (back/home button, menu button). So basically I have put the override methods in a basic activity (which all other activities extend), and placed the code there. This code sets the title of each activity as it is provided in AndroidManifest.xml, and also does som other custom stuff (like setting a custom tint on action bar buttons, and custom font on the title). You only need to leave out the gravity in action_bar.xml, and use padding instead. actionBar != null check is used, since not all my activities have one.
Tested on 4.4.2 and 5.0.1
public class BaseActivity extends AppCompatActivity {
private ActionBar actionBar;
private TextView actionBarTitle;
private Toolbar toolbar;
#Override
protected void onCreate(Bundle savedInstanceState) {
getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
super.onCreate(savedInstanceState);
...
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setElevation(0);
actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
actionBar.setCustomView(R.layout.action_bar);
LinearLayout layout = (LinearLayout) actionBar.getCustomView();
actionBarTitle = (TextView) layout.getChildAt(0);
actionBarTitle.setText(this.getTitle());
actionBarTitle.setTypeface(Utility.getSecondaryFont(this));
toolbar = (Toolbar) layout.getParent();
toolbar.setContentInsetsAbsolute(0, 0);
if (this.getClass() == BackButtonActivity.class || this.getClass() == AnotherBackButtonActivity.class) {
actionBar.setHomeButtonEnabled(true);
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setDisplayShowHomeEnabled(true);
Drawable wrapDrawable = DrawableCompat.wrap(getResources().getDrawable(R.drawable.ic_back));
DrawableCompat.setTint(wrapDrawable, getResources().getColor(android.R.color.white));
actionBar.setHomeAsUpIndicator(wrapDrawable);
actionBar.setIcon(null);
}
else {
actionBar.setHomeButtonEnabled(false);
actionBar.setDisplayHomeAsUpEnabled(false);
actionBar.setDisplayShowHomeEnabled(false);
actionBar.setHomeAsUpIndicator(null);
actionBar.setIcon(null);
}
}
try {
ViewConfiguration config = ViewConfiguration.get(this);
Field menuKeyField = ViewConfiguration.class.getDeclaredField("sHasPermanentMenuKey");
if(menuKeyField != null) {
menuKeyField.setAccessible(true);
menuKeyField.setBoolean(config, false);
}
} catch (Exception ex) {
// Ignore
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
if (actionBar != null) {
int padding = (getDisplayWidth() - actionBarTitle.getWidth())/2;
MenuInflater inflater = getMenuInflater();
if (this.getClass() == MenuActivity.class) {
inflater.inflate(R.menu.activity_close_menu, menu);
}
else {
inflater.inflate(R.menu.activity_open_menu, menu);
}
MenuItem item = menu.findItem(R.id.main_menu);
Drawable icon = item.getIcon();
icon.mutate().mutate().setColorFilter(getResources().getColor(R.color.white), PorterDuff.Mode.SRC_IN);
item.setIcon(icon);
ImageButton imageButton;
for (int i =0; i < toolbar.getChildCount(); i++) {
if (toolbar.getChildAt(i).getClass() == ImageButton.class) {
imageButton = (ImageButton) toolbar.getChildAt(i);
padding -= imageButton.getWidth();
break;
}
}
actionBarTitle.setPadding(padding, 0, 0, 0);
}
return super.onCreateOptionsMenu(menu);
} ...
And my action_bar.xml is like this (if anyone is interested):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#color/actionbar_text_color"
android:textAllCaps="true"
android:textSize="9pt"
/>
</LinearLayout>
EDIT: If you need to change the title to something else AFTER the activity is loaded (onCreateOptionsMenu has already been called), put another TextView in your action_bar.xml and use the following code to "pad" this new TextView, set text and show it:
protected void setSubTitle(CharSequence title) {
if (!initActionBarTitle()) return;
if (actionBarSubTitle != null) {
if (title != null || title.length() > 0) {
actionBarSubTitle.setText(title);
setActionBarSubTitlePadding();
}
}
}
private void setActionBarSubTitlePadding() {
if (actionBarSubTitlePaddingSet) return;
ViewTreeObserver vto = layout.getViewTreeObserver();
if(vto.isAlive()){
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
int padding = (getDisplayWidth() - actionBarSubTitle.getWidth())/2;
ImageButton imageButton;
for (int i = 0; i < toolbar.getChildCount(); i++) {
if (toolbar.getChildAt(i).getClass() == ImageButton.class) {
imageButton = (ImageButton) toolbar.getChildAt(i);
padding -= imageButton.getWidth();
break;
}
}
actionBarSubTitle.setPadding(padding, 0, 0, 0);
actionBarSubTitlePaddingSet = true;
ViewTreeObserver obs = layout.getViewTreeObserver();
obs.removeOnGlobalLayoutListener(this);
}
});
}
}
protected void hideActionBarTitle() {
if (!initActionBarTitle()) return;
actionBarTitle.setVisibility(View.GONE);
if (actionBarSubTitle != null) {
actionBarSubTitle.setVisibility(View.VISIBLE);
}
}
protected void showActionBarTitle() {
if (!initActionBarTitle()) return;
actionBarTitle.setVisibility(View.VISIBLE);
if (actionBarSubTitle != null) {
actionBarSubTitle.setVisibility(View.GONE);
}
}
EDIT (25.08.2016): This does not work with appcompat 24.2.0 revision (August 2016), if your activity has a "back button". I filed a bug report (Issue 220899), but I do not know if it is of any use (doubt it will be fixed any time soon). Meanwhile the solution is to check if the child's class is equal to AppCompatImageButton.class and do the same, only increase the width by 30% (e.g. appCompatImageButton.getWidth()*1.3 before subtracting this value from the original padding):
padding -= appCompatImageButton.getWidth()*1.3;
In the mean time I threw in some padding/margin checks in there:
Class<?> c;
ImageButton imageButton;
AppCompatImageButton appCompatImageButton;
for (int i = 0; i < toolbar.getChildCount(); i++) {
c = toolbar.getChildAt(i).getClass();
if (c == AppCompatImageButton.class) {
appCompatImageButton = (AppCompatImageButton) toolbar.getChildAt(i);
padding -= appCompatImageButton.getWidth()*1.3;
padding -= appCompatImageButton.getPaddingLeft();
padding -= appCompatImageButton.getPaddingRight();
if (appCompatImageButton.getLayoutParams().getClass() == LinearLayout.LayoutParams.class) {
padding -= ((LinearLayout.LayoutParams) appCompatImageButton.getLayoutParams()).getMarginEnd();
padding -= ((LinearLayout.LayoutParams) appCompatImageButton.getLayoutParams()).getMarginStart();
}
break;
}
else if (c == ImageButton.class) {
imageButton = (ImageButton) toolbar.getChildAt(i);
padding -= imageButton.getWidth();
padding -= imageButton.getPaddingLeft();
padding -= imageButton.getPaddingRight();
if (imageButton.getLayoutParams().getClass() == LinearLayout.LayoutParams.class) {
padding -= ((LinearLayout.LayoutParams) imageButton.getLayoutParams()).getMarginEnd();
padding -= ((LinearLayout.LayoutParams) imageButton.getLayoutParams()).getMarginStart();
}
break;
}
}
It works nicely.
activity = (AppCompatActivity) getActivity();
activity.getSupportActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
LayoutInflater inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View v = inflater.inflate(R.layout.custom_actionbar, null);
ActionBar.LayoutParams p = new ActionBar.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT,
Gravity.CENTER);
((TextView) v.findViewById(R.id.title)).setText(FRAGMENT_TITLE);
activity.getSupportActionBar().setCustomView(v, p);
activity.getSupportActionBar().setDisplayShowTitleEnabled(true);
activity.getSupportActionBar().setDisplayHomeAsUpEnabled(true);
Below layout of custom_actionbar:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/title"
android:layout_width="wrap_content"
android:text="Example"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:ellipsize="end"
android:maxLines="1"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="#color/colorBlack" />
</RelativeLayout>
Best and easiest way, specifically for those who just want text view with gravity center without any xml layout.
AppCompatTextView mTitleTextView = new AppCompatTextView(getApplicationContext());
mTitleTextView.setSingleLine();
ActionBar.LayoutParams layoutParams = new ActionBar.LayoutParams(ActionBar.LayoutParams.WRAP_CONTENT, ActionBar.LayoutParams.WRAP_CONTENT);
layoutParams.gravity = Gravity.CENTER;
actionBar.setCustomView(mTitleTextView, layoutParams);
actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM | ActionBar.DISPLAY_HOME_AS_UP);
mTitleTextView.setText(text);
mTitleTextView.setTextAppearance(getApplicationContext(), android.R.style.TextAppearance_Medium);
A Kotlin-only solution that does not require to have changes in the XML Layouts:
//Function to call in onResume() of your activity
private fun centerToolbarText() {
val mTitleTextView = AppCompatTextView(this)
mTitleTextView.text = title
mTitleTextView.setSingleLine()//Remove it if you want to allow multiple lines in the toolbar
mTitleTextView.textSize = 25f
val layoutParams = android.support.v7.app.ActionBar.LayoutParams(
ActionBar.LayoutParams.WRAP_CONTENT,
ActionBar.LayoutParams.WRAP_CONTENT
)
layoutParams.gravity = Gravity.CENTER
supportActionBar?.setCustomView(mTitleTextView,layoutParams)
supportActionBar?.displayOptions = ActionBar.DISPLAY_SHOW_CUSTOM
}
After a lot of research:
This actually works:
getActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
getActionBar().setCustomView(R.layout.custom_actionbar);
ActionBar.LayoutParams p = new ActionBar.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
p.gravity = Gravity.CENTER;
You have to define custom_actionbar.xml layout which is as per your requirement e.g. :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#2e2e2e"
android:orientation="vertical"
android:gravity="center"
android:layout_gravity="center">
<ImageView
android:id="#+id/imageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/top_banner"
android:layout_gravity="center"
/>
</LinearLayout>
You need to set ActionBar.LayoutParams.WRAP_CONTENT and ActionBar.DISPLAY_HOME_AS_UP
View customView = LayoutInflater.from(this).inflate(R.layout.actionbar_title, null);
ActionBar.LayoutParams params = new ActionBar.LayoutParams(ActionBar.LayoutParams.WRAP_CONTENT,
ActionBar.LayoutParams.MATCH_PARENT, Gravity.CENTER);
getSupportActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM | ActionBar.DISPLAY_SHOW_HOME | ActionBar.DISPLAY_HOME_AS_UP );
Here is a complete Kotlin + androidx solution, building upon the answer from #Stanislas Heili. I hope it may be useful to others. It's for the case when you have an activity that hosts multiple fragments, with only one fragment active at the same time.
In your activity:
private lateinit var customTitle: AppCompatTextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// stuff here
customTitle = createCustomTitleTextView()
// other stuff here
}
private fun createCustomTitleTextView(): AppCompatTextView {
val mTitleTextView = AppCompatTextView(this)
TextViewCompat.setTextAppearance(mTitleTextView, R.style.your_style_or_null);
val layoutParams = ActionBar.LayoutParams(
ActionBar.LayoutParams.WRAP_CONTENT,
ActionBar.LayoutParams.WRAP_CONTENT
)
layoutParams.gravity = Gravity.CENTER
supportActionBar?.setCustomView(mTitleTextView, layoutParams)
supportActionBar?.displayOptions = ActionBar.DISPLAY_SHOW_CUSTOM
return mTitleTextView
}
override fun setTitle(title: CharSequence?) {
customTitle.text = title
}
override fun setTitle(titleId: Int) {
customTitle.text = getString(titleId)
}
In your fragments:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
activity?.title = "some title for fragment"
}
The other tutorials I've seen override the whole action bar layout hiding the MenuItems. I've got it worked just doing the following steps:
Create a xml file as following:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="#+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:ellipsize="end"
android:maxLines="1"
android:text="#string/app_name"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="#android:color/white" />
</RelativeLayout>
And in the classe do it:
LayoutInflater inflator = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View v = inflator.inflate(R.layout.action_bar_title, null);
ActionBar.LayoutParams params = new ActionBar.LayoutParams(ActionBar.LayoutParams.WRAP_CONTENT, ActionBar.LayoutParams.MATCH_PARENT, Gravity.CENTER);
TextView titleTV = (TextView) v.findViewById(R.id.title);
titleTV.setText("Test");
For Kotlin users:
Use the following code in your activity:
// Set custom action bar
supportActionBar?.displayOptions = ActionBar.DISPLAY_SHOW_CUSTOM
supportActionBar?.setCustomView(R.layout.action_bar)
// Set title for action bar
val title = findViewById<TextView>(R.id.titleTextView)
title.setText(resources.getText(R.string.app_name))
And the XML/ resource layout:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
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">
<TextView
android:id="#+id/titleTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Title"
android:textColor="#color/black"
android:textSize="18sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
My solution will be to keep text part of tool bar separate, to define style and say, center or whichever alignment. It can be done in XML itself. Some paddings can be specified after doing calculations when you have actions that are visible always. I have moved two attributes from toolbar to its child TextView. This textView can be provided id to be accessed from fragments.
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.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">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppTheme.AppBarOverlay">
<androidx.appcompat.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:theme="#style/defaultTitleTheme"
app:titleTextColor="#color/white"-->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingStart="#dimen/icon_size"
android:text="#string/title_home"
style="#style/defaultTitleTheme"
tools:ignore="RtlSymmetry" />
</androidx.appcompat.widget.Toolbar>
</com.google.android.material.appbar.AppBarLayout>
<FrameLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Here's a quick tip to center align the action:
android:label=" YourTitle"
Assuming that you have Actionbar Enable, You can add this in your activity with some space (Can be adjusted) to place the title at the center.
However, This is just diddly and unreliable method. You probably shouldn't do that. So, The best thing to do is to create a custom ActionBar. So, What you wanna do is remove the default Actionbar and use this to replace it as an ActionBar.
<androidx.constraintlayout.widget.ConstraintLayout
android:elevation="30dp"
android:id="#+id/customAction"
android:layout_width="match_parent"
android:layout_height="56dp"
android:background="#color/colorOnMain"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/app_name"
android:textAllCaps="true"
android:textColor="#FFF"
android:textSize="18sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
I have used Constraint Layout to center the textView and used 10dp elevation with 56dp height so that it looks as same as the default ActionBar.
This code will not hide back button, Same time will align the title in centre.
call this method in oncreate
centerActionBarTitle();
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
myActionBar.setIcon(new ColorDrawable(Color.TRANSPARENT));
private void centerActionBarTitle() {
int titleId = 0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
titleId = getResources().getIdentifier("action_bar_title", "id", "android");
} else {
// This is the id is from your app's generated R class when
// ActionBarActivity is used for SupportActionBar
titleId = R.id.action_bar_title;
}
// Final check for non-zero invalid id
if (titleId > 0) {
TextView titleTextView = (TextView) findViewById(titleId);
DisplayMetrics metrics = getResources().getDisplayMetrics();
// Fetch layout parameters of titleTextView
// (LinearLayout.LayoutParams : Info from HierarchyViewer)
LinearLayout.LayoutParams txvPars = (LayoutParams) titleTextView.getLayoutParams();
txvPars.gravity = Gravity.CENTER_HORIZONTAL;
txvPars.width = metrics.widthPixels;
titleTextView.setLayoutParams(txvPars);
titleTextView.setGravity(Gravity.CENTER);
}
}