Action Bar Tabs CustomView too long - android

After finally getting each CustomView to wrap the Tab parent completely, I ran into a problem where the Tabs are too long and are turning the Action Bar into a slider. My drawables have widths of 150px , which should be fine because I tested the width in px of the Samsung Galaxy S2 screen and got 480px (480/3 tabs = 160px each).
Screenshot:
Set-up: Each Tab is set by the same RelativeLayout that has different drawawble resources attached to the layout. That layout is then passed to setCustomView() of the Tab. I don't think there is a need for an ImageView for each Tab, unless that would fix my problem. Some Style config changes such as removing left and right padding of the TabView have been made in order to place the custom views over the Tab.
Code (not using ImageView, setting drawable resource on RelativeLayout)
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="56dp"
android:layout_margin="0dp"
android:paddingBottom="2dp" >
<!-- <ImageView
android:id="#+id/ivCustomTab"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="2dp"
android:contentDescription="#string/tabsDescription"
android:duplicateParentState="true" /> -->
</RelativeLayout>
//setting up tabs + custom views on tabs
LayoutInflater inflater = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
RelativeLayout discoverTabLayout = (RelativeLayout) inflater.inflate(R.layout.actionbar_tabs, null);
RelativeLayout tagsTabLayout = (RelativeLayout) inflater.inflate(R.layout.actionbar_tabs, null);
RelativeLayout badgeTabLayout = (RelativeLayout) inflater.inflate(R.layout.actionbar_tabs, null);
//ImageView customTabImg = (ImageView) customTabLayout.findViewById(R.id.ivCustomTab); //re-setting this ImageView for each tab
ActionBar.Tab discoverTab = actionBar.newTab();//.setText("Discover").setIcon(R.drawable.selector_tabicon_discover);//.setCustomView(drawable.selector_tab_discover);
//customTabImg.setImageResource(R.drawable.selector_tab_discover);
discoverTabLayout.setBackgroundResource(R.drawable.selector_tab_discover);
discoverTab.setCustomView(discoverTabLayout);
<!-- Application theme. -->
<style name="Theme.AppTheme" parent="AppBaseTheme">
<!-- All customizations that are NOT specific to a particular API-level can go here. -->
<item name="android:textSize">18sp</item>
<item name="actionBarTabStyle">#style/Theme.TabsNoPadding</item>
<item name="android:actionBarTabStyle">#style/Theme.TabsNoPadding</item>
</style>
<style name="Theme.TabsNoPadding" parent="#style/Widget.Sherlock.ActionBar.TabView">
<item name="android:paddingLeft">0dp</item>
<item name="android:paddingRight">0dp</item>
<item name="android:minWidth">0dp</item>
</style>
What I've tried:
Adding android:layout_width="120dp" to RelativeLayout to shorten the Tabs, but the width stayed the same.
Re-sized the images and reduced a total length of 45px, no change. And if I set them too small they won't cover the tab host.
I've also noticed that the tabs customView(s) disappear onCreate() most of the time. Not sure if that has anything to do with the rendering off the tab scroll layout that I don't want.
I can post my Main Activity code if needed.

I would suggest to think in dp(Density-independent pixel) instead of px(pixels) when working in Android.
If you want a custom tabbar I would suggest to simply create a LinearLayout with a width being set to match_parent and a height by your choice (for ex. 48dp). The orientation would be set to horizontal.
Inside the LinearLayout create as many ImageView or View as many tab you want and set the width to 0dp, height to match_parent and most importantly weight to 1 (without dp or any other unit) for each View inside the LinearLayout. This way the tabs will have the same width and they will remain inside the boundaries of the screen.
Hope this helps.

Related

android-add top padding to Chip text

