What should be action bar's height compatible for all devices? - android

I am using different layout for action bar and add different items to it that matched to my requirements. and then calling it in java class like this
ActionBar actionBar = getActionBar();
actionBar.setCustomView(R.layout.actionbar);
actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
actionBar.setDisplayShowHomeEnabled(false);
It looks fine for 2 or 3 different devices but doesn't look compatible for nexus7 tablet and xhdpi. The height of action bar is small for that and it gives empty space.What should I do to manage this? I am using
android:layout_width="match_parent"
android:layout_height="48dp"
in actionbar layout.I have also used
android:layout_height="wrap_content"
but it doesn't work at all.I don't know how to fix it. Please help.

You can set the height of the action bar at source not in the resources.
so all you need is to calculate the height of the action bar :
TypedValue tv = new TypedValue();
if (getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true))
{
actionBarHeight = TypedValue.complexToDimensionPixelSize(tv.data,getResources().getDisplayMetrics());
}

ActionBar bar = getSupportActionBar();
Display d = getWindowManager().getDefaultDisplay();
DisplayMetrics dm = new DisplayMetrics();
d.getMetrics(dm);
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)myCustomView.getLayoutParams();
final int ACTION_BAR_HEIGHT = dm.heightPixels/10; // 1/10 from screen height
lp.height = ACTION_BAR_HEIGHT;
myCustomView.setLayoutParams(lp);
bar.setCustomView(myCustomView);

Related

Why does the navigation_bar_item_icon_container reset the gravity setting?

My goal is to customize the navigation bar by changing the default icon that is in the center of the navigation bar.
I have increased the size of this icon programmatically and checked the source code where I saw that navigation_bar_item_icon_container has android:layout_gravity="center_horizontal" so I changed it to center too.
In the end I got a good result.
But after switching the menu items, the gravity setting is reset on the configured element, and it slides down.
How can I fix it so that it doesn't slide down?
My code to change the size of the central icon:
private void increaseSizeOfHomeNavigationButton() {
BottomNavigationView bottomNavigationView = findViewById(R.id.navigation_view);
Menu menu = bottomNavigationView.getMenu();
MenuItem menuItem = menu.getItem(2);
View navigationBarItemView = bottomNavigationView.findViewById(menuItem.getItemId());
View iconItemView = navigationBarItemView.findViewById(
com.google.android.material.R.id.navigation_bar_item_icon_container);
FrameLayout.LayoutParams iconItemViewParams =
(FrameLayout.LayoutParams) iconItemView.getLayoutParams();
iconItemViewParams.width = (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
50F,
getResources().getDisplayMetrics());
iconItemViewParams.height = (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
50F,
getResources().getDisplayMetrics());
iconItemViewParams.gravity = Gravity.CENTER;
iconItemView.setLayoutParams(iconItemViewParams);
VectorDrawable foreground =
(VectorDrawable) AppCompatResources.getDrawable(this, R.drawable.ic_home_fine);
iconItemView.setForeground(foreground);
}
What I want to have (and have before switching tabs):
And what I have after switching tabs:

How to hide actionbar based on layout in Android

