Monday, May 4, 2015

Dart and Android

It's time to learn new language now that the future seems to be Android and Dart. Here is the video


Sunday, March 15, 2015

Extending Components and AppTheme with Material Design

Recently I have been dealing with custom font in the default components of Android. However I need to use different fonts in English and one font in Chinese. As we know integrating custom fonts with the default components shipped out by Android is a bit tricky specially if you have to cater earlier version of the platform. To fix this problem, i need to extend the components first and this StackOverflow post helped with setting up the classes.

Another piece of the puzzle is with making it use the widget tinting that comes with appcompat v21. We need this because without it we need to generate a lot of files (drawable, styles, etc) and maintaining them is not fun. For this, we refer to the appcompat v21 material design for pre lollipop where we just need to put colorAccent, colorControlNormal, colorControlActivated, colorControlHighlight & colorSwitchThumbNormal. But then, our problem is that if we extend RadioButton, EditText and others, the tinting is not applied. Initially I extended the style of the RadioButton to android:Widget.CompoundButton but nothing happens, then I make sure that if I just use RadioButton and set the color* that it would work and it did. After few tries, I went back to StackOverflow and found this in where it tells use to extends the internal class.

So I made an experiment and here is the gist
First, we create a FontUtils so that we could reuse it with different components
public class FontUtils {
    public static int FONT_REGULAR = 0;
    public static int FONT_THIN = 1;

    public static void setTypeface (int fontName, TextView textView) {
        Typeface font = null;
        Context context = textView.getContext();
        Resources resources = context.getResources();
        if (fontName == FontUtils.FONT_REGULAR) {
            font = Typeface.createFromAsset(context.getAssets(), resources.getString(R.string.font_regular));
        } else if (fontName == FontUtils.FONT_THIN) {
            font = Typeface.createFromAsset(context.getAssets(), resources.getString(R.string.font_thin));
        }
        textView.setTypeface(font);
    }
}

The full class is here, basically here we create a helper class that would set the typeface based on the fontName that is passed from the xml. We create the typeface from the files we have under assets/ using the Typeface.createFromAsset(context.getAssets(), resources.getString(R.string.font_thin)); where the getString() will load the path of the string based on the locale we have. For example we passed in 0 (FONT_REGULAR) we would then load fonts/Roboto-Regular.ttf for English and fonts/NotoSansCJKtc-Bold.oft for Chinese.

For the custom class we have RadioButton as example but it could easily be done with EditText, CheckBox, Spinner using the prefix Tint.
public class RadioButtonCustomFont  extends TintRadioButton {
    private int mFontName;
 
    ...
    public RadioButtonCustomFont(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(attrs, 0);
    }
    ... 

    private void init(AttributeSet attrs, int defStyle) {
        final TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.font, defStyle, 0);
        mFontName = a.getInt(R.styleable.font_name, FontUtils.FONT_REGULAR);
        a.recycle();
 
        if (!isInEditMode()) {
            FontUtils.setTypeface(mFontName, this);
        }
    }
}

Here we just pass the mFontName to our FontUtils helper, we got that from the xml on our layout.

To create our RadioButtonCustomFont on our layout we must do something like this
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:font="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    <com.monmonja.tutorial.RadioButtonCustomFont
        font:name="Regular"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Yes"
        />
</RelativeLayout>

Here we create a namespace for font (the same as the name in our assets.xml) then we pass in font:name the value/s from the assets.xml.

Finally we need to apply the tinting that comes with appcompat, for that take a look at the our themes.xml and its explanation is the same as Appcompat for pre-lollipop theming part
Hope this helps :)

Thursday, March 12, 2015

Automatically generate Parcelable in Android

Found this really amazing plugin (for lazy people) for Android Studio
Android Parcelable boilerplate code generation

What it does is rewrite the class automatically to include the codes for making your object be Parcelable (for passing between activity, fragment, screen orientation or more).

Tuesday, March 10, 2015

Center DialogFragment with padding

How do you center the DialogFragment in Android with padding on the right and left? Something like this

For the following, the code is at Github Gist

The problem:
When I created a DialogFragment, the layout's width (match_parent) is being ignored.
The solution for this is to get the window and set the width on the layout
@Override
public void onStart() {
    super.onStart();
    getDialog().getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
}

However we want to add padding on the right and left of the window.
One solution, which I did right now is to

Create the dialog with custom style
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    final View view = View.inflate(getActivity(), R.layout.dialog_fragment, null);

    Dialog dialog = new Dialog(getActivity(), R.style.DialogFragment);
    dialog.setContentView(view);
    return dialog;
}

On DialogFragment we extend it to the framework's Dialog style and set windowIsFloating to true with windowBackground of transparent
<style name="DialogFragment" parent="android:style/Theme.Dialog">
    <item name="android:windowBackground">@android:color/transparent
    <item name="android:windowNoTitle">true
    <item name="android:windowIsFloating">true
 
    <item name="android:layout_gravity">center
</style>
Add another layer on the layout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="20dp"
    android:paddingRight="20dp"
    >
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:background="@drawable/dialog_fragment_bg"
        >
            ...

We added another layer so that we can add the simulated window style on the child layout, we also added a fake shadow on dialog_fragment_bg because we removed it when we set the windowBackground to transparent.

If there is a better solution, please comment below
Hope this helps :)

Wednesday, February 11, 2015

SMS Quotes new app

Released a new android app SMS Quotes, it is a rewrite of my previous website back in 2006/2007 but with added feature like being able to create quotes that could be share in different social network like instagram. Like:

Any feedback is appreciated :)

Download SMS Quotes