I'm using Chip component from material library in my android app. It is an action chip which has an icon and a text inside. the point is that I need to add some padding to the top of the text in order to bring it down a little a bit.
I have tried to add textAppearance style to the chip, but can not find any style item to do what i need. how to do that?!
<com.google.android.material.chip.Chip
android:id="#+id/chip"
android:layout_width="wrap_content"
app:chipIcon="#drawable/satisfied"
app:chipIconTint="#444"
android:layout_height="wrap_content"
android:text="my text!"
android:textAppearance="#style/Widget.App.Chip" />
<style name="Widget.App.Chip" parent="Widget.MaterialComponents.Chip.Action">
<item name="android:textSize">14dp</item>
<item name="android:fontFamily">#font/xyz</item>
<item name="android:textStyle">bold</item>
// what item is needed to achieve top padding?!
</style>
simply: you can't. Chip is designed as is and it extends AppCompatCheckBox and further TextView (doc HERE). so these icons on the left and/or right are compound drawables, not separated Views (e.g. ImageViews), so every padding you will set to Chip will add padding to text and all icons (as this is one View). for your purposes you must create own custom View, easiest way would be probably to create horizontal LinearLayout with childs: TextView and ImageViews on left and right to it, and then you can set additional padding only for text

Are the layout bounds of a layer-list windowBackground different than an inflated layout?

On an app I'm working on, we have a splash screen consisting of a RelativeLayout and a logo in the center (and some other stuff, like a loading spinner, etc):
fragment_splash_image.xml:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:background="#drawable/loading_screen_bg"
... >
<ImageView
android:id="#+id/universal_loading_logo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="#drawable/logo_large"
... />
... other stuff ...
</RelativeLayout>
To make sure there wasn't just a brief blank screen before our splash screen, we have a SplashTheme in styles.xml for the activity. Its android:windowBackground is just a layer-list with the logo in the center again, with the hopes that the logo would appear to stay in the middle of the screen while the other things in fragment_splash_image appear as well.
splash_placeholder.xml:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" android:opacity="opaque">
<item android:drawable="#drawable/loading_screen_gradient"/>
<item>
<bitmap
android:gravity="center"
android:src="#drawable/logo_large"/>
</item>
</layer-list>
Notice that #drawable/logo_large is the same logo in each, and centered on the screen in each. The intended behavior is that it shouldn't appear to move at all.
Anyway, fragment_splash_image is inflated in a class that extends from FrameLayout, in this method:
private void inflateContent() {
final View splashImageFragment = LayoutInflater.from(getContext()).inflate(R.layout.fragment_splash_image, this, true);
final ImageView brandLogo = (ImageView) splashImageFragment.findViewById(R.id.universal_loading_logo);
final int statusBarHeight = ScreenUtils.getStatusBarHeight(getResources());
final int navBarHeight = !ScreenUtils.hasSoftNavBar() ? 0 : ScreenUtils.getNavigationBarHeight(getResources());
brandLogo.setPadding(0, 0, 0, statusBarHeight - navBarHeight);
}
Now, what's going on in there is that originally, we just inflated the fragment as-is. Unfortunately, this causes the logo in the splash fragment to jump up or down a small distance compared to the splash placeholder's logo, depending on the device tested on. On my Galaxy S6 phone, I figured that perhaps the placeholder splash screen included the status bar height, so I added it as padding to the bottom of the logo. Problem solved for that device. However, on a Nexus 7 which has a soft navigation bar, the logo still jumped very far up. I concluded that maybe it was also including the navbar height in the layout bounds, and wrote what you see above: bottom padding = statusBarHeight - navBarHeight, where navBarHeight is 0 for devices with hard navigation buttons.
This works for both devices...and then I tested on a Google Pixel. The logo jumps down. This only works on the Pixel if I set the bottom padding to 0, and the top padding to the status bar height.
I'm stumped. What the heck is determining the height of both layouts here? They are clearly different and I'm not sure how to ensure that the logo does not jump from one screen to the next on any devices. Thanks in advance!
Adding <item name="android:windowDrawsSystemBarBackgrounds">false</item> on API 21+ may allow you to keep the same formula for all devices.
I am facing a similar issue, and thinking about going this route.
Sajal's answer is the way forward.
In your styles.xml file, add a theme for your splashscreen, such as:
<style name="SplashTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:windowBackground">#drawable/background_splash</item>
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
</style>
Where #drawable/background_splash is your splashscreen <layer-list> definition. This will ensure that the splashscreen doesn't sit underneath the status bar/navigation bar.

EditText shows the status bar, or causes content above to move instead of resize