I want to disable actionBar when the layout is changed for smaller devices but I dont know how to do it. Probably I will do
ActionBar actionBar = getSupportActionBar();
actionBar.hide();
but how to check the layout?
Its simple you can use this example to get the size of the screen and then hide the ActionBar if needed.
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
double x = Math.pow(dm.widthPixels/dm.xdpi,2);
double y = Math.pow(dm.heightPixels/dm.ydpi,2);
double screenInches = Math.sqrt(x+y);
it will get you the size of the screen in inches. and if you want it in pixels then you can use
Display display = getWindowManager().getDefaultDisplay();
int width = display.getWidth();
int height = display.getHeight();
Hope it helps
There are a number of options in this situation.
Firstly, are you sure that your application will be useable without an action bar? e.g. Why do you need an action bar on large devices when you can do without it on smaller devices?
Are you using the Android Toolbar (Which I recommend)? If so you can choose not to include the toolbar in your layout for the smaller screen in your layout xml files. e.g. Include the toolbar in layout-large directory and exclude it from layout-small. Then when you bind the views in your activity/fragment handle the case where the toolbar view is not found.
Toolbar toolbar = (Toolbar)findViewById(R.id.myToolbar);
if(toolbar != null) {
//set up my toolbar here which might include
setSupportActionBar(toolbar);
}
Another option is to use multiple styles for different size screens. Where for the large screen your style is Theme.AppCompat.Light.DarkActionBar and for your small screen its Theme.AppCompat.Light.NoActionBar
Probably your best approach is to make a copy of your style.xml of the res/values to the res/values-mdpi (or your desired layout size) and change the AppTheme to your style + .NoActionBar.
Example:
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
If you want to check which layout was loaded you can add tags to your layout for example:
ldpi layout:
<RelativeLayout
android:width="match_parent"
android:height="match_parent"
android:id="#+id/mainlayout"
android:tag="ldpi" >
mdpi layout:
<RelativeLayout
android:width="match_parent"
android:height="match_parent"
android:id="#+id/mainlayout"
android:tag="mdpi" >
and so on.
In your program code you can now check which tag the layout have:
RelativeLayout layout = (RelativeLayout) findViewById(R.id.mainlayout);
String tag = layout.getTag();
if(tag != null && tag.equals("ldpi")) {
// Ldpi Layout loaded, hide actionbar
}
Use DisplayMetrics
public void setAppInvisible() {
actionBar.setVisibility(View.INVISIBLE);
// Or actionBar.hide();
}
DisplayMetrics dm = new DisplayMetrics();
getActivity().getWindowManager().getDefaultDisplay().getMetrics(dm);
int screenWidth = dm.widthPixels;
if(screenWidth < 500){
setAppInvisible();
}

AppCompat v7:21 Split Action Bar Broken?

