Showing posts with label style. Show all posts
Showing posts with label style. Show all posts

04 August 2016

Stylish Dynamic Layouts

One of the things we are taught in Android is that we should gracefully handle different layouts based on screen sizes. With more and more things being not just screen size-specific but also OS version-specific, this is one thing I think a lot more devs need to pay attention to. Today was my turn to do just that.

I wanted to create a dialog with an image that resizes itself while maintaining aspect ratio but being constrained by the container. Okay.

So I went about creating my ImageView:
<ImageView
android:id="@+id/permission_image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="200dp"
android:adjustViewBounds="true"
android:scaleType="centerCrop"
android:src="@{ContextCompat.getDrawable(context, permission.descriptionDrawable)}"/>

Loaded up the layout and it looks satisfactory:

But then, I tried rotating and what the hell!

The image does not fit, you cannot see "NOT NOW". It doesn't work. Then I tried it on a tablet:

OMG how could it possibly get worse. There is so much space and it's not filling it up properly! I am pretty sure the root layout has layout_height="wrap_content". Weird.

After some furious Googling, I found out that I have to set the LayoutParams on the dialog after it has been shown. Why do I have to do that? I said wrap it and you refuse and now you want me to do it myself? Why?

I gave in and did the thing that StackOverflow tells me to. But it didn't work. It still looked the same. I tried moving stuff around; calling setLayout instead of setAttributes. It still looked the same. :sad_panda:

And so the time has come to look for another approach. A couple of things need to happen:
a. We shouldn't make the user scroll just to click the buttons on a landscape phone
b. Make the image take up more space on tablets

To make (a) happen, we either: create a new layout for this orientation or just set the image to be invisible. The second option is more appealing for me. There really is not much difference in the two orientations aside from the image after all. We can set the visibility of the image at runtime, but then maybe we can afford to show the image if there is enough space for it.

This means that to make (b) happen, maybe we need to tweak our layout a little. And this is where the beauty of Android's alternative resources come in. To be as less repetitive as possible, I chose to harness styles too, since I only need to override one attribute -- the visibility.

First I created a style in the default /res/values folder that I would apply to the image:
<style name="DescriptionImage">
   <item name="android:visibility">gone</item>
</style>

Now it's time to make the variations. We want to hide the image if we are in landscape, so into /res/values-land this style goes:
<style name="DescriptionImage">
   <item name="android:visibility">gone</item>
</style>

But we want to show it if there is enough space, so into /res/values-h500dp this style goes:
<style name="DescriptionImage">
   <item name="android:visibility">visible</item>
</style>

And now it's just a matter of applying this style to our image (and I found out that setting maxHeight works a bit better):
<ImageView
android:id="@+id/permission_image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxHeight="200dp"
android:adjustViewBounds="true"
android:scaleType="centerCrop"
style="@style/DescriptionImage"
android:src="@{ContextCompat.getDrawable(context, permission.descriptionDrawable)}"/>

I applied this technique to another dialog and here's the end result on a phone:


Yay!

28 December 2012

Styling tab selectors for ActionBarSherlock

This post builds on the previous post for ABS + VPI.

I have gotten a lot of questions on styling the ABS, specifically the tab selected indicators. This task may seem daunting, but in reality it is relatively simple. I am also quite confused why I didn't find any straightforward tutorials when I tried googling this. Anyway, this post will hopefully help developers who aim to style their action bars.

We will need to use Jeff Gilfelt's awesome styling tool. To use it, just input in your app's color scheme for the highlights and what-not then download the generated zip file. If you want to just change the tab underline color, change the value under "Accent color". To make the change obvious from the default settings, I have used a shade of orange for the tab selected indicators. Here are the settings I used for this demo.

Jeff's tool conveniently generates all the XML files and drawables and organizes them into the correct /res/drawable folders. Unzip the file and just drag the generated files into your project, or merge the contents if you already have such existing files.

See how easy it was? Seriously, we should all lie prostrate at Jeff Gilfelt's and Jake Wharton's feet. These guys are AWESOME.

The two photos below show the difference between the old app and the styled app. As you can see, I only changed the tab selected color. You can explore what happens if you use the other styles you can get from Jeff's tool.
DefaultStyled
The hard work is done, let's now try to understand the automagically generated configurations we did.

First, we have to configure the theme to use custom tab indicators. We do this by changing the tab styles in themes.xml. In my sample app, these lines customize the tabs we are using.
<!-- Styling the tabs -->
<style name="CustomTabPageIndicator" parent="Widget.TabPageIndicator">
   <!-- Tab text -->
   <item name="android:textSize">15dip</item>
   <item name="android:textColor">#FFB33E3E</item>
        
   <!--  Lines under tabs -->
   <item name="background">@drawable/tab_indicator_ab_styling_abs</item>
   <item name="android:background">@drawable/tab_indicator_ab_styling_abs</item>
</style>

The "drawable" tab_indicator_ab_styling_abs is actually a state list drawable that provides different images for each state of a tab -- focused and non-focused, pressed and not pressed.

You can see part of this in action in the image above. Try long pressing on a tab and you can see the tab's background change to use the unselected-pressed drawable.

Again, HUGE thanks to Jeff Gilfelt and Jake Wharton for creating tools that make our lives easier. :)

I have pushed a new branch in github that uses this style. The master branch of that repo still uses the default tab selectors.