Android: Creating a FlowLayout

Sometimes in mobile development you want to create a layout programmatically with an unknown number of elements. You may want to add elements to it dynamically and have the layout height grow as elements are added. Unfortunately, in Android, there is no native FlowLayout. Here is a method that gets us this functionality. I worked on this with Sherif elKhatib on StackOverlow. Actually, he wrote the original version and I’ve optimized it account for a layout which doesn’t fill the entire width of the screen. The code below turns a native LinearLayout into a FlowLayout. Just pass in the LinearLayout, the set of Views you want to add to the LinearLayout, the Context, and any extra view that may be on the left or right of the LinearLayout.

(Note: Make sure your LinearLayout has orientation vertical.)

/**
 * Copyright 2011 Sherif 
 * Updated by Karim Varela to handle LinearLayouts with other views on either side.
 * @param linearLayout
 * @param views : The views to wrap within LinearLayout
 * @param context
 * @param extraView : An extra view that may be to the right or left of your LinearLayout.
 * @author Karim Varela
 **/
private void populateViews(LinearLayout linearLayout, View[] views, Context context, View extraView)
{
    extraView.measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);

    // kv : May need to replace 'getSherlockActivity()' with 'this' or 'getActivity()'
    Display display = getSherlockActivity().getWindowManager().getDefaultDisplay();
    linearLayout.removeAllViews();
    int maxWidth = display.getWidth() - extraView.getMeasuredWidth() - 20;

    linearLayout.setOrientation(LinearLayout.VERTICAL);

    LinearLayout.LayoutParams params;
    LinearLayout newLL = new LinearLayout(context);
    newLL.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
    newLL.setGravity(Gravity.LEFT);
    newLL.setOrientation(LinearLayout.HORIZONTAL);

    int widthSoFar = 0;

    for (int i = 0; i < views.length; i++)
    {
        LinearLayout LL = new LinearLayout(context);
        LL.setOrientation(LinearLayout.HORIZONTAL);
        LL.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
        LL.setLayoutParams(new ListView.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));

        views[i].measure(0, 0);
        params = new LinearLayout.LayoutParams(views[i].getMeasuredWidth(), LayoutParams.WRAP_CONTENT);
        params.setMargins(5, 0, 5, 0);

        LL.addView(views[i], params);
        LL.measure(0, 0);
        widthSoFar += views[i].getMeasuredWidth();
        if (widthSoFar >= maxWidth)
        {
            linearLayout.addView(newLL);

            newLL = new LinearLayout(context);
            newLL.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
            newLL.setOrientation(LinearLayout.HORIZONTAL);
            newLL.setGravity(Gravity.LEFT);
            params = new LinearLayout.LayoutParams(LL.getMeasuredWidth(), LL.getMeasuredHeight());
            newLL.addView(LL, params);
            widthSoFar = LL.getMeasuredWidth();
        }
        else
        {
            newLL.addView(LL);
        }
    }
    linearLayout.addView(newLL);
}

Mapping iOS Assets to Android

So I’ve got a sweet new job working for Beachbody. We make awesome products like P90X and Brazil Butt Lift. We also make mobile apps. They hired me to essentially port their P90X iOS app to Android.

I’m in the planning stages right now and one of the challenges I’m facing is how to map the existing iOS asset classes to their appropriate Android asset classes. For iOS, it’s still pretty easy, you just have at most three classes of assets to worry about:

  • Small = 480 x 320 (163 dpi)
  • Large = 960 x 640 (326 dpi)
  • Tall = 1136 x 640 (326 dpi)

For Android, you have the following screen sizes classes:

  • Small = at least 426dp x 320dp
  • Medium = at least 470dp x 320dp
  • Large = at least 640dp x 480dp
  • xLarge = at least 960dp x 720dp

Then, you also have different density classes:

  • ldpi = low density (~120dpi)
  • mdpi = medium (baseline) density (~160dpi)
  • hdpi = high density (~240dpi)
  • xhdpi = extra high density (~320dpi)
Looking at this data, if you don’t have the resources to create assets for every Android density class (ldpi, mdpi, hdpi, xhdpi), it looks the following mappings make sense:
  • Small iOS images should work for ldpi and mdpi Android devices.
  • Large iOS images should work for hdpi and xhdpi Android devices.

Unless I hear about a better solution, this will the strategy I’m taking. Please comment on this post if you have any feedback or input! Cheers!

Android: How to Programmatically Lock the Orientation

In mobile application development, there may be times when you want certain screens within your app to always show in landscape or in portrait mode. Android makes this easy to do within your Activity class:

import android.content.pm.ActivityInfo;
...
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

You can also set this in the manifest:


Android Selectors

Android selectors can be used to give your Buttons or images the feeling that they are being pressed. Essentially, a selector defines a different drawable for different states of an image or Button. Selector files should reside in the /res/drawable/ folder in your project. Here’s what a basic selector looks like:


    
     
     

If this XML resided in /res/drawable/imagebutton_selector, for example you’d set the android:src attribute of your button to android:src=”@drawable/imagebutton_selector”.

What is Eurocurrency?

It’s a common misconception that Eurocurrency has to be the deposit of foreign currency in a European bank. In fact, Eurocurrency is considered a deposit any currency in an international bank located in a different country from the deposited money.