I am currently developing an application in which I use a heavily modified Split Action Bar. Here is a link to the app's current state:
You'll notice a transparent action bar up top, with a custom view inflated into it, with a hacked together split action bar on bottom. The bottom view is actually a single action item with a custom view inflated into it and showAlways=true.
Currently I only support SDK v15+ and I don't really plan on changing that, but with the Lollipop AppCompat library that just released, I decided to implement it, so I could get some of that awesomeness in my app.
I've changed my theme to Theme.AppCompat.Light, and my MainActivity now extends ActionBarActivity instead of Activity.
All references to getActionBar have now been switched to getSupportActionBar, and with only those changes, this is what my activity now looks like:
You'll notice I got a UI dump from the Device Monitor, and it's shoving the bottom action bar into a weird space and calling that the action bar, and getting rid of my top custom view.
Here is my code for setting up my action bar:
public void initializeActionBar(){
View customNav = LayoutInflater.from(this).inflate(R.layout.action_bar_top, null);
actionBar = getSupportActionBar();
actionBar.setBackgroundDrawable(getResources().getDrawable(R.drawable.transparent_fifty_percent));
final PopupWindow window = addPopupWindow();
actionBarOptions = (ImageView)customNav.findViewById(R.id.options);
actionBarOptions.setVisibility(View.GONE);
actionBarOptions.setImageDrawable(app.svgToBitmapDrawable(getResources(), R.raw.vertical_ellipsis, app.scaleByDensity(48)));
actionBarOptions.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
window.showAsDropDown(actionBarOptions, 0, 0);
}
});
TextView title = (TextView) customNav.findViewById(R.id.screen_title);
Typeface font1 = Typeface.createFromAsset(getAssets(), "Merriweather-Italic.ttf");
title.setText("Parsley");
title.setTypeface(font1);
actionBar.setCustomView(customNav);
actionBar.setDisplayShowCustomEnabled(true);
actionBar.setDisplayShowTitleEnabled(false);
actionBar.setDisplayShowHomeEnabled(false);
actionBar.setDisplayUseLogoEnabled(false);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
new MenuInflater(this).inflate(R.menu.test, menu);
LinearLayout fullMenu = (LinearLayout) menu.findItem(R.id.full_menu).getActionView();
ViewGroup.LayoutParams params;
icon1 = (ImageView) fullMenu.findViewById(R.id.action_item1);
params = icon1.getLayoutParams();
params.width = getResources().getDisplayMetrics().widthPixels / 4;
params.height = (int) (48 * getResources().getDisplayMetrics().density);
icon1.setImageDrawable(app.svgToBitmapDrawable(getResources(), R.raw.shopping_list_icon, app.scaleByDensity(32)));
icon2 = (ImageView) fullMenu.findViewById(R.id.action_item2);
icon3 = (ImageView) fullMenu.findViewById(R.id.action_item3);
icon4 = (ImageView) fullMenu.findViewById(R.id.action_item4);
icon2.setImageDrawable(app.svgToBitmapDrawable(getResources(), R.raw.recipe_box_icon, app.scaleByDensity(32)));
icon3.setImageDrawable(app.svgToBitmapDrawable(getResources(), R.raw.icon_search, app.scaleByDensity(32)));
icon4.setImageDrawable(app.svgToBitmapDrawable(getResources(), R.raw.icon_add, app.scaleByDensity(32)));
params = icon2.getLayoutParams();
params.width = getResources().getDisplayMetrics().widthPixels / 4;
params.height = (int) (48 * getResources().getDisplayMetrics().density);
params = icon3.getLayoutParams();
params.width = getResources().getDisplayMetrics().widthPixels / 4;
params.height = (int) (48 * getResources().getDisplayMetrics().density);
params = icon4.getLayoutParams();
params.width = getResources().getDisplayMetrics().widthPixels / 4;
params.height = (int) (48 * getResources().getDisplayMetrics().density);
if (!firstLoad) {
setBottomActionBarActive();
setActiveTab(0);
}
optionsLoaded = true;
return true;
}
initializeActionBar() is called from onCreate in my activity. Any ideas what I'm doing wrong?
Toolbar should be used. In your case it's one toolbar at the top, and one at the bottom. Check android team blog, they have nice integration guide.
If you just want your bottom action bar back, you can simply change back to appcompat v7:20 ,and it works for me. The problem is split action bar is no longer being supported in appcomat v7:21.
While user482277's solution may work for instances with a more traditional split action bar, utilizing action items, navigation drawer, etc, it didn't quite work for me. What I ended up doing was building a pair of custom (compound really) views to emulate both the top and bottom action bar. I found this situation to work much better, especially with backwards compatibility. I don't have to worry about earlier versions supporting action bar, because at the end of the day, it's just a pair of classes that extend LinearLayout. In addition, I don't have to worry about different screen sizes (particularly tablets) not supporting the split version.

PopupWindow above status bar of Nexus 7 (and status bars of other devices)