Background
I have a login Activity , which has a layout as such (vertically, from top to bottom) :
title (logo ImageView and TextView)
image&viewPager that takes the rest of the screen
EditTexts&login button, appear on top of #2 (covering a part of them), but at the bottom of the screen
I need to have this activity full screen, hiding the status bar, and when the soft keyboard appears, change the layout a bit for what's shown above #3 .
The problem
It seems that the combination of those requirements are quite problematic.
I have 2 main issues with them:
What I've made for sensing the soft-keyboard being shown- doesn't seem to work here even though it worked fine on other Activities.
When the soft-keyboard appears, it either re-shows the status bar, or it moves the content above the bottom area (#3) instead of resizing it, while also hiding the button at the bottom (of #3) and showing only the EditText as the first view above the soft-keyboard.
Since there is no way to really have a listener for when the soft-keyboard is shown/hidden, I had to create a customized layout that just tells me when its size has changed. When its height is reduced, I assume the keyboard is shown, and vice versa.
What I've tried
I've tried multiple variants of the layout. Doesn't seem to help
I've used this layout as the root of the fragment, to check if the soft-keyboard is shown (as it changes its size) :
https://stackoverflow.com/a/25895869/878126
Sadly, it works on all other activities except for this one.
I've tried various "windowSoftInputMode" values, including "adjustResize" and "adjustPan"
I thought the issues were because I use a transparent navigation bar, so I've disabled it and also disabled "fitsSystemWindows" for the bottom area (#3) .
I've tried this way to hide the status bar:
requestWindowFeature(Window.FEATURE_NO_TITLE);
and also this way:
if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) {
View decorView = getWindow().getDecorView();
int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN;
decorView.setSystemUiVisibility(uiOptions);
} else
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
The current layout
here's a short description of the current layout:
<LayoutSizeChangedSensorFrameLayout>
<RelativeLayout>
#1
<LinearLayout vertical, aligned to parent-top>
<ImageView/>
<TextView/>
<CirclePageIndicator/>
</LinearLayout>
#2
<ImageView aligned to parent-bottom, and below #1 />
<ViewPager aligned to the ImageView from all sides/>
#3
<LinearLayout vertical, aligned to the parent-bottom>
<TextView/>
<EditText/>
<Button/>
</LinearLayout>
</RelativeLayout>
</LayoutSizeChangedSensorFrameLayout>
And this is the theme of the activity:
<style name="AppTheme.Material" parent="#style/Theme.AppCompat.Light.DarkActionBar">
...
<item name="windowActionBar">false</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<item name="android:windowTranslucentNavigation" tools:ignore="NewApi">true</item>
<item name="android:windowTranslucentStatus" tools:ignore="NewApi">true</item>
<item name="android:navigationBarColor" tools:ignore="NewApi">#android:color/transparent</item>
</style>
The question
How come hiding the status bar doesn't work permanantly, or it affects what's shown when showing the soft-keyboard ?
How come my customized layout can't sense that the soft-keyboard is shown?
Are there any other ways to achieve what I've tried?
I managed to keep the status bar hidden when the soft keyboard shows, by doing the following 2 steps:
Adding the following in the onCreate of the activity:
//No title bar is set for the activity
requestWindowFeature(Window.FEATURE_NO_TITLE);
//Full screen is set for the Window
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
Setting windowFullscreento truein the theme:
<style name="CustomTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:windowFullscreen">true</item>
</style>
Unfortunately this is not a complete answer, but it might help you get some of the way.
In addition to adding FLAG_FULLSCREEN to window,
FLAG_FORCE_NOT_FULLSCREEN - this flag can also be cleared:
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);

Android Navigation Drawer and windowActionBarOverlay = true

