Android Themes: A dialog without a title


Most of the times, I have seen developers not leveraging the power of themes and styles. Themes and styles are a great way to easily create UI that are  manageable and compatible for various platforms. Here’s the official documentation that explains styles and themes in details, and I consider this portion of documentation to be equally important to any developer working with Android.

For the example of this post, we will see how to make a dialog, a custom dialog, not to have a title. The easiest way to do this, is through code byt writing this snippet in your custom dialog class.

requestWindowFeature(Window.FEATURE_NO_TITLE);

Dialog with Title on Android 2.2


Dialog with no title on Android 2.2

While this would work anyway, and would also be compatible with all the versions of Android. But, it’s a good idea to use more of your themes and styles in your programming, so that your code base is maintainable and your apps would behave and feel consistently. Using styles and themes makes it very easy to tweak or adapt to various platform versions and/or device sizes and resolutions. So, let’s get in.

The application tag, has a configurable attribute called “android:theme” with which you can set a theme to your application as a whole. You can also specify themes for individual themes for all your activities separately. Sounds nice!!! But, let’s stick to one theme for our application as a whole for simplicity.

For this example, we have a theme (it’s actually called a style), called MyThemeSelector as shown below. This is specified in the styles.xml in your values folder. Notice, your custom theme is a child of the Theme, which is one of the system’s default themes.

<resources>        <style name=”MyThemeSelector” parent=”@android:style/Theme”></style></resources>

Ideally, you should also declare your custom theme to extend one of the basic themes that are available with platforms on or above Honeycomb. For example, here we have created another styles.xml in a folder called values-v11, which looks like this.

<resources>
        <style name=”MyThemeSelector” parent=”@android:style/Theme.DeviceDefault.Light”></style>
</resources>

So, your basic theme is now compatible with both older versions and versions greater than Honeycomb. By this, I mean, that, when you run the app, your app would adapt to the platform that it is running on, and would give a consistent look and feel for your users.

Now, coming back to the main problem. “Creating a dialog without title”. Here also, we would use themes, as against code. Here are the two new themes that you would be declaring.

For values folder: (Platform versions older than Honeycomb)

<style name=”My.Theme.Dialog” parent=”@android:style/Theme.Dialog”>
            <item name=”android:windowNoTitle”>true</item>
</style>
<style name=”MyThemedDialog” parent=”@style/My.Theme.Dialog”></style>

For values-v11 folder: (Platform version for Honeycomb and above)

<style name=”My.Dialog.Theme” parent=”@android:style/Theme.DeviceDefault.Light.Dialog.NoActionBar”></style>
<style name=”MyThemedDialog” parent=”@style/My.Dialog.Theme”></style>

There’s a subtle difference between the two versions. Of course, other than the parent classes. In older platform versions, there wasn’t a version of the Dialog theme without a title bar. So, what we do here, is to extend the basic Dialog them, and overwrite an attribute, so that our custom “My.Theme.Dialog” is a dialog without a title bar.

But, for Honeycomb and above, the platform itself provides a version of the Dialog theme, without the title bar (or the Action Bar).

And finally, the last step for getting everything to work is set the theme to your dialogs.

MyDialog dialog = new MyDialog(this, R.style.MyThemedDialog);
dialog.setTitle(“Here’s my title”);
dialog.show(); 

Why didn’t we use “My.Theme.Dialog” directly? Well, we could still try and tweak the theme for older versions, in the values folder, by adding a few more attributes.

Dialog with title on Android 4.1


Dialog with no title on Android 4.1

As you can see, for both older and newer platforms, the app runs by adapting itself and gives a consistent look and feel. You didn’t have to do much with your code. 
15 lines of XML is the MAGIC here!!!!  (I didn’t count though, just guessing)

Sample project here.

Inverted Android Button

Nothing complex. Just a few lines of code to invert your button. A horizontal flip of 180 degrees is pretty simple to achieve. If you want it with a specific angle, it might be a bit tricky.

Lets start with a creating a custom button class that extends the android Button class. Name it as InvertedButton.java.

You will need to override it’s onDraw() method to rotate the canvas, so that before any drawing is done, you rotate it by 180 degrees. To make the text-alignment perfect, you will also need to do a few calculations.

    @Override
    protected void onDraw(Canvas canvas) {
        int left = getPaddingLeft();
        int top = getPaddingTop();
        int right = getPaddingRight();
        int bottom = getPaddingBottom();
        int width = getWidth() – left – right;
        int height = getHeight() – top – bottom;
       
        int saveCount = canvas.getSaveCount();
        canvas.translate(left + width / 2, top + height / 2);
        canvas.rotate(-180);
        canvas.translate((-width / 2)-left, (-height / 2)-top);
        canvas.restoreToCount(saveCount);
       
        super.onDraw(canvas);

    }

There you go. You can now add this button anywhere in your XML layouts and you will always get an inverted button.

<?xml version=”1.0″ encoding=”utf-8″?>
<LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android”
    android:orientation=”vertical” android:layout_width=”fill_parent”
    android:layout_height=”fill_parent”>
    <Button android:text=”Button” android:id=”@+id/button1″
        android:layout_width=”wrap_content” android:layout_height=”wrap_content”
        android:layout_gravity=”center_horizontal|top” android:textStyle=”bold”></Button>
    <com.beanie.examples.invertedbutton.InvertedButton
        android:text=”Button” android:id=”@+id/button2″ android:layout_width=”wrap_content”
        android:layout_height=”wrap_content” android:layout_gravity=”center_horizontal|bottom”
        android:textStyle=”bold”></com.beanie.examples.invertedbutton.InvertedButton>