I have a PopupWindow which opens after I click an ImageButton:
// Get the [x, y]-location of the ImageButton
int[] loc = new int[2];
myImageButton.getLocationOnScreen(loc);
// Inflate the tag_popup.xml
LinearLayout viewGroup = (LinearLayout)findViewById(R.id.tagPopupLayout);
LayoutInflater layoutInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final View layout = layoutInflater.inflate(R.layout.tag_popup, viewGroup);
// Create the PopupWindow
myPopupWindow = new PopupWindow(ChecklistActivity.this);
myPopupWindow.setContentView(layout);
myPopupWindow.setWindowLayoutMode(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
myPopupWindow.setFocusable(true);
myPopupWindow.setOutsideTouchable(false);
// Clear the default translucent background and use a white background instead
myPopupWindow.setBackgroundDrawable(new ColorDrawable(android.graphics.Color.WHITE));
// Set the content of the TextViews, EditTexts and Buttons of the PopupWindow
setPopupContent(...);
// Displaying the Pop-up at the specified location
myPopupWindow.showAtLocation(layout, Gravity.NO_GRAVITY, 0, loc[1]);
because of the Gravity.NO_GRAVITY, the PopupWindow will be displayed within the borders of the Window. Everything works as intended on my Emulator, but when I run it on my Nexus 7 Tablet, it is partly covered by the Device's bottom status bar.
How can I fix this? Should I somehow get the current PopupWindow's location after the Gravity.NO_GRAVITY took place, then change the y-location to add the Device's Statusbar's height, and then re-draw it? (Will try this, but I think that having the right location to start with instead of re-drawing it is a better solution..)
This is what I came up with:
What we have:
The [x, y]-position we gave to the PopupWindow's showAtLocation-method (we only need the y-position in this, which I named oldY)
What we calculate:
The Popup height
The Status Bar height
The max possible height to be within Window boundaries (screenHeight - statusBarHeight - popupHeight)
What we then check:
We check if the oldY is larger than the maxY
If this is the case, the newY will be the maxY and we re-draw the PopupWindow. If this isn't the case it means we do nothing and just use the oldY as the correct Y-postition.
NOTE 1: I made the code for this, but during debugging it turned out the Status Bar's Height is 0 on both my Emulator and my Nexus Tablet, so just using the screenHeight - popupHeight was enough for me. Still, I included the code to calculate the Bottom Status Bar Height with a boolean in my Config-file to enable/disable this, in case the app is installed on another tablet in the future.
Here it is in code, I just added the description above to make it clear which approach I used to tackle this problem:
// Get the [x, y]-location of the ImageButton
int[] loc = new int[2];
myImageButton.getLocationOnScreen(loc);
// Inflate the popup.xml
LinearLayout viewGroup = (LinearLayout)findViewById(R.id.popup_layout);
LayoutInflater layoutInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final View layout = layoutInflater.inflate(R.layout.popup, viewGroup);
// Create the PopupWindow
myPopupWindow = new PopupWindow(ChecklistActivity.this);
myPopupWindow.setContentView(layout);
myPopupWindow.setWindowLayoutMode(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
... // Some more stuff with the PopupWindow's content
// Clear the default translucent background and use a white background instead
myPopupWindow.setBackgroundDrawable(new ColorDrawable(android.graphics.Color.WHITE));
// Displaying the Pop-up at the specified location
myPopupWindow.showAtLocation(layout, Gravity.NO_GRAVITY, 0, loc[1]);
// Because the PopupWindow is displayed below the Status Bar on some Device's,
// we recalculate it's height:
// Wait until the PopupWindow is done loading by using an OnGlobalLayoutListener:
final int[] finalLoc = loc;
if(layout.getViewTreeObserver().isAlive()){
layout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
// This will be called once the layout is finished, prior to displaying it
// So we can change the y-position of the PopupWindow just before that
#Override
public void onGlobalLayout() {
// Get the PopupWindow's height
int popupHeight = layout.getHeight();
// Get the Status Bar's height
int statusBarHeight = 0;
// Enable/Disable this in the Config-file
// This isn't needed for the Emulator, nor the Nexus 7 tablet
// Since the calculated Status Bar Height is 0 with both of them
// and the PopupWindow is displayed at its correct position
if(D.WITH_STATUS_BAR_CHECK){
// Check whether the Status bar is at the top or bottom
Rect r = new Rect();
Window w = ChecklistActivity.this.getWindow();
w.getDecorView().getWindowVisibleDisplayFrame(r);
int barHeightCheck = r.top;
// If the barHeightCheck is 0, it means our Status Bar is
// displayed at the bottom and we need to get it's height
// (If the Status Bar is displayed at the top, we use 0 as Status Bar Height)
if(barHeightCheck == 0){
int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0)
statusBarHeight = getResources().getDimensionPixelSize(resourceId);
}
}
// Get the Screen's height:
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
int screenHeight = dm.heightPixels;
// Get the old Y-position
int oldY = finalLoc[1];
// Get the max Y-position to be within Window boundaries
int maxY = screenHeight - statusBarHeight - popupHeight;
// Check if the old Y-position is outside the Window boundary
if(oldY > maxY){
// If it is, use the max Y-position as new Y-position,
// and re-draw the PopupWindow
myPopupWindow.dismiss();
myPopupWindow.showAtLocation(layout, Gravity.NO_GRAVITY, 0, maxY);
}
// Since we don't want onGlobalLayout to continue forever, we remove the Listener here again
layout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
}
NOTE 2: I've set the tag_popup itself to width = match_parent; height = wrap_content on this line:
myPopupWindow.setWindowLayoutMode(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
and the main layout of this Popup to width = match_parent; height = match_parent:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xml>
<!-- The DOCTYPE above is added to get rid of the following warning:
"No grammar constraints (DTD or XML schema) detected for the document." -->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/popup_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#layout/tag_shape"
android:padding="#dimen/default_margin">
... <!-- Popup's Content (EditTexts, Spinner, TextViews, Button, etc.) -->
</RelativeLayout>
NOTE 3: My app is forced to stay in Portrait mode. I haven't test this in Landscape mode, but I assume some modifications should be made (not sure though). EDIT: Tested and it also works in Landscape mode on my two devices. I don't know if this also works in Landscape Mode with the Bottom Bar Height enabled.
Took me some time, but it works now. Hopefully they will fix PopupWindow's Gravity in the future, so it will never be below a Status bar, unless the programmer wants this themselves and change the PopupWindow's settings. Makes things a lot easier..

How to change the width of action bar tab in Android?

I have searched more than 100 links but haven't found any working answer to the question.
I need to create variable number of tabs depending on the number of tabs I receive from previous activity. The tabs I get can have a length from 3 characters (All) to 24 characters. I am using the attached code for creating the tabs.
final ActionBar actionBar = getActionBar();
actionBar.setDisplayShowHomeEnabled(false);
actionBar.setDisplayShowTitleEnabled(false);
actionBar.setDisplayHomeAsUpEnabled(false);
actionBar.setDisplayShowCustomEnabled(true);
actionBar.setCustomView(actionBarLayout);
actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
final int actionBarColor = getResources().getColor(R.color.green);
actionBar.setBackgroundDrawable(new ColorDrawable(actionBarColor));
for(int k = 0; k < tabs.length; k++) {
TextView t = new TextView(browse_sub_category);
t.setText(tabs[k]);
t.setTextSize(18);
t.setGravity(Gravity.CENTER);
t.setSingleLine();
t.setPadding(0, 20, 0, 0);
t.setTypeface(myTypefaceLight);
t.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
actionBar.addTab(
actionBar.newTab()
.setCustomView(t)
.setTabListener(browse_sub_category));
}
actionBar.setHomeButtonEnabled(false);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
By using the setCustomView, I can customize the textview but that doesn't impact the width of my tab. It is taking the default width. I want that if my tab name say 'All' require only 40dp to fit in then it should take only 40dp and if my tab name say 'Hello World' require 120dp then the tab should automatically take that width.
I have already tried customizing the textview by changing the width from LayoutParams.WRAP_CONTENT to numeric values. I have also tried to put a check like
if(tabs[k].length() <= 3) {
tabWidth=40;
} else if((tabs[k].length() > 3) && (tabs[k].length() <= 6) {
tabWidth=80;
} else {
tabWidth=120;
}
but this impacts only the width textview not the width of tab.
I can set the maximum and minimum width of tab in styles.xml but that doesn't provide me the freedom to customize tab width based on tab name.
Any help would be really appreciated.

Categories

Resources