I'm trying to implement the new Android Navigation Drawer in my application. I have created a BaseActivity.java that handles the Drawer setup and listeners, and I have two subactivities that extend this base class. On the second activity, I plan to use a different action bar style, using the following attrs:
<item name="android:windowActionBarOverlay">true</item>
<item name="android:background">#android:color/transparent</item>
to make the action bar transparent, and make content richer, as there is a picture header in my layout.
I've achieved just that, but now the problem is, that because the content is expanding to take advantage of the extra space of using the ActionBar as overlay, the Navigation Drawer itself is expanding too and it overlaps the ActionBar, creating a pretty awful looking layout:
What I'd like to have done, is the actual content (frame layout that will be populated with a fragment) to take up the extra space, but have the nav drawer still go underneath the action bar, similar to the Play Music App:
Any ideas on what I can do to make that happen?
EDIT So, as per Ahmad's assistance I set the marginTop on the ListView only. Here's the layout:
<!-- The navigation drawer -->
<ListView android:id="#+id/left_drawer"
android:layout_marginTop="?android:attr/actionBarSize"
<!-- This was added after seeing the crazy effect, but does nothing -->
android:layout_marginBottom="0dp"
android:layout_marginLeft="0dp"
android:layout_marginRight="0dp"
android:layout_width="240dp"
android:layout_height="fill_parent"
android:layout_gravity="start"
android:choiceMode="singleChoice"
android:background="?attr/listviewBackground"
/>
And now, it works great for the top side, but for some reason there's also a margin at the bottom of the view, which doesn't make any sense to me at all. Here's a screenshot.
Not sure what's causing it :(
And now, it works great for the top side, but for some reason there's also a margin at the bottom of the view, which doesn't make any sense to me at all. Here's a screenshot.
If you set your ListView gravity to start|bottom it solves your problem. No additional margin is added at the bottom. Looks like the DrawerLayout default gravity is start|center
<ListView
android:id="#+id/left_drawer"
android:layout_marginTop="?android:attr/actionBarSize"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start|bottom"/>
In case anyone is interested in another take to this question. Here's what happened.
I tried setting only the margin to the top of the list view like this:
android:layout_marginTop="?android:attr/actionBarSize"
But as mentioned on the edited question, that had a weird behaviour where there was also a margin on the bottom despite not being set on the layout resource file.
So, I was looking closely at the Play Music App and noticed that it's not actually a margin, but rather some padding, and additionally they are using a custom background that fills the space specified by the padding with a transparent color.
Here's what I did:
Set Padding at the top of the ListView, rather than margin:
android:paddingTop="?android:attr/actionBarSize"
As said before, it's important to not hard code the dimensions as they vary per device.
Create a custom drawable that has a top part transparent, and then rest of a solid color:
It looks somehow like this:
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item>
<shape android:shape="rectangle">
<solid android:color="#80000000" />
</shape>
</item>
<item android:top="#dimen/action_bar_default_height">
<shape
android:shape="rectangle">
<solid android:color="#color/light_gray" />
</shape>
</item>
Note that I tried to use ?android:attr/actionBarSize on the drawable, but that made the app force close. Instead, I searched through grepcode and found a few dimen files with different sizes for the action bar, so I added those to my own project's dimen files.
For values: 48dp
For values-land: 40dp
For values-sw600dp: 56dp
And after that, I think I looks great, notice on the screenshot how the listview and the actionbar don't overlap, and the transparent part of the listview is just the right size.
Hope that helps anyone who was wondering how to achieve this.
You can set a margin at the top of your layout, so that the content draws itself below the ActionBar.
Just add this in your parent layout:
android:layout_marginTop="?android:attr/actionBarSize"
The attribute actionBarSize refers to, like you would have already guessed, to the size of the ActionBar. You can't set an absolute value as a margin, since the ActionBar does not always have the same size across all Android devices (It's bigger on tablets, smaller on handset devices).
Edit:
Set the margin to the ListView.
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ListView
android:id="#+id/left_drawer"
android:layout_marginTop="?android:attr/actionBarSize"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"/>
</android.support.v4.widget.DrawerLayout>
The Google Music app does the same:
I solved this problem using paddingTop:
<FrameLayout
android:id="#+id/menu_frame"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:paddingTop="?attr/actionBarSize" >
<ListView
android:id="#+id/left_drawer_list"
android:layout_width="240dp"
android:layout_height="match_parent" />
</FrameLayout>
Hope that helps
I have created a working demo following the above guide and tested on 2.x to 5.x
You can clone from Github
The important thing to play around is in Main Activity
toolbar = (Toolbar) findViewById(R.id.toolbar);
res = this.getResources();
this.setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setHomeButtonEnabled(true);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
{
ScrimInsetsFrameLayout scrimInsetsFrameLayout = (ScrimInsetsFrameLayout)
findViewById(R.id.linearLayout);
scrimInsetsFrameLayout.setOnInsetsCallback(this);
}
and the call back
#Override
public void onInsetsChanged(Rect insets) {
Toolbar toolbar = this.toolbar;
ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams)
toolbar.getLayoutParams();
lp.topMargin = insets.top;
int top = insets.top;
insets.top += toolbar.getHeight();
toolbar.setLayoutParams(lp);
insets.top = top; // revert
}
Absolutely the Theme for V21 does the magic
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- API 21 theme customizations can go here. -->
<item name="colorPrimary">#color/colorPrimary</item>
<item name="colorPrimaryDark">#color/colorPrimaryDark</item>
<item name="colorAccent">#color/accent_material_light</item>
<item name="windowActionModeOverlay">true</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:statusBarColor">#android:color/transparent</item>
<item name="android:windowTranslucentStatus">true</item>
</style>

