Related
I create small example to show my issue.
Main layout with SearchView in toolbar and 3 buttons:
1) Set text - expand search view and set query
2) Expand - expand search view
3) Collapse - collapse search view
activity_main.xml
android:fitsSystemWindows="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:orientation="vertical"
tools:context="com.porn.MainActivity">
<android.support.design.widget.AppBarLayout
android:layout_width="368dp"
android:layout_height="wrap_content"
tools:layout_editor_absoluteX="8dp"
tools:layout_editor_absoluteY="0dp">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:contentInsetStartWithNavigation="0dp">
</android.support.v7.widget.Toolbar>
</android.support.design.widget.AppBarLayout>
<Button
android:id="#+id/setTextBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Set text" />
<Button
android:id="#+id/expandBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Expand" />
<Button
android:id="#+id/collapseBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Collapse" />
</LinearLayout>
</android.support.v4.widget.DrawerLayout>
MainActivity.java
public class MainActivity extends AppCompatActivity {
private MenuItem toolbarSearchMenuItem;
private SearchView toolbarSearchView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Toolbar
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayShowTitleEnabled(false);
findViewById(R.id.expandBtn).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
toolbarSearchMenuItem.expandActionView();
}
});
findViewById(R.id.collapseBtn).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
toolbarSearchMenuItem.collapseActionView();
}
});
findViewById(R.id.setTextBtn).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
setToolbarSearchQuery("Text2");
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.toobar, menu);
toolbarSearchMenuItem = menu.findItem(R.id.toolbar_action_search);
toolbarSearchView = (SearchView) menu.findItem(R.id.toolbar_action_search).getActionView();
init();
return true;
}
public void init() {
//In real app i get searchQuery from extra
//String searchQuery = getIntent().getStringExtra(INTENT_EXTRA_SEARCH_QUERY_KEY);
setToolbarSearchQuery("Text from intent");
}
private void setToolbarSearchQuery(String searchQuery) {
if (!searchQuery.equals("")) {
toolbarSearchMenuItem.expandActionView();
toolbarSearchView.setQuery(searchQuery, false);
toolbarSearchView.clearFocus();
} else {
toolbarSearchMenuItem.collapseActionView();
}
}
}
My problem appears when i call method init() from onCreateOptionsMenu (In real app i init SearchView with text from intent extra). If i call setToolbarSearchQuery method from init and after i click collapse button SearchView collapsed and search icon disappear.
But if i will not call init method and will call same method setToolbarSearchQuery with set text button it works correctly (SearchView is collapsed and search icon shown in toolbar).
How i can solve this problem? And why icon disappear after collapse?
I understood that it happens when i expand SearchView from onCreateOptionsMenu. But how i can correct init SearchView from intent extra?
Screenshot how it looks after collapse
Screenshot how it must looks after collapse
The "anton111111" answer works perfectly, but just for those who don't want to use delay, I recommend change search menu item showAsAction property as below:
android:showAsAction="always|collapseActionView"
instead of
android:showAsAction="ifRoom|collapseActionView"
See original answer here.
I found only one solution. Set text in init method delayed.
public void init() {
//setToolbarSearchQuery("Text from intent");
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
toolbarSearchMenuItem.expandActionView();
toolbarSearchView.setQuery("Text from intent", false);
}
}, 1000);
}
But i don't like this solution. It looks like trick.
I have been looking for ways to implement a searchview in the activity toolbar (actionbar) as per the material design guidelines.
On clicking on the search icon, the entire toolbar animates to have only the search EditText with white background with suggestions appearing in the main view instead of a drop down.
Here is a screenshot from the guidelines:
Here is a gif from the Gmail Inbox implementation:
I have been looking for code examples and tutorials but so far I have been unsuccesful. How do I go about doing this?
I tried several material SearchView libraries, but none of them worked good as the one from the support library, so I decided to redesign it, after a lot of work, I am pleased with the result:
Here is how you can do it:
1) Add SearchView item to your menu
<item
android:id="#+id/m_search"
android:icon="#drawable/ic_action_search"
android:title="#string/search_title"
app:actionLayout="#layout/search_view_layout"
app:showAsAction="ifRoom|collapseActionView" />
Notice that I'm declaring actionLayout instead of actionViewClass, I figured that this is the only way to set SearchView theme separately from Toolbar theme.
search_view_layout.xml:
<android.support.v7.widget.SearchView
android:id="#+id/search_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/SearchViewTheme" />
2) Add the custom SearchView theme to your styles, declare SearchView theme in your Toolbar theme as well:
<style name="SearchViewTheme" parent="Widget.AppCompat.SearchView.ActionBar">
<item name="layout">#layout/toolbar_search_view</item>
<item name="commitIcon">#drawable/ic_search_commit</item>
<item name="colorControlNormal">#color/material_light_active_icon</item>
<item name="colorControlHighlight">#color/material_ripple_light</item>
<item name="autoCompleteTextViewStyle">#style/AutoCompleteTextViewStyle</item>
<item name="suggestionRowLayout">#layout/search_view_suggestion_row</item>
<item name="android:maxWidth">9999dp</item>
</style>
<style name="AutoCompleteTextViewStyle" parent="Widget.AppCompat.Light.AutoCompleteTextView">
<item name="android:popupBackground">#drawable/search_suggestions_bg</item>
<item name="android:popupElevation">0dp</item>
</style>
<style name="ToolbarTheme" parent="ThemeOverlay.AppCompat.Dark.ActionBar">
<item name="searchViewStyle">#style/SearchViewTheme</item>
</style>
toolbar_search_view.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/search_bar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:paddingEnd="8dp">
<!-- This is actually used for the badge icon *or* the badge label (or neither) -->
<TextView
android:id="#+id/search_badge"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginBottom="2dp"
android:drawablePadding="0dp"
android:gravity="center_vertical"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="?android:attr/textColorPrimary"
android:visibility="gone" />
<ImageView
android:id="#+id/search_button"
style="?attr/actionButtonStyle"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:contentDescription="#string/abc_searchview_description_search"
android:focusable="true" />
<LinearLayout
android:id="#+id/search_edit_frame"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:layoutDirection="locale"
android:orientation="horizontal">
<ImageView
android:id="#+id/search_mag_icon"
style="#style/RtlOverlay.Widget.AppCompat.SearchView.MagIcon"
android:layout_width="#dimen/abc_dropdownitem_icon_width"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:scaleType="centerInside"
android:visibility="gone" />
<!-- Inner layout contains the app icon, button(s) and EditText -->
<LinearLayout
android:id="#+id/search_plate"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:orientation="horizontal">
<view
android:id="#+id/search_src_text"
class="android.support.v7.widget.SearchView$SearchAutoComplete"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:layout_marginEnd="#dimen/item_list_horizontal_margin"
android:layout_marginStart="#dimen/item_list_horizontal_margin"
android:layout_weight="1"
android:background="#null"
android:dropDownAnchor="#id/anchor_dropdown"
android:dropDownHeight="wrap_content"
android:dropDownHorizontalOffset="0dp"
android:dropDownVerticalOffset="0dp"
android:ellipsize="end"
android:imeOptions="actionSearch"
android:inputType="text|textAutoComplete|textNoSuggestions"
android:maxLines="1"
android:paddingEnd="8dp"
android:textColor="#android:color/black"
android:textColorHint="#color/material_light_hint_text"
android:textSize="20sp" />
<ImageView
android:id="#+id/search_close_btn"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="#string/abc_searchview_description_clear"
android:focusable="true"
android:paddingEnd="8dp"
android:paddingStart="8dp" />
</LinearLayout>
<LinearLayout
android:id="#+id/submit_area"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal">
<ImageView
android:id="#+id/search_go_btn"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="#string/abc_searchview_description_submit"
android:focusable="true"
android:paddingEnd="8dp"
android:paddingStart="8dp"
android:visibility="gone" />
<ImageView
android:id="#+id/search_voice_btn"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="#string/abc_searchview_description_voice"
android:focusable="true"
android:paddingEnd="8dp"
android:paddingStart="8dp"
android:visibility="gone" />
</LinearLayout>
</LinearLayout>
Notice that I added anchor dropdown view under the Toolbar view, so suggestions will get full screen width.
<android.support.design.widget.AppBarLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/appBar"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:collapseIcon="#drawable/ic_search_collapse"
app:popupTheme="#style/AppTheme.PopupOverlay"
app:theme="#style/ToolbarTheme" />
<View
android:id="#+id/anchor_dropdown"
android:layout_width="match_parent"
android:layout_height="0dp" />
</android.support.design.widget.AppBarLayout>
search_view_suggestion_row.xml:
(change suggestion_divider visibility if you want divider between suggestions):
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="58dp"
android:theme="#style/Theme.AppCompat.DayNight">
<!-- Icons come first in the layout, since their placement doesn't depend on
the placement of the text views. -->
<ImageView
android:id="#android:id/icon1"
style="#style/RtlOverlay.Widget.AppCompat.Search.DropDown.Icon1"
android:layout_width="56dp"
android:layout_height="56dp"
android:layout_alignParentBottom="true"
android:layout_alignParentTop="true"
android:scaleType="centerInside"
android:visibility="invisible" />
<ImageView
android:id="#+id/edit_query"
style="#style/RtlOverlay.Widget.AppCompat.Search.DropDown.Query"
android:layout_width="56dp"
android:layout_height="56dp"
android:layout_alignParentBottom="true"
android:layout_alignParentTop="true"
android:background="?attr/selectableItemBackground"
android:scaleType="centerInside"
android:visibility="gone" />
<ImageView
android:id="#id/android:icon2"
style="#style/RtlOverlay.Widget.AppCompat.Search.DropDown.Icon2"
android:layout_width="56dp"
android:layout_height="56dp"
android:layout_alignParentBottom="true"
android:layout_alignParentTop="true"
android:layout_alignWithParentIfMissing="true"
android:scaleType="centerInside"
android:visibility="gone" />
<!-- The subtitle comes before the title, since the height of the title depends on whether the
subtitle is visible or gone. -->
<TextView
android:id="#android:id/text2"
style="?android:attr/dropDownItemStyle"
android:layout_width="match_parent"
android:layout_height="29dp"
android:layout_alignParentBottom="true"
android:layout_alignWithParentIfMissing="true"
android:gravity="top"
android:maxLines="1"
android:paddingBottom="4dp"
android:textColor="?android:textColorSecondary"
android:textSize="12sp"
android:visibility="gone" />
<!-- The title is placed above the subtitle, if there is one. If there is no
subtitle, it fills the parent. -->
<TextView
android:id="#android:id/text1"
style="?android:attr/dropDownItemStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="#android:id/text2"
android:layout_centerVertical="true"
android:ellipsize="end"
android:maxLines="1"
android:scrollHorizontally="false"
android:textColor="?android:textColorPrimary"
android:textSize="16sp" />
<View
android:id="#+id/suggestion_divider"
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:layout_alignParentBottom="true"
android:layout_alignStart="#android:id/text1"
android:layout_marginStart="8dp"
android:background="#color/divider_color"
android:visibility="gone" />
The suggestions background and the commit icon are custom made, the rest of the icons I used can be found at: https://material.io/icons/
ic_search_commit.xml:
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:autoMirrored="true"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#color/active_icon_color"
android:pathData="m18.364,16.95l-8.605,-8.605l7.905,-0l-0.007,-2.001l-11.314,0l0,11.314l1.994,-0l0.007,-7.898l8.605,8.605l1.414,-1.414z" />
search_suggestions_bg.xml:
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<padding android:top="0.5dp" />
<stroke
android:width="0.5dp"
android:color="#color/divider_color" />
</shape>
</item>
<item>
<shape android:shape="rectangle">
<solid android:color="#color/cards_and_dialogs_color" />
</shape>
</item>
</layer-list>
Add following values to your colors.xml (add values-night only if you are using DayNight theme):
values/colors.xml
<color name="material_light_primary_text">#DE000000</color>
<color name="material_light_hint_text">#61000000</color>
<color name="material_light_active_icon">#8A000000</color>
<color name="material_ripple_light">#1F000000</color>
<color name="divider_color">#1F000000</color>
<color name="active_icon_color">#8A000000</color>
<color name="cards_and_dialogs_color">#android:color/white</color>
<color name="quantum_grey_600">#757575</color>
values-night/colors.xml:
<color name="divider_color">#1FFFFFFF</color>
<color name="active_icon_color">#android:color/white</color>
<color name="cards_and_dialogs_color">#424242</color>
3) Last part, make the magic happen in code:
Setup and initialize SearchView in your desired activity
private MenuItem mSearchItem;
private Toolbar mToolbar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
mToolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(mToolbar);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
mSearchItem = menu.findItem(R.id.m_search);
MenuItemCompat.setOnActionExpandListener(mSearchItem, new MenuItemCompat.OnActionExpandListener() {
#Override
public boolean onMenuItemActionCollapse(MenuItem item) {
// Called when SearchView is collapsing
if (mSearchItem.isActionViewExpanded()) {
animateSearchToolbar(1, false, false);
}
return true;
}
#Override
public boolean onMenuItemActionExpand(MenuItem item) {
// Called when SearchView is expanding
animateSearchToolbar(1, true, true);
return true;
}
});
return true;
}
public void animateSearchToolbar(int numberOfMenuIcon, boolean containsOverflow, boolean show) {
mToolbar.setBackgroundColor(ContextCompat.getColor(this, android.R.color.white));
mDrawerLayout.setStatusBarBackgroundColor(ContextCompat.getColor(this, R.color.quantum_grey_600));
if (show) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
int width = mToolbar.getWidth() -
(containsOverflow ? getResources().getDimensionPixelSize(R.dimen.abc_action_button_min_width_overflow_material) : 0) -
((getResources().getDimensionPixelSize(R.dimen.abc_action_button_min_width_material) * numberOfMenuIcon) / 2);
Animator createCircularReveal = ViewAnimationUtils.createCircularReveal(mToolbar,
isRtl(getResources()) ? mToolbar.getWidth() - width : width, mToolbar.getHeight() / 2, 0.0f, (float) width);
createCircularReveal.setDuration(250);
createCircularReveal.start();
} else {
TranslateAnimation translateAnimation = new TranslateAnimation(0.0f, 0.0f, (float) (-mToolbar.getHeight()), 0.0f);
translateAnimation.setDuration(220);
mToolbar.clearAnimation();
mToolbar.startAnimation(translateAnimation);
}
} else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
int width = mToolbar.getWidth() -
(containsOverflow ? getResources().getDimensionPixelSize(R.dimen.abc_action_button_min_width_overflow_material) : 0) -
((getResources().getDimensionPixelSize(R.dimen.abc_action_button_min_width_material) * numberOfMenuIcon) / 2);
Animator createCircularReveal = ViewAnimationUtils.createCircularReveal(mToolbar,
isRtl(getResources()) ? mToolbar.getWidth() - width : width, mToolbar.getHeight() / 2, (float) width, 0.0f);
createCircularReveal.setDuration(250);
createCircularReveal.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
mToolbar.setBackgroundColor(getThemeColor(MainActivity.this, R.attr.colorPrimary));
mDrawerLayout.setStatusBarBackgroundColor(getThemeColor(MainActivity.this, R.attr.colorPrimaryDark));
}
});
createCircularReveal.start();
} else {
AlphaAnimation alphaAnimation = new AlphaAnimation(1.0f, 0.0f);
Animation translateAnimation = new TranslateAnimation(0.0f, 0.0f, 0.0f, (float) (-mToolbar.getHeight()));
AnimationSet animationSet = new AnimationSet(true);
animationSet.addAnimation(alphaAnimation);
animationSet.addAnimation(translateAnimation);
animationSet.setDuration(220);
animationSet.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
mToolbar.setBackgroundColor(getThemeColor(MainActivity.this, R.attr.colorPrimary));
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
mToolbar.startAnimation(animationSet);
}
mDrawerLayout.setStatusBarBackgroundColor(getThemeColor(MainActivity.this, R.attr.colorPrimaryDark));
}
}
private boolean isRtl(Resources resources) {
return resources.getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
}
private static int getThemeColor(Context context, int id) {
Resources.Theme theme = context.getTheme();
TypedArray a = theme.obtainStyledAttributes(new int[]{id});
int result = a.getColor(0, 0);
a.recycle();
return result;
}
Few things to notice about the code:
1) The animation will adjust it's start point based on your set of number of menu items and if the toolbar has overflow icon, it will detect if layout is LTR or RTL automatically.
2) I'm using navigation drawer activity, so I set StatusBar color to mDrawerLayout, if you are using regular activity, you can set StatusBar color this way:
getWindow().setStatusBarColor(ContextCompat.getColor(this, R.color.quantum_grey_600));
3) The circular reveal animation will only work on KitKat and above.
It is actually quite easy to do this, if you are using android.support.v7 library.
Step - 1
Declare a menu item
<item android:id="#+id/action_search"
android:title="Search"
android:icon="#drawable/abc_ic_search_api_mtrl_alpha"
app:showAsAction="ifRoom|collapseActionView"
app:actionViewClass="android.support.v7.widget.SearchView" />
Step - 2
Extend AppCompatActivity and in the onCreateOptionsMenu setup the SearchView.
import android.support.v7.widget.SearchView;
public class YourActivity extends AppCompatActivity {
...
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_home, menu);
// Retrieve the SearchView and plug it into SearchManager
final SearchView searchView = (SearchView) MenuItemCompat.getActionView(menu.findItem(R.id.action_search));
SearchManager searchManager = (SearchManager) getSystemService(SEARCH_SERVICE);
searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
return true;
}
...
}
The idea is very simple - you have to write your own AutoCompleteTextView using EditText, TextWatcher and RecyclerView with Filterable adapter.
EditText gives you a text field with ability to input characters
TextWatcher allows you to watch for text changes
RecyclerView can be placed anywhere, so you can show the search results just like on your screenshot
Filterable adapter helps to present data filtered with the entered text
So:
make a layout with EditText on the top, with RecyclerView filling the remaining space. Add the icon, shadow, etc.
add a TextWatcher and update the adapter on each text change
If you'd like to see my solution in action, check out my project on github:
https://github.com/ZieIony/Carbon
The Auto complete demo can be sound in the sample app in 'Demos' section.
Taking a hint from #Zielony's answer I did the following:
1) Instead if using an ActionBar or ToolBar I built my own layout (basically a RelativeLayout with burger menu, search and other menu buttons and a EditText for search)
2) Used a theme without an ActionBar, placed my custom layout at the top of the activity so that it appeared like an ActionBar.
3) In the search button's OnClickListener I do 2 things:
Hide the menu buttons and show the 'search' EditText.
Add a fragment to display search suggestions and search
Show the soft keyboard input
3) Added OnClickListeners for the other menu buttons.
4) Added a TextWatcher on the 'search' EditText to display search hints and results from the server.
This is how it appears now:
I think I've figured it out.
I'm now using just an EditText inside of the Toolbar.
I now have this:
First inside onCreate() of my activity I added the EditText with an image view on the right hand side to the Toolbar like this:
// Setup search container view
searchContainer = new LinearLayout(this);
Toolbar.LayoutParams containerParams = new Toolbar.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
containerParams.gravity = Gravity.CENTER_VERTICAL;
searchContainer.setLayoutParams(containerParams);
// Setup search view
toolbarSearchView = new EditText(this);
// Set width / height / gravity
int[] textSizeAttr = new int[]{android.R.attr.actionBarSize};
int indexOfAttrTextSize = 0;
TypedArray a = obtainStyledAttributes(new TypedValue().data, textSizeAttr);
int actionBarHeight = a.getDimensionPixelSize(indexOfAttrTextSize, -1);
a.recycle();
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0, actionBarHeight);
params.gravity = Gravity.CENTER_VERTICAL;
params.weight = 1;
toolbarSearchView.setLayoutParams(params);
// Setup display
toolbarSearchView.setBackgroundColor(Color.TRANSPARENT);
toolbarSearchView.setPadding(2, 0, 0, 0);
toolbarSearchView.setTextColor(Color.WHITE);
toolbarSearchView.setGravity(Gravity.CENTER_VERTICAL);
toolbarSearchView.setSingleLine(true);
toolbarSearchView.setImeActionLabel("Search", EditorInfo.IME_ACTION_UNSPECIFIED);
toolbarSearchView.setHint("Search");
toolbarSearchView.setHintTextColor(Color.parseColor("#b3ffffff"));
try {
// Set cursor colour to white
// http://stackoverflow.com/a/26544231/1692770
// https://github.com/android/platform_frameworks_base/blob/kitkat-release/core/java/android/widget/TextView.java#L562-564
Field f = TextView.class.getDeclaredField("mCursorDrawableRes");
f.setAccessible(true);
f.set(toolbarSearchView, R.drawable.edittext_whitecursor);
} catch (Exception ignored) {
}
// Search text changed listener
toolbarSearchView.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
Fragment mainFragment = getFragmentManager().findFragmentById(R.id.container);
if (mainFragment != null && mainFragment instanceof MainListFragment) {
((MainListFragment) mainFragment).search(s.toString());
}
}
#Override
public void afterTextChanged(Editable s) {
// http://stackoverflow.com/a/6438918/1692770
if (s.toString().length() <= 0) {
toolbarSearchView.setHintTextColor(Color.parseColor("#b3ffffff"));
}
}
});
((LinearLayout) searchContainer).addView(toolbarSearchView);
// Setup the clear button
searchClearButton = new ImageView(this);
Resources r = getResources();
int px = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 16, r.getDisplayMetrics());
LinearLayout.LayoutParams clearParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
clearParams.gravity = Gravity.CENTER;
searchClearButton.setLayoutParams(clearParams);
searchClearButton.setImageResource(R.drawable.ic_close_white_24dp); // TODO: Get this image from here: https://github.com/google/material-design-icons
searchClearButton.setPadding(px, 0, px, 0);
searchClearButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
toolbarSearchView.setText("");
}
});
((LinearLayout) searchContainer).addView(searchClearButton);
// Add search view to toolbar and hide it
searchContainer.setVisibility(View.GONE);
toolbar.addView(searchContainer);
This worked, but then I came across an issue where onOptionsItemSelected() wasn't being called when I tapped on the home button. So I wasn't able to cancel the search by pressing the home button. I tried a few different ways of registering the click listener on the home button but they didn't work.
Eventually I found out that the ActionBarDrawerToggle I had was interfering with things, so I removed it. This listener then started working:
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// toolbarHomeButtonAnimating is a boolean that is initialized as false. It's used to stop the user pressing the home button while it is animating and breaking things.
if (!toolbarHomeButtonAnimating) {
// Here you'll want to check if you have a search query set, if you don't then hide the search box.
// My main fragment handles this stuff, so I call its methods.
FragmentManager fragmentManager = getFragmentManager();
final Fragment fragment = fragmentManager.findFragmentById(R.id.container);
if (fragment != null && fragment instanceof MainListFragment) {
if (((MainListFragment) fragment).hasSearchQuery() || searchContainer.getVisibility() == View.VISIBLE) {
displaySearchView(false);
return;
}
}
}
if (mDrawerLayout.isDrawerOpen(findViewById(R.id.navigation_drawer)))
mDrawerLayout.closeDrawer(findViewById(R.id.navigation_drawer));
else
mDrawerLayout.openDrawer(findViewById(R.id.navigation_drawer));
}
});
So I can now cancel the search with the home button, but I can't press the back button to cancel it yet. So I added this to onBackPressed():
FragmentManager fragmentManager = getFragmentManager();
final Fragment mainFragment = fragmentManager.findFragmentById(R.id.container);
if (mainFragment != null && mainFragment instanceof MainListFragment) {
if (((MainListFragment) mainFragment).hasSearchQuery() || searchContainer.getVisibility() == View.VISIBLE) {
displaySearchView(false);
return;
}
}
I created this method to toggle visibility of the EditText and menu item:
public void displaySearchView(boolean visible) {
if (visible) {
// Stops user from being able to open drawer while searching
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
// Hide search button, display EditText
menu.findItem(R.id.action_search).setVisible(false);
searchContainer.setVisibility(View.VISIBLE);
// Animate the home icon to the back arrow
toggleActionBarIcon(ActionDrawableState.ARROW, mDrawerToggle, true);
// Shift focus to the search EditText
toolbarSearchView.requestFocus();
// Pop up the soft keyboard
new Handler().postDelayed(new Runnable() {
public void run() {
toolbarSearchView.dispatchTouchEvent(MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, 0, 0, 0));
toolbarSearchView.dispatchTouchEvent(MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, 0, 0, 0));
}
}, 200);
} else {
// Allows user to open drawer again
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
// Hide the EditText and put the search button back on the Toolbar.
// This sometimes fails when it isn't postDelayed(), don't know why.
toolbarSearchView.postDelayed(new Runnable() {
#Override
public void run() {
toolbarSearchView.setText("");
searchContainer.setVisibility(View.GONE);
menu.findItem(R.id.action_search).setVisible(true);
}
}, 200);
// Turn the home button back into a drawer icon
toggleActionBarIcon(ActionDrawableState.BURGER, mDrawerToggle, true);
// Hide the keyboard because the search box has been hidden
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(toolbarSearchView.getWindowToken(), 0);
}
}
I needed a way to toggle the home button on the toolbar between the drawer icon and the back button. I eventually found the method below in this SO answer. Though I modified it slightly to made more sense to me:
private enum ActionDrawableState
{
BURGER, ARROW
}
private void toggleActionBarIcon(final ActionDrawableState state, final ActionBarDrawerToggle toggle, boolean animate) {
if (animate) {
float start = state == ActionDrawableState.BURGER ? 1.0f : 0f;
float end = Math.abs(start - 1);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
ValueAnimator offsetAnimator = ValueAnimator.ofFloat(start, end);
offsetAnimator.setDuration(300);
offsetAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
offsetAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
float offset = (Float) animation.getAnimatedValue();
toggle.onDrawerSlide(null, offset);
}
});
offsetAnimator.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
}
#Override
public void onAnimationEnd(Animator animation) {
toolbarHomeButtonAnimating = false;
}
#Override
public void onAnimationCancel(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
}
});
toolbarHomeButtonAnimating = true;
offsetAnimator.start();
}
} else {
if (state == ActionDrawableState.BURGER) {
toggle.onDrawerClosed(null);
} else {
toggle.onDrawerOpened(null);
}
}
}
This works, I've managed to work out a few bugs that I found along the way. I don't think it's 100% but it works well enough for me.
EDIT: If you want to add the search view in XML instead of Java do this:
toolbar.xml:
<android.support.v7.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/toolbar"
contentInsetLeft="72dp"
contentInsetStart="72dp"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:elevation="4dp"
android:minHeight="?attr/actionBarSize"
app:contentInsetLeft="72dp"
app:contentInsetStart="72dp"
app:popupTheme="#style/ActionBarPopupThemeOverlay"
app:theme="#style/ActionBarThemeOverlay">
<LinearLayout
android:id="#+id/search_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:orientation="horizontal">
<EditText
android:id="#+id/search_view"
android:layout_width="0dp"
android:layout_height="?attr/actionBarSize"
android:layout_weight="1"
android:background="#android:color/transparent"
android:gravity="center_vertical"
android:hint="Search"
android:imeOptions="actionSearch"
android:inputType="text"
android:maxLines="1"
android:paddingLeft="2dp"
android:singleLine="true"
android:textColor="#ffffff"
android:textColorHint="#b3ffffff" />
<ImageView
android:id="#+id/search_clear"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:src="#drawable/ic_close_white_24dp" />
</LinearLayout>
onCreate() of your Activity:
searchContainer = findViewById(R.id.search_container);
toolbarSearchView = (EditText) findViewById(R.id.search_view);
searchClearButton = (ImageView) findViewById(R.id.search_clear);
// Setup search container view
try {
// Set cursor colour to white
// http://stackoverflow.com/a/26544231/1692770
// https://github.com/android/platform_frameworks_base/blob/kitkat-release/core/java/android/widget/TextView.java#L562-564
Field f = TextView.class.getDeclaredField("mCursorDrawableRes");
f.setAccessible(true);
f.set(toolbarSearchView, R.drawable.edittext_whitecursor);
} catch (Exception ignored) {
}
// Search text changed listener
toolbarSearchView.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
Fragment mainFragment = getFragmentManager().findFragmentById(R.id.container);
if (mainFragment != null && mainFragment instanceof MainListFragment) {
((MainListFragment) mainFragment).search(s.toString());
}
}
#Override
public void afterTextChanged(Editable s) {
}
});
// Clear search text when clear button is tapped
searchClearButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
toolbarSearchView.setText("");
}
});
// Hide the search view
searchContainer.setVisibility(View.GONE);
Here is how I tried to implement it, please check this out.
https://github.com/Shahroz16/material-searchview
You can use AutoCompleteTextView to achieve this, Follow the link below
How to build Gmail like search box in the action bar?
I'm using android.app.AlertDialog that contains a ScrollView and inside (of course) some content.
Google shows in its material-guidelines a small grey line above the buttons when the content is larger than the visible space: http://www.google.com/design/spec/components/dialogs.html#dialogs-behavior
My alert-dialog doesn't have this grey line. How do I create this line?
I already tried a background for the ScrollView like this:
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<stroke
android:width="1dp"
android:color="#color/dark_transparent"/>
</shape>
But this created a line on top AND bottom. And it also appears when the content is smaller than the visible space, which looks ugly.
I found a solution for the grey line! :)
I found the solution how to show the grey line at all here: How to make a static button under a ScrollView?
For the check if I want to show it, I found the solution here: How can you tell when a layout has been drawn?
This is how my code looks like now:
This is my_material_dialog.xml:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<ScrollView
android:id="#+id/myMaterialDialog_scrollView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:fillViewport="true">
<LinearLayout
android:id="#+id/myMaterialDialog_textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="5dp"
android:paddingLeft="26dp"
android:paddingRight="26dp"
android:paddingTop="15dp">
<!-- dynamically added content goes here -->
</LinearLayout>
</ScrollView>
<View
android:id="#+id/myMaterialDialog_lineView"
android:layout_width="fill_parent"
android:layout_height="1dp"
android:layout_gravity="center_horizontal"
android:background="#15000000"
android:gravity="center_horizontal"
android:visibility="gone"/>
</LinearLayout>
And this is MyMaterialDialog.java:
public class MyMaterialDialog extends AlertDialog {
private Context context;
private ScrollView scrollView;
private LinearLayout textView;
private View lineView;
private boolean checkingLayout;
public MyMaterialDialog(final Context context) {
super(context);
this.context = context;
final View myMaterialDialog = getLayoutInflater().inflate(R.layout.my_material_dialog, null);
this.scrollView = (ScrollView) myMaterialDialog.findViewById(R.id.myMaterialDialog_scrollView);
this.textView = (LinearLayout) myMaterialDialog.findViewById(R.id.myMaterialDialog_textView);
this.lineView = myMaterialDialog.findViewById(R.id.myMaterialDialog_lineView);
final ViewTreeObserver vto = scrollView.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
if (checkingLayout) {
// avoid infinite recursions
return;
}
checkingLayout = true;
if (scrollView.canScrollVertically(1)) {
lineView.setVisibility(View.VISIBLE);
} else {
lineView.setVisibility(View.GONE);
}
checkingLayout = false;
}
});
setTitle(R.string.myMaterialDialog_title);
setText();
setView(myMaterialDialog);
show();
}
/**
* do request to webserver for texts
*/
private final void setText() {
final GetDialogTextRequest request = new GetDialogTextRequest();
final GetDialogTextResultHandler resultHandler = new GetDialogTextResultHandler(context, textView);
request.submit(resultHandler);
}
}
private final class GetDialogTextResultHandler extends DefaultRequestResultHandler<List<MyTextObject>> {
private final Context context;
private final LinearLayout textView;
private GetDialogTextResultHandler(final Context context, final LinearLayout textView) {
super(context);
this.context = context;
this.textView = textView;
}
#Override
public void handleResult(final List<MyTextObject> texts) {
setText(texts); // ... sets the content, can vary in size
}
}
Add something like this below your ScrollView:
<View android:layout_width="fill_parent"
android:layout_height="2px"
android:background="#90909090"/>
It should give you a slim greyish horizontal bar.
If you're using API 23+ (Android 6.0) using the following in scroll view will add the top and bottom indicators.
android:scrollIndicators="top|bottom"
If targeting older API's I looked into Google's Alert Dialog controller source code, and am using the following code:
private static void setScrollIndicators(ViewGroup root, final NestedScrollView content,
final int indicators, final int mask) {
// use it like this:
// setScrollIndicators(contentPanel, content, indicators,
// ViewCompat.SCROLL_INDICATOR_TOP | ViewCompat.SCROLL_INDICATOR_BOTTOM);
// Set up scroll indicators (if present).
View indicatorUp = root.findViewById(R.id.scrollIndicatorUp);
View indicatorDown = root.findViewById(R.id.scrollIndicatorDown);
if (Build.VERSION.SDK_INT >= 23) {
// We're on Marshmallow so can rely on the View APIsaa
ViewCompat.setScrollIndicators(content, indicators, mask);
// We can also remove the compat indicator views
if (indicatorUp != null) {
root.removeView(indicatorUp);
}
if (indicatorDown != null) {
root.removeView(indicatorDown);
}
} else {
// First, remove the indicator views if we're not set to use them
if (indicatorUp != null && (indicators & ViewCompat.SCROLL_INDICATOR_TOP) == 0) {
root.removeView(indicatorUp);
indicatorUp = null;
}
if (indicatorDown != null && (indicators & ViewCompat.SCROLL_INDICATOR_BOTTOM) == 0) {
root.removeView(indicatorDown);
indicatorDown = null;
}
if (indicatorUp != null || indicatorDown != null) {
final View top = indicatorUp;
final View bottom = indicatorDown;
if (content != null) {
// We're just showing the ScrollView, set up listener.
content.setOnScrollChangeListener(
new NestedScrollView.OnScrollChangeListener() {
#Override
public void onScrollChange(NestedScrollView v, int scrollX,
int scrollY,
int oldScrollX, int oldScrollY) {
manageScrollIndicators(v, top, bottom);
}
});
// Set up the indicators following layout.
content.post(new Runnable() {
#Override
public void run() {
manageScrollIndicators(content, top, bottom);
}
});
} else {
// We don't have any content to scroll, remove the indicators.
if (top != null) {
root.removeView(top);
}
if (bottom != null) {
root.removeView(bottom);
}
}
}
}
}
private static void manageScrollIndicators(View v, View upIndicator, View downIndicator) {
if (upIndicator != null) {
upIndicator.setVisibility(
ViewCompat.canScrollVertically(v, -1) ? View.VISIBLE : View.INVISIBLE);
}
if (downIndicator != null) {
downIndicator.setVisibility(
ViewCompat.canScrollVertically(v, 1) ? View.VISIBLE : View.INVISIBLE);
}
}
And XML looks like this:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<View
android:id="#+id/scrollIndicatorUp"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#color/dim_white"
android:visibility="gone"
tools:visibility="visible" />
<android.support.v4.widget.NestedScrollView
android:id="#+id/scrollView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<... you content here>
</android.support.v4.widget.NestedScrollView>
<View
android:id="#+id/scrollIndicatorDown"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#color/dim_white"
android:visibility="gone"
tools:visibility="visible" />
</LinearLayout>
i need some guidance. I need to make a custom view that touched and drag up the screen slides out of the screen. I have tried this cool library: here but this is dependend to exactly 2 layouts. The one that is slided out and the one that remains after that. What i have now is buggy and ugly.
public class DemoActivity extends Activity {
private SlidingUpPanelLayout mLayout;
private RelativeLayout layout;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_demo);
layout = (RelativeLayout) findViewById(R.id.panel);
final int defaulttop = layout.getTop();
final int defaultbottom = layout.getBottom();
RelativeLayout dragView = (RelativeLayout) findViewById(R.id.dragView);
mLayout = (SlidingUpPanelLayout) findViewById(R.id.sliding_layout);
mLayout.setDragView(dragView);
mLayout.setPanelSlideListener(new PanelSlideListener() {
#Override
public void onPanelSlide(View panel, float slideOffset) {
}
#Override
public void onPanelExpanded(View panel) {
System.out.println("panel expanded");
}
#Override
public void onPanelCollapsed(View panel) {
System.out.println("panel collapsed");
}
#Override
public void onPanelAnchored(View panel) {
System.out.println("anchored");
}
#Override
public void onPanelHidden(View panel) {
System.out.println("panel is hidden now");
}
});
}
#Override
public void onBackPressed() {
if (mLayout != null && mLayout.isPanelExpanded()) {
mLayout.collapsePanel();
} else {
super.onBackPressed();
}
}
}
The layout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".DemoActivity" >
<com.sothree.slidinguppanel.SlidingUpPanelLayout
xmlns:sothree="http://schemas.android.com/apk/res-auto"
android:id="#+id/sliding_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/transparent"
android:gravity="bottom"
sothree:dragView="#+id/dragView"
sothree:panelHeight="60dp"
sothree:paralaxOffset="60dp"
sothree:shadowHeight="0dp" >
<RelativeLayout
android:id="#+id/panel"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/unt"
android:orientation="vertical" >
<Button
android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_gravity="center"
android:text="Sleep" />
</RelativeLayout>
<RelativeLayout
android:id="#+id/dragView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/transparent"
android:clickable="true"
android:focusable="false" >
</RelativeLayout>
</com.sothree.slidinguppanel.SlidingUpPanelLayout>
</RelativeLayout>
it slides up but leaves a white background in the back. If i touch the screen then it slides. So, i need a new path. Did anyone confrunted with something similar? I need a hint, not code. Thanks.
I have used the library you mentioned here and it worked out fine for me. You might have not set the drag view/layout
Do use mSlidingPanelLayout.setDragView(YourLayout) to set the layout that can be dragged
I have done something like this previously but with a button.
I did it using Animation class when moving it by OnTouchListener. While you have to be careful while using it and control the X and Y values of the layout.
I'm trying to figure out the right way to use a custom font for the toolbar title, and center it in the toolbar (client requirement).
At the moment, i'm using the good old ActionBar, and I was setting the title to empty value, and using setCustomView to put my custom font TextView and center it using ActionBar.LayoutParams.
Is there a better way to do that? Using the new Toolbar as my ActionBar.
To use a custom title in your Toolbar all you need to do is remember is that Toolbar is just a fancy ViewGroup so you can add a custom title like so:
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar_top"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:minHeight="?android:attr/actionBarSize"
android:background="#color/action_bar_bkgnd"
app:theme="#style/ToolBarTheme" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Toolbar Title"
android:layout_gravity="center"
android:id="#+id/toolbar_title" />
</android.support.v7.widget.Toolbar>
This means that you can style the TextView however you would like because it's just a regular TextView. So in your activity you can access the title like so:
Toolbar toolbarTop = (Toolbar) findViewById(R.id.toolbar_top);
TextView mTitle = (TextView) toolbarTop.findViewById(R.id.toolbar_title);
This's just to help to join all pieces using #MrEngineer13 answer with #Jonik and #Rick Sanchez comments with the right order to help to achieve title centered easly!!
The layout with TextAppearance.AppCompat.Widget.ActionBar.Title :
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="#style/AppTheme.PopupOverlay">
<TextView
android:id="#+id/toolbar_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="#style/TextAppearance.AppCompat.Widget.ActionBar.Title"
android:layout_gravity="center" />
</android.support.v7.widget.Toolbar>
The way to achieve with the right order:
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
TextView mTitle = (TextView) toolbar.findViewById(R.id.toolbar_title);
setSupportActionBar(toolbar);
mTitle.setText(toolbar.getTitle());
getSupportActionBar().setDisplayShowTitleEnabled(false);
Please don't forget to upvote #MrEngineer13 answer !!!
Here is a sample project ToolbarCenterTitleSample
Hope to help somebody else ;)
The ToolBar title is stylable. Any customization you make has to be made in the theme. I'll give you an example.
Toolbar layout:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar
style="#style/ToolBarStyle.Event"
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
android:minHeight="#dimen/abc_action_bar_default_height_material" />
Styles:
<style name="ToolBarStyle" parent="ToolBarStyle.Base"/>
<style name="ToolBarStyle.Base" parent="">
<item name="popupTheme">#style/ThemeOverlay.AppCompat.Light</item>
<item name="theme">#style/ThemeOverlay.AppCompat.Dark.ActionBar</item>
</style>
<style name="ToolBarStyle.Event" parent="ToolBarStyle">
<item name="titleTextAppearance">#style/TextAppearance.Widget.Event.Toolbar.Title</item>
</style>
<style name="TextAppearance.Widget.Event.Toolbar.Title" parent="TextAppearance.Widget.AppCompat.Toolbar.Title">
<!--Any text styling can be done here-->
<item name="android:textStyle">normal</item>
<item name="android:textSize">#dimen/event_title_text_size</item>
</style>
we don't have direct access to the ToolBar title TextView so we use reflection to access it.
private TextView getActionBarTextView() {
TextView titleTextView = null;
try {
Field f = mToolBar.getClass().getDeclaredField("mTitleTextView");
f.setAccessible(true);
titleTextView = (TextView) f.get(mToolBar);
} catch (NoSuchFieldException e) {
} catch (IllegalAccessException e) {
}
return titleTextView;
}
Define the following class:
public class CenteredToolbar extends Toolbar {
private TextView centeredTitleTextView;
public CenteredToolbar(Context context) {
super(context);
}
public CenteredToolbar(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
}
public CenteredToolbar(Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
public void setTitle(#StringRes int resId) {
String s = getResources().getString(resId);
setTitle(s);
}
#Override
public void setTitle(CharSequence title) {
getCenteredTitleTextView().setText(title);
}
#Override
public CharSequence getTitle() {
return getCenteredTitleTextView().getText().toString();
}
public void setTypeface(Typeface font) {
getCenteredTitleTextView().setTypeface(font);
}
private TextView getCenteredTitleTextView() {
if (centeredTitleTextView == null) {
centeredTitleTextView = new TextView(getContext());
centeredTitleTextView.setTypeface(...);
centeredTitleTextView.setSingleLine();
centeredTitleTextView.setEllipsize(TextUtils.TruncateAt.END);
centeredTitleTextView.setGravity(Gravity.CENTER);
centeredTitleTextView.setTextAppearance(getContext(), R.style.TextAppearance_AppCompat_Widget_ActionBar_Title);
Toolbar.LayoutParams lp = new Toolbar.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
lp.gravity = Gravity.CENTER;
centeredTitleTextView.setLayoutParams(lp);
addView(centeredTitleTextView);
}
return centeredTitleTextView;
}
}
...and then just use it instead of regular Toolbar like this:
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/colorAccent">
<your.packagename.here.CenteredToolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
android:minHeight="?attr/actionBarSize"
android:theme="?attr/actionBarTheme"
app:title="#string/reset_password_page_title"/>
<!-- Other views -->
</RelativeLayout>
You still need these 2 lines of code in your Activity (as with standard Toolbar):
Toolbar toolbar = (Toolbar) findViewByid(R.id.toolbar); // note that your activity doesn't need to know that it is actually a custom Toolbar
setSupportActionBar(binding.toolbar);
That's it! You don't need to hide the standard left-aligned title, don't need to duplicate the same XML code over and over, etc., just use CenteredToolbar like if it was default Toolbar. You can also set your custom font programatically since you now have direct access to the TextView. Hope this helps.
MaterialToolbar from Material Components 1.4.0-alpha02 now has the ability to center the toolbar's title by setting the titleCentered attribute to true:
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.appbar.MaterialToolbar
android:id="#+id/topAppBar"
style="#style/Widget.MaterialComponents.Toolbar.Primary"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:titleCentered="true" />
</com.google.android.material.appbar.AppBarLayout>
Here is title text dependant approach to find TextView instance from Toolbar.
public static TextView getToolbarTitleView(ActionBarActivity activity, Toolbar toolbar){
ActionBar actionBar = activity.getSupportActionBar();
CharSequence actionbarTitle = null;
if(actionBar != null)
actionbarTitle = actionBar.getTitle();
actionbarTitle = TextUtils.isEmpty(actionbarTitle) ? toolbar.getTitle() : actionbarTitle;
if(TextUtils.isEmpty(actionbarTitle)) return null;
// can't find if title not set
for(int i= 0; i < toolbar.getChildCount(); i++){
View v = toolbar.getChildAt(i);
if(v != null && v instanceof TextView){
TextView t = (TextView) v;
CharSequence title = t.getText();
if(!TextUtils.isEmpty(title) && actionbarTitle.equals(title) && t.getId() == View.NO_ID){
//Toolbar does not assign id to views with layout params SYSTEM, hence getId() == View.NO_ID
//in same manner subtitle TextView can be obtained.
return t;
}
}
}
return null;
}
No one has mentioned this, but there are some attributes for Toolbar:
app:titleTextColor for setting the title text color
app:titleTextAppearance for setting the title text appearance
app:titleMargin for setting the margin
And there are other specific-side margins such as marginStart, etc.
I use this solution:
static void centerToolbarTitle(#NonNull final Toolbar toolbar) {
final CharSequence title = toolbar.getTitle();
final ArrayList<View> outViews = new ArrayList<>(1);
toolbar.findViewsWithText(outViews, title, View.FIND_VIEWS_WITH_TEXT);
if (!outViews.isEmpty()) {
final TextView titleView = (TextView) outViews.get(0);
titleView.setGravity(Gravity.CENTER);
final Toolbar.LayoutParams layoutParams = (Toolbar.LayoutParams) titleView.getLayoutParams();
layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
toolbar.requestLayout();
//also you can use titleView for changing font: titleView.setTypeface(Typeface);
}
}
Without toolbar TextView we can customize font by using below code
getSupportActionBar().setDisplayShowTitleEnabled(false);
or
getActionBar().setDisplayShowTitleEnabled(false);
public void updateActionbar(String title){
SpannableString spannableString = new SpannableString(title);
spannableString.setSpan(new TypefaceSpanString(this, "futurastdmedium.ttf"),
0, spannableString.length(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
mToolbar.setTitle(spannableString);
}
public class TestActivity extends AppCompatActivity {
private Toolbar toolbar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.setContentView(R.layout.activity_test);
toolbar = (Toolbar) findViewById(R.id.tool_bar); // Attaching the layout to the toolbar object
setSupportActionBar(toolbar);
customizeToolbar(toolbar);
}
public void customizeToolbar(Toolbar toolbar){
// Save current title and subtitle
final CharSequence originalTitle = toolbar.getTitle();
final CharSequence originalSubtitle = toolbar.getSubtitle();
// Temporarily modify title and subtitle to help detecting each
toolbar.setTitle("title");
toolbar.setSubtitle("subtitle");
for(int i = 0; i < toolbar.getChildCount(); i++){
View view = toolbar.getChildAt(i);
if(view instanceof TextView){
TextView textView = (TextView) view;
if(textView.getText().equals("title")){
// Customize title's TextView
Toolbar.LayoutParams params = new Toolbar.LayoutParams(Toolbar.LayoutParams.WRAP_CONTENT, Toolbar.LayoutParams.MATCH_PARENT);
params.gravity = Gravity.CENTER_HORIZONTAL;
textView.setLayoutParams(params);
// Apply custom font using the Calligraphy library
Typeface typeface = TypefaceUtils.load(getAssets(), "fonts/myfont-1.otf");
textView.setTypeface(typeface);
} else if(textView.getText().equals("subtitle")){
// Customize subtitle's TextView
Toolbar.LayoutParams params = new Toolbar.LayoutParams(Toolbar.LayoutParams.WRAP_CONTENT, Toolbar.LayoutParams.MATCH_PARENT);
params.gravity = Gravity.CENTER_HORIZONTAL;
textView.setLayoutParams(params);
// Apply custom font using the Calligraphy library
Typeface typeface = TypefaceUtils.load(getAssets(), "fonts/myfont-2.otf");
textView.setTypeface(typeface);
}
}
}
// Restore title and subtitle
toolbar.setTitle(originalTitle);
toolbar.setSubtitle(originalSubtitle);
}
}
Layout:
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar_top"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:minHeight="?attr/actionBarSize"
android:background="#color/action_bar_bkgnd"
app:theme="#style/ToolBarTheme" >
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Toolbar Title"
android:layout_gravity="center"
android:gravity="center"
android:id="#+id/toolbar_title" />
</android.support.v7.widget.Toolbar>
Code:
Toolbar mToolbar = parent.findViewById(R.id.toolbar_top);
TextView mToolbarCustomTitle = parent.findViewById(R.id.toolbar_title);
//setup width of custom title to match in parent toolbar
mToolbar.postDelayed(new Runnable()
{
#Override
public void run ()
{
int maxWidth = mToolbar.getWidth();
int titleWidth = mToolbarCustomTitle.getWidth();
int iconWidth = maxWidth - titleWidth;
if (iconWidth > 0)
{
//icons (drawer, menu) are on left and right side
int width = maxWidth - iconWidth * 2;
mToolbarCustomTitle.setMinimumWidth(width);
mToolbarCustomTitle.getLayoutParams().width = width;
}
}
}, 0);
A very quick and easy way to set a custom font is to use a custom titleTextAppearance with a fontFamily:
Add to styles.xml:
<style name="ToolbarTitle" parent="TextAppearance.Widget.AppCompat.Toolbar.Title">
<item name="android:textSize">16sp</item>
<item name="android:textColor">#FF202230</item>
<item name="android:fontFamily">#font/varela_round_regular</item>
</style>
In your res folder create a font folder (Ex: varela_round_regular.ttf)
Read the official guide to find out more https://developer.android.com/guide/topics/ui/look-and-feel/fonts-in-xml.html
Solution that I used for this problem:
public static void applyFontForToolbarTitle(Activity a){
Toolbar toolbar = (Toolbar) a.findViewById(R.id.app_bar);
for(int i = 0; i < toolbar.getChildCount(); i++){
View view = toolbar.getChildAt(i);
if(view instanceof TextView){
TextView tv = (TextView) view;
if(tv.getText().equals(a.getTitle())){
tv.setTypeface(getRuneTypefaceBold(a));
break;
}
}
}
}
For center gravity I think it would be necessary to change layout params to match_parent horizontally and then:
tv.setGravity(Gravity.CENTER);
I don't know if anything changed in the appcompat library but it's fairly trivial, no need for reflection.
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
// loop through all toolbar children right after setting support
// action bar because the text view has no id assigned
// also make sure that the activity has some title here
// because calling setText() with an empty string actually
// removes the text view from the toolbar
TextView toolbarTitle = null;
for (int i = 0; i < toolbar.getChildCount(); ++i) {
View child = toolbar.getChildAt(i);
// assuming that the title is the first instance of TextView
// you can also check if the title string matches
if (child instanceof TextView) {
toolbarTitle = (TextView)child;
break;
}
}
I solved this solution , And this is a following codes:
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="#style/AppTheme.PopupOverlay" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Order History"
android:layout_gravity="center"
android:id="#+id/toolbar_title"
android:textSize="17sp"
android:textStyle="bold"
android:textColor="#color/colorWhite"
/>
</android.support.v7.widget.Toolbar>
And you can change title/label , in Activity, write a below codes:
Toolbar toolbarTop = (Toolbar) findViewById(R.id.toolbar_top);
TextView mTitle = (TextView) toolbarTop.findViewById(R.id.toolbar_title);
mTitle.setText("#string/....");
You can use like the following
<android.support.v7.widget.Toolbar
android:id="#+id/top_actionbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppThemeToolbar">
<TextView
android:id="#+id/pageTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
/>
</android.support.v7.widget.Toolbar>
With the Material Components, starting from the version 1.4.x as described in the doc you can use the MaterialToolbar.
Just add the attribute app:titleCentered and/or app:subtitleCentered attributes to true on your MaterialToolbar.
Something like:
<com.google.android.material.appbar.MaterialToolbar
android:id="#+id/topAppBar"
app:titleCentered="true"
... />
With Compose using the Material3 package you can simply use the CenterAlignedTopAppBar:
CenterAlignedTopAppBar(
title = { Text("Centered TopAppBar") },
navigationIcon = {
IconButton(onClick = { /* doSomething() */ }) {
Icon(
imageVector = Icons.Filled.Menu,
contentDescription = "Localized description"
)
}
}
)
If you are using Compose and the Material2 package, there isn't a builtin component but you can customize the layout of content inside the TopAppBar as described in this answer.
Update from #MrEngineer13's answer: to align title center in any cases, including Hamburger icon, option menus, you can add a FrameLayout in toolbar like this:
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar_top"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:minHeight="?attr/actionBarSize"
android:background="#color/action_bar_bkgnd"
app:theme="#style/ToolBarTheme" >
<FrameLayout android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Toolbar Title"
android:layout_gravity="center"
style="#style/TextAppearance.AppCompat.Widget.ActionBar.Title"
android:id="#+id/toolbar_title" />
</FrameLayout>
</android.support.v7.widget.Toolbar>
Now using Material Design 3 we can align the title in the center without doing extra work or without adding a text view in the toolbar
Added below dependencies in build.gradle file
implementation 'com.google.android.material:material:1.6.1'
To align the title in the center We need to use the below properly
app:titleCentered="true"
To align subtitles in the center we need to use the below property
app:subtitleCentered="true"
Sample Code
<?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">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.appbar.MaterialToolbar
android:id="#+id/topAppBar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:title="AskNilesh"
app:subtitle="Nilesh"
app:subtitleCentered="true"
app:menu="#menu/top_app_bar"
app:titleCentered="true"
app:navigationIcon="#drawable/ic_android_black_24dp" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
</androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
OUTPUT
Even though adding a text view to the toolbar can solve the problem of the restriction of title styling, there is an issue with it. Since we are not adding it to a layout, we do not have too much control over its width. We can either use wrap_content or match_parent.
Now consider a scenario where we have a searchView as a button on the right edge of the toolbar. If the title contents are more, it will go on top of the button obscuring it. There is no way of controlling this short of setting a width to the label and is something you don't want to do if you want to have a responsive design.
So, here is a solution that worked for me which is slightly different from adding a textview to the toolbar. Instead of that, add the toolbar and text view to a relative layout and ensure that the text view is on top of the toolbar. Then we can use appropriate margins and make sure the text view shows up where we want it to show up.
Make sure you set the toolbar to not show the title.
Here is the XML for this solution:
<RelativeLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary">
<android.support.v7.widget.Toolbar
android:theme="#style/ThemeOverlay.AppCompat.Dark"
android:id="#+id/activity_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:titleTextAppearance="#style/AppTheme.TitleTextView"
android:layout_marginRight="40dp"
android:layoutMode="clipBounds">
<android.support.v7.widget.SearchView
android:id="#+id/search_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:foregroundTint="#color/white" />
</android.support.v7.widget.Toolbar>
<TextView
android:id="#+id/toolbar_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginRight="90dp"
android:text="#string/app_name"
android:textSize="#dimen/title_text_size"
android:textColor="#color/white"
android:lines="1"
android:layout_marginLeft="72dp"
android:layout_centerVertical="true" />
</RelativeLayout>
Solves the issue #ankur-chaudhary mentioned above.
Since android.support.v7.appcompat 24.2 Toolbar has method setTitleTextAppearance and you can set its font without external textview.
create new style in styles.xml
<style name="RobotoBoldTextAppearance">
<item name="android:fontFamily">#font/roboto_condensed_bold</item>
</style>
and use it
mToolbar.setTitleTextAppearance(this, R.style.RobotoBoldTextAppearance);
I spent several days searching for a universal solution. My toolbar working with android menu and nav icon.
At first, you need create custom toolbar class. This class must have calculate title centered positions (paddings):
class CenteredToolbar #JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0)
: Toolbar(context, attrs, defStyleAttr) {
init {
addOnLayoutChangeListener(object : View.OnLayoutChangeListener {
override fun onLayoutChange(v: View?, left: Int, top: Int, right: Int, bottom: Int, oldLeft: Int, oldTop: Int, oldRight: Int, oldBottom: Int) {
val titleTextView = findViewById<TextView>(R.id.centerTitle)
val x = titleTextView.x.toInt()
val x2 = x + titleTextView.width
val fullWidth = width
val fullCenter = fullWidth / 2
val offsetLeft = Math.abs(fullCenter - x)
val offsetRight = Math.abs(x2 - fullCenter)
val differOffset = Math.abs(offsetLeft - offsetRight)
if (offsetLeft > offsetRight) {
titleTextView.setPadding(differOffset, 0, 0, 0)
} else if (offsetRight > offsetLeft) {
titleTextView.setPadding(0, 0, differOffset, 0)
}
removeOnLayoutChangeListener(this)
}
})
}
override fun setTitle(resId: Int) = getTitleView().setText(resId)
override fun setTitle(title: CharSequence?) = getTitleView().setText(title)
fun getTitleView(): TextView = findViewById(R.id.centerTitle)
}
Secondly, you need create layout toolbar:
<CenteredToolbar xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/toolbar">
<TextView
android:id="#+id/centerTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</CenteredToolbar>
That's all
Try taking Toolbar and tittle in a separate view. Take a view on right end and given them weight equal to the toolbar weight. In this way your tittle will come in center.
<android.support.design.widget.AppBarLayout
android:id="#+id/app_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppTheme.AppBarOverlay"
android:background="#color/white_color">
<LinearLayout
android:id="#+id/toolbar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/white_color">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="0dp"
android:layout_height="?attr/actionBarSize"
android:background="#color/white_color"
app:popupTheme="#style/AppTheme.PopupOverlay"
app:contentInsetLeft="0dp"
app:contentInsetStart="0dp"
android:layout_weight="0.2"
app:contentInsetStartWithNavigation="0dp"
app:navigationIcon="#color/greyTextColor">
</android.support.v7.widget.Toolbar>
<com.an.customfontview.CustomTextView
android:id="#+id/headingText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.6"
android:gravity="center"
android:text="Heading"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:textColor="#color/colorPrimary"
android:textSize="#dimen/keyboard_number"
android:layout_gravity="center_horizontal|center_vertical"
app:textFontPath="fonts/regular.ttf" />
<ImageView
android:id="#+id/search_icon"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:visibility="visible"
android:layout_weight="0.2"
android:layout_gravity="center_horizontal|center_vertical"
android:src="#drawable/portfolio_icon"/>
</LinearLayout>
</android.support.design.widget.AppBarLayout>
You can insert this code in your xml file
<androidx.appcompat.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/colorPrimaryDark"
android:elevation="4dp"
android:theme="#style/ThemeOverlay.AppCompat.ActionBar">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Toolbar Title"
android:textColor="#000000"
android:textSize="20dp"
android:id="#+id/toolbar_title" />
</androidx.appcompat.widget.Toolbar>
To use a custom title in your Toolbar you can add a custom title like :
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:elevation="5dp"
app:contentInsetLeft="0dp"
app:contentInsetStart="0dp"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light"
app:theme="#style/ThemeOverlay.AppCompat.Dark">
<LinearLayout
android:id="#+id/lnrTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:orientation="vertical">
<TextView
android:id="#+id/txvHeader"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal|center"
android:gravity="center"
android:ellipsize="end"
android:maxLines="1"
android:text="Header"
android:textColor="#color/white"
android:textSize="18sp" />
</LinearLayout>
</android.support.v7.widget.Toolbar>
Java Code:
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
if (getSupportActionBar() == null)
return;
getSupportActionBar().setTitle("Title");
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
Use com.google.android.material.appbar.MaterialToolbar and app:titleCentered="true" tag
<com.google.android.material.appbar.MaterialToolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:titleCentered="true" />
private void makeTitleCenter(String title, Toolbar toolbar) {
if (title != null && !TextUtils.isEmpty(title.trim())) {
final String tag = " ";
if (getSupportActionBar() != null) {
getSupportActionBar().setTitle(tag);
}
TextView titleTv = null;
View leftBtn = null;
for (int i = 0; i < toolbar.getChildCount(); i++) {
View view = toolbar.getChildAt(i);
CharSequence text = null;
if (view instanceof TextView && (text = ((TextView) view).getText()) != null && text.equals(tag)) {
titleTv = (TextView) view;
} else if (view instanceof ImageButton) {
leftBtn = view;
}
}
if (titleTv != null) {
final TextView fTitleTv = titleTv;
final View fLeftBtn = leftBtn;
fTitleTv.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
fTitleTv.getViewTreeObserver().removeOnGlobalLayoutListener(this);
int leftWidgetWidth = fLeftBtn != null ? fLeftBtn.getWidth() : 0;
fTitleTv.setPadding(DimenUtil.getResources().getDisplayMetrics().widthPixels / 2 - leftWidgetWidth - fTitleTv.getWidth() / 2, 0, 0, 0);
fTitleTv.requestLayout();
}
});
}
}
}
for custom font in toolbar you can override textView font in style and then every textView in your app also toolbar title font changed automatically
i tested it in android studio 3.1.3
in style do it:
<style name="defaultTextViewStyle" parent="android:Widget.TextView">
<item name="android:fontFamily">#font/your_custom_font</item>
</style>
and then in your theme use this:
<item name="android:textViewStyle">#style/defaultTextViewStyle</item>
I found another way to add custom toolbar without any adicional Java/Kotlin code.
First: create a XML with your custom toolbar layout with AppBarLayout as the parent:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.AppBarLayout
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="wrap_content"
android:theme="#style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="#style/AppTheme.PopupOverlay">
<ImageView
android:layout_width="80dp"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:layout_marginEnd="#dimen/magin_default"
android:src="#drawable/logo" />
</android.support.v7.widget.Toolbar>
Second: Include the toolbar in your 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"
android:background="#color/blue"
tools:context=".app.MainAcitivity"
tools:layout_editor_absoluteY="81dp">
<include
layout="#layout/toolbar_inicio"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<!-- Put your layout here -->
</android.support.constraint.ConstraintLayout>