Eurocurrency got it’s start back in the Soviet communist days. Back then, Communist countries were afraid to deposit their US dollars in US banks for fear their assets would be frozen our stripped (due to anti-Communist) sentiment. They chose to deposit their US dollars in a French bank whose telex address happen to be EURO-BANK. That’s why we call it Eurocurrency!

Since the advent of the European Union and the euro, however, we have started to call Eurocurrency simply international currency. Also, instead of the term Eurobank, we now use the term prime bank. I think this makes more sense.

When a Eurobank, or prime bank, makes a short to medium-term loan, we call this appropriately a Eurocredit. These loans would be loans in currencies other than the currency of the home country of the lending bank.

A Kind Message from Software Developers to Recruiters

Dear Recruiters,

I write this message to you on behalf of all software developers as I know that most us feel the same way.

Let me start off by saying that I appreciate what recruiters do. I don’t appreciate what they do for the corporate world, or for technology, as I could argue either way for those benefits. I appreciate what recruiters have done for me personally. If it wasn’t for recruiters, I’d probably be making about half the income I make I right now. Also, if it wasn’t for recruiters, I probably never would have moved from San Francisco to Seattle and then from Seattle to Los Angeles. It’s not that I couldn’t have figured out how to make more money on my own or that I couldn’t have moved around the country on my own. It’s just that the motivation to leave companies for more money or to move to a different city to go work for a different company isn’t really an inherent motivation for me. Recruiters have supplied much of this motivation, and for that I’m thankful.

Now to what I don’t appreciate:

  • Not reading my resume / LinkedIn profile:
    I don’t appreciate you pitching jobs to me for which I’m obviously not qualified or interested in. Take a minute and read the entire thing. At the bottom of my LinkedIn profile, there’s even a section where I spell out for you which types of jobs I’d be interested in interviewing for.
  • Calling me while I’m at work:
    You know I have a job, right? You know I get paid to write code, not talk on the phone, right? Do I call you while you’re at your job and try to get you to take a job somewhere else? No, I don’t. It’s called respect. If you give us respect, we’ll give you  respect.
  • Scheduling a phone interview during the middle of my day:
    This goes back to my previous point. Why would I want to interview for a different position during the middle of my work day? Who does that? Only unemployed people. Get a clue please.

Sorry if this sounds harsh. I realize you are just trying to make a living the best way you can. Think about this though. Maybe if you stopped treating developers like your next paycheck, they would actually have some semblance of loyalty to you or your recruiting firm and not treat you like a commodity.

Happy head hunting,
Karim

Android: How to Hide Keyboard By Touching Screen Outside Keyboard

If you’ve ever worked for a mobile software company that builds both an iOS app and an Android app, many times the product people will ask that a certain feature be implemented consistently across both platforms.  This week I was tasked with implementing a popular iOS feature, the ability to hide the virtual keyboard when the user touches outside of the keyboard, on Android.

The methodology is simple, but not entirely intuitive. Let’s look at how it’s done. Basically, you get a handle on the layout in question. In this example, we’ll use a LinearLayout:

LinearLayout layout = (LinearLayout) findViewById(R.id.layout);

 

Then, override the layout’s OnTouchListener.onTouch() like so:

layout.setOnTouchListener(new OnTouchListener()
{
    @Override
    public boolean onTouch(View view, MotionEvent ev)
    {
        hideKeyboard(view);
        return false;
    }
});

 

The code to hide the keyboard is fairly popular:

/**
* Hides virtual keyboard
*
* @author kvarela
*/
protected void hideKeyboard(View view)
{
    InputMethodManager in = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
    in.hideSoftInputFromWindow(view.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
}

Software Engineers, Don’t Waste Your Time Any Longer, Build Your Future

Today, I came to the full realization of something that’s always been an itch in the back of my mind. If you’re a software engineer and you’re not utilizing your talents to help build a company or gain a stake in a company, you are wasting your time.

You may say, “Oh Karim, that’s mighty hypocritical for you to say. After all, you work for Fandango as a consultant and have no stake in NBC Universal, the parent company of Fandango. You get no benefit and no share of Fandango’s immense success.” If you said this, you are right, and don’t get me wrong, Fandango is an awesome place to work. From our catered lunches and company movie outings and an incredible location just three miles from my apartment, it’s difficult to imagine a better place to work right now.

I’m not resting on my laurels, however; I’m actively doing things to build my future. For instance, I’m about half way through with business school at the University of Florida. I’m also attending the AT&T Mobile App Hackathon – Los Angeles in a few weeks. There, I plan to build my first commercial mobile app.

As software engineers, we have the unique ability to not only think something up, but to go out and build it. We have the power to create software that millions of people will use. We have the power to create this with nothing more than our brains, our fingers, and a computer. Even with a world economy in the midst of a deep recession, the demand for software engineers has been increasing faster than the supply. Don’t waste your talent; go build your future. If you have a good idea, and are interested in working with me, hit me up. Let’s chat!

Awareness Is …

A person is aware when they contemplate the world around them, when they
understand they are just a grain of sand in the universal ocean, when they
recognize how good we have it and empathize with those who are less
fortunate, when they know what’s going on in the world outside of their
city, state, country, race, creed, or origin, when they form their beliefs
based on their own moral compass and are not influenced by media or popular
culture, when they can put themselves in somebody else’s shoes who may
think very different from them and understand why they think that way.