Android UI widget vertical alignment issue

I am trying to create a layout (using eclipse) in which I need to vertically align various controls like TextView and Button. I am trying to keep all the widgets perfectly left aligned. Even if I specify the same left margins/paddings for the controls, still a difference of 1-2 pixels can be seen between different types of controls.
The problem is that the distance between widget’s border (blue rectangle in eclipse) and widget’s content/graphics varies across widgets (say TextView and Button).
I can apply workarounds by either specifying left padding for TextView or by reducing the left margin of the button container. But I am looking for cleaner solution. I am unable to find any attribute which controls the difference between widget's border and content.
Any pointers on how I can control this gap ?
Snapshot demonstrating the problem is below. Here is the layout XML that I am using for this problem:-
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World" />
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Dummy Button" />
</LinearLayout>
The images below show the snapshot of the dummy application. Please note the difference between left side margin of "Hello World" TextView and "Dummy Button".
The second pic shows the button widget when selected in Eclipse. The blue rectangle indicates the widget boundary/border. Is the difference between button's border (blue rectangle) and content (greyed rectangle) controllable by some property ?
This is a tough one the TextView and other Android widgets may have some intrinsic styles of their own (android version dependant as well).
Therefore to get around this you would have to create your own style.
In creating your own style always reference the android source code on this subject:
https://github.com/android/platform_frameworks_base/tree/master/core/res/res/values
https://github.com/android/platform_frameworks_base/blob/master/core/res/res/values/themes.xml
https://github.com/android/platform_frameworks_base/blob/master/core/res/res/values/styles.xml
There are multiple ways to create your own style.
One way is to theme your activity in your manifest.
First you need a styles.xml file, in your /values/ folder.
In here you would declare your new style:
<style name="Theme.MyTheme.Dark" parent="#android:style/Theme.NoTitleBar">
<item name="android:textViewStyle">#style/Widget.TextView.Black</item>
</style>
<style name="Theme.MyTheme.Light" parent="#android:style/Theme.NoTitleBar">
<item name="android:textViewStyle">#style/Widget.TextView.White</item>
</style>
The style above it inheriting from the Android style that hides the title bar, you can inherit from something else.
In this theme we then override the textViewStyle, this allows us to set custom values for our TextView's and override some of the intrinsic values.
<style name="Widget.TextView.White" parent="#android:style/Widget.TextView">
<item name="android:textColor">#FFFFFF</item>
</style>
<style name="Widget.TextView.Black" parent="#android:style/Widget.TextView">
<item name="android:textColor">#000000</item>
</style>
Finally you theme your activity in the AndroidManifest.xml:
<activity
android:name=".ui.phone.FirstActivity"
android:theme="#style/Theme.MyTheme.Dark" />
<activity
android:name=".ui.phone.SecondActivity"
android:theme="#style/Theme.MyTheme.Light" />
Now when you use a TextView in the FirstActivity it's text will be Black by default and in the second activity it will be white.
For your specific question:
You would have to go look in the source code files I linked at the top and see if there is any padding or minWidth or size attributes that are affecting your widgets and your layout.

Categories

Resources