</LinearLayout>

You can find the source code here. Happy coding!!!!

Improved Copy/Paste in Gingerbread

It’s really important for the copy/paste feature to work on a mobile even if you don’t have a mouse to select text you want to copy. Apple’s implementation is nice. Till Froyo, there wasn’t a unified concept of copy/paste feature implemented. But, the Gingerbread has actually changed a few things 🙂 . Copying phone numbers from your mails and email addresses from web pages should be trivial and should involve the least amount of button presses. Prior to Gingerbread, this wasn’t the case, but Gingerbread has this “New Feature now”.

Here’s the link where you can find out more about this.

Some images and videos

Official documentation

You need to double-tap on the text before you can bring up the text selection controls. Once you are done with the selection, single tap on the text copies the selected text to the clipboard, and then you can extract the data from the clipboard. This is really nice. Else, you would have to write a bit of extra code to trigger text selection mode first. This copy/paste selector works on an EditText and on the Browser. I haven’t tested it further.

Gingerbread Stuff!!!! **It works on the emulator**.

Getting animations to work

This is a simple project that will explain how to use animations in android through AnimationDrawable. The documentation was a bit outdated. But you might hit a dead-end if you try to call the animation’s start method from within any of the Activity’s life-cycle methods.

In this example, there is an ImageView with it’s “src” value set to an image. The ImageView‘s background is set with you own AnimationDrawable, basically an xml in your res/drawable folder. In the activity, the ImageView has a click listener, which creates an AnimationDrawable from the ImageView’s background, and just calls the start method of the AnimationDrawable class.

Here is a sample AnimationDrawable described through XML.

<?xml version=”1.0″ encoding=”utf-8″?>
<animation-list xmlns:android=”http://schemas.android.com/apk/res/android”
    android:oneshot=”false”>
    <item android:drawable=”@drawable/black” android:duration=”200″ />
    <item android:drawable=”@drawable/cyan” android:duration=”200″ />
    <item android:drawable=”@drawable/green” android:duration=”200″ />
    <item android:drawable=”@drawable/magenta” android:duration=”200″ />
    <item android:drawable=”@drawable/navy” android:duration=”200″ />
    <item android:drawable=”@drawable/orange” android:duration=”200″ />
    <item android:drawable=”@drawable/pink” android:duration=”200″ />
    <item android:drawable=”@drawable/white” android:duration=”200″ />
    <item android:drawable=”@drawable/yellow” android:duration=”200″ />
</animation-list>

And here is the code that gets your animation started.

imageView = (ImageView) findViewById(R.id.ImageButton01);
        imageView.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                AnimationDrawable animator = (AnimationDrawable) imageView.getBackground();
                imageView.setImageDrawable(null);
                animator.start();
            }
        });

One point to notice is that, you have to remove the ImageView’s “src” value, so that the animation is visible, since the animation works by changing the background of the ImageView, else, your animation would be blocked by the ImageView’s “src” image.

Once you are done, you can stop the animation, and reset the ImageView’s “src” to it’s original image.

// Call this method to stop the animation
    public void stopAnimation(){
        AnimationDrawable animator = (AnimationDrawable) imageView.getBackground();
        animator.stop();
        imageView.setImageResource(R.drawable.icon);
    }

 You can find the whole source code for this example here.

ExpandableListView on Android

ListView is pretty widely used. There are situations when you would like to group/categorize your list items. To achieve such a thing on Android, you would probably use the ExpandableListView. The data to the ExpandableListView is supplied by a special kind of adapter called the SimpleExpandableListAdapter which extends the BaseExpandableListAdapter.

As with any other widget on Android, you are free to customize the widgets as per your needs. Here, I will show how to create such a custom list adapter for the ExpandableListView.

For this example, I want to show a list of vehicles with their names. Also, I want to group them according to their category.

I have 4 classes.
1. Vehicle : The parent class for the rest.
2. Car: Extends the Vehicle class.
3. Bus: Extends the Vehicle class.
4. Bike: Extends the Vehicle class.

I have a method called getRandomVehicle(String name) which returns a random vehicle instance setting the name that I pass. The vehicle can be a Bus, Car or a Bike. Its completely random.

In the ExpandableListAdapter, (the custom adapter), there’s a method called addItem(Vehicle vehicle), which manages the groups and their children.

In the SampleActivity, I have initialized a blank ExpandableListAdapter and set it to the list view. Now, I start a thread, which gets a random vehicle after every 2 seconds, and adds it to the adapter, and calls the adapter to notify that the data has changed.

There are a few methods, in the ExpandableListAdapter, which you should go through carefully. I have two layout files, group_layout.xml and child_layout.xml which are used as the layout for the group views and the child views of the ExpandableListView.

There you go, you have a custom ExpandableListView. You can find the full source code for this example here, ready to run.

There are some more methods that you might be interested in, like, how to change the “arrow icon” for the group views(official doc link), or how to expand or collapse a group at will, or how to handle specific events like group collapsed or group expanded. Read the docs on ExpandableListView.