Search

Android–Bluetooth Barcode Scanners & The Soft Keyboard

Wednesday, 22 October 2014

Bluetooth barcode scanners are a great alternative to barcode apps that use the camera. The only downside is that because they work as bluetooth keyboards they can stop the soft keyboard from appearing. This means you have to turn the scanner off if you want to type anything in. Here’s a way to get the scanner and the soft keyboard working together…
  1. Pair the scanner and to the device.
  2. Go to Settings.
  3. Go to Language & Input.
  4. Under ‘Keyboard & Input Methods’ click on ‘Default’.
  5. Turn ‘Hardware/Physical Keyboard’ Off.
Screenshot_2014-10-22-12-01-02
Now the scanner and the soft keyboard will work together. The downside to this method is that you have to do it each item the scanner is paired with the device. I’m investigating solutions to that so watch this space…

Xamarin Android Listviews - Custom Activity Layout

Monday, 20 October 2014

This post demonstrates how to use a custom activity layout with an Android ListView. The source code for the example is available here.
The previous examples have used the default list activity layout, which is just a full screen list view. Now we’ll use a custom layout to show the list view and a few other controls. The is the layout:
<?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="All Players By Name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/btnSort" />
<Button
android:text="Just Notts"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/btnJustNotts" />
<Button
android:text="Empty List"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/btnEmpty" />
<TextView
android:text="Nothing to show!"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@android:id/empty"
android:layout_margin="4dp" />
<ListView
android:minWidth="25px"
android:minHeight="25px"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:id="@android:id/list" />
</LinearLayout>
This is a simple vertical linear layout. There are some buttons at the top which control what is displayed, a text view which is displayed if the list is empty, and the list itself. The list has the id “android:id/list” - this id tells the activity to use the list. The activity will display the element with the id “@android:id/empty” if there are no items in the list. It doesn’t have to be present and it can be used with any layout element.
In the code for the activity we need to use the custom layout in the OnCreate method…
protected override void OnCreate(Bundle bundle)
{
    base.OnCreate(bundle);

    this.SetContentView(Resource.Layout.CustomLayout);

    this.FindViewById<Button>(Resource.Id.btnSort).Click += this.btnSort_Click;
    this.FindViewById<Button>(Resource.Id.btnJustNotts).Click += this.btnJustNotts_Click;
    this.FindViewById<Button>(Resource.Id.btnEmpty).Click += this.btnEmpty_Click;

    data = Player.GetPlayers();
    this.ListAdapter = new PlayerAdapter(this, data);
}

Xamarin Android Listviews - Checkboxes On List Items

Friday, 17 October 2014

This post demonstrates how to put check boxes on list items, and how to handle the checkbox change events. The source code for the example is available here.

First of all we need a layout for the list items. This is the one I’ve used:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="25px"
    android:minHeight="25px"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/relativeLayout1"
    android:padding="4dp">
    <TextView
        android:text="txtName"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/txtName" />
    <TextView
        android:text="txtTeam"
        android:textAppearance="?android:attr/textAppearanceSmall"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/txtName"
        android:id="@+id/txtTeam"
        android:layout_alignLeft="@+id/txtName" />
    <CheckBox
        android:text="Captain"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/txtTeam"
        android:id="@+id/chkCaptain"
        android:layout_marginRight="0.0dp" />
</RelativeLayout>

Then we need an adapter, mine looks like this:

private class CheckBoxAdapter : BaseAdapter
{
    private Activity activity;
    private List data;

    public CheckBoxAdapter(Activity activity, List data)
    {
        this.activity = activity;
        this.data = data;
    }

    public override Player this[int position]
    {
        get { return this.data[position]; }
    }

    public override int Count
    {
        get { return this.data.Count(); }
    }

    public override long GetItemId(int position)
    {
        return 0;
    }

    public override View GetView(int position, View convertView, ViewGroup parent)
    {
        View view = convertView;

        if (view == null)
        {
            view = this.activity.LayoutInflater.Inflate(Resource.Layout.PlayerListItem4, null);
        }

        Player player = this.data[position];

        view.FindViewById(Resource.Id.txtName).Text = player.Name;
        view.FindViewById(Resource.Id.txtTeam).Text = player.Team;

        CheckBox chkCaptain = view.FindViewById(Resource.Id.chkCaptain);
        chkCaptain.Tag = player.Name;

        chkCaptain.SetOnCheckedChangeListener(null);
        chkCaptain.Checked = player.Captain;
        chkCaptain.SetOnCheckedChangeListener(new CheckedChangeListener(this.activity));

        return view;
    }

    private class CheckedChangeListener : Java.Lang.Object, CompoundButton.IOnCheckedChangeListener
    {
        private Activity activity;

        public CheckedChangeListener(Activity activity)
        {
            this.activity = activity;
        }

        public void OnCheckedChanged(CompoundButton buttonView, bool isChecked)
        {
            if (isChecked)
            {
                string name = (string)buttonView.Tag;
                string text = string.Format("{0} Checked.", name);
                Toast.MakeText(this.activity, text, ToastLength.Short).Show();
            }
        }
    }
}

Notice how we need to call SetOnCehckedChangeListener(null) before changing the value of the check box. This is because changing the value will also fire the event. If we don’t set the listener to null the change handler is called every time we bind an item to the layout.

The rest of the controller is pretty simple. The CheckedChangeListener shows a toast message whenever the checkbox is checked.


Xamarin Android ListViews–Buttons on List Items

Thursday, 9 October 2014

In this post we look at how to show a button on each item in a list, and how to handle click on both the list item and the button. The source code for the example is available here.

The first thing to do is to add a button to the item layout:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="25px"
    android:minHeight="25px"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/relativeLayout1"
    android:padding="4dp">
    <TextView
        android:text="txtName"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/txtName" />
    <TextView
        android:text="txtTeam"
        android:textAppearance="?android:attr/textAppearanceSmall"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/txtName"
        android:id="@+id/txtTeam"
        android:layout_alignLeft="@+id/txtName" />
    <Button
        android:text="Button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/txtTeam"
        android:id="@+id/button1" />
</RelativeLayout>


And you also need to update the adapter to handle button clicks. Here’s the full adapter code…

private class ButtonAdapter : BaseAdapter<Player>
{
    private Activity activity;
    private List<Player> data;

    public ButtonAdapter(Activity activity, List<Player> data)
    {
        this.activity = activity;
        this.data = data;
    }

    public override Player this[int position]
    {
        get { return this.data[position]; }
    }

    public override int Count
    {
        get { return this.data.Count(); }
    }

    public override long GetItemId(int position)
    {
        return 0;
    }

    public override View GetView(int position, View convertView, ViewGroup parent)
    {
        View view = convertView;

        if (view == null)
        {
            view = this.activity.LayoutInflater.Inflate(Resource.Layout.PlayerListItem3, null);
        }

        Player player = this.data[position];

        string name = player.Name;

        if (player.Captain)
        {
            name = string.Format("{0} (c)", name);
        }

        view.FindViewById<TextView>(Resource.Id.txtName).Text = name;
        view.FindViewById<TextView>(Resource.Id.txtTeam).Text = player.Team;

        Button button1 = view.FindViewById<Button>(Resource.Id.button1);
        button1.Tag = name;
        button1.SetOnClickListener(new ButtonClickListener(this.activity));

        return view;
    }

    private class ButtonClickListener : Java.Lang.Object, View.IOnClickListener
    {
        private Activity activity;

        public ButtonClickListener(Activity activity)
        {
            this.activity = activity;
        }

        public void OnClick(View v)
        {
            string name = (string)v.Tag;
            string text = string.Format("{0} Button Click.", name);
            Toast.MakeText(this.activity, text, ToastLength.Short).Show();
        }
    }
}


Here we’ve used a class that implements View.IOnClickListener to handle the clicks. Alternatively we could subscribe to the click event but then we would need to be careful to make sure that we only subscribe once for each button. As the item views are reused it’s easy to inadvertently subscribe to each button click multiple times. Using SetOnClickListener ensures that the click will only be handled once – it automatically replaces the old handler with the new one.


Handling Button Clicks & Item Clicks



Here’s the code for the activity – you can see that we have overridden OnListItemClick to show some toast.

[Activity(Label = "Custom Adapter")]
public class ButtonActivity : ListActivity
{
    protected override void OnCreate(Bundle bundle)
    {
        base.OnCreate(bundle);

        List<Player> players = Player.GetPlayers();
        this.ListAdapter = new ButtonAdapter(this, players);
    }

    protected override void OnListItemClick(ListView l, View v, int position, long id)
    {
        base.OnListItemClick(l, v, position, id);

        Player player = ((ButtonAdapter)this.ListAdapter)[position];
        string text = string.Format("{0} Item Click!", player.Name);
        Toast.MakeText(this, text, ToastLength.Short).Show();
    }
}


With the layout used above the OnListItemClick event won’t actually fire – to get it to fire we need to set focusable to false on the button like this:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="25px"
    android:minHeight="25px"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/relativeLayout1"
    android:padding="4dp">
    <TextView
        android:text="txtName"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/txtName" />
    <TextView
        android:text="txtTeam"
        android:textAppearance="?android:attr/textAppearanceSmall"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/txtName"
        android:id="@+id/txtTeam"
        android:layout_alignLeft="@+id/txtName" />
    <Button
        android:text="Button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/txtTeam"
        android:id="@+id/button1"
        android:focusable="false" />
</RelativeLayout>


Setting focusable to false stops the button from taking focus when you click on the ListItem and lets the OnListItemClick method run.


Xamarin Android ListViews–Alternating Item Layouts

Tuesday, 7 October 2014

If you want your list to show alternating layouts you need to create two layouts and do a bit more work in the adapter. The source for this, and the other articles in the series is available here. The end result looks like this.
AlternatingLayout

To do this you’ll need two separate layouts, one with the image on the left and one with it on the right.
PlayerListItem1
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="25px"
    android:minHeight="25px"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/relativeLayout1"
    android:padding="4dp">
    <ImageView
        android:src="@android:drawable/ic_menu_gallery"
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:id="@+id/imgRoleIcon"
        android:layout_margin="4dp" />
    <TextView
        android:text="txtName"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/imgRoleIcon"
        android:id="@+id/txtName" />
    <TextView
        android:text="txtTeam"
        android:textAppearance="?android:attr/textAppearanceSmall"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/txtName"
        android:id="@+id/txtTeam"
        android:layout_alignLeft="@+id/txtName" />
</RelativeLayout>

PlayerListItem2
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="25px"
    android:minHeight="25px"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/relativeLayout1"
    android:padding="4dp">
    <ImageView
        android:src="@android:drawable/ic_menu_gallery"
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:id="@+id/imgRoleIcon"
        android:layout_alignParentRight="true"
        android:layout_margin="4dp" />
    <TextView
        android:text="txtName"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/txtName" />
    <TextView
        android:text="txtTeam"
        android:textAppearance="?android:attr/textAppearanceSmall"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/txtName"
        android:id="@+id/txtTeam"
        android:layout_alignLeft="@+id/txtName" />
</RelativeLayout>

In the adapter we need to override ViewTypeCount and GetItemViewType. ViewTypeCount just needs to return the number of views that are used.
public override int ViewTypeCount
{
    get
    {
        return 2;
    }
}

GetItemViewType needs to return an int that identifies which layout is used for an item. In this example we are alternating the views so we return 0 for odd numbered items and 1 for evens.
public override int GetItemViewType(int position)
{
    int result = 0;

    if (position % 2 == 0)
    {
        result = 1;
    }

    return result;
}

We also need to make some changes to the GetView method so that the correct layout is inflated. Android is clever about this makes sure the correct view is passed as convertView; we only need to set the layout if convertView is blank. As both layouts have the same controls we can use common code for setting them up.
public override View GetView(int position, View convertView, ViewGroup parent)
{
    View view = convertView;

    if (view == null)
    {
        switch (this.GetItemViewType(position))
        {
            case 0:
                view = this.activity.LayoutInflater.Inflate(Resource.Layout.PlayerListItem1, null);
                break;

            case 1:
                view = this.activity.LayoutInflater.Inflate(Resource.Layout.PlayerListItem2, null);
                break;
        }
        
    }

    Player player = this.data[position];

    string name = player.Name;

    if (player.Captain)
    {
        name = string.Format("{0} (c)", name);
    }

    view.FindViewById<TextView>(Resource.Id.txtName).Text = name;
    view.FindViewById<TextView>(Resource.Id.txtTeam).Text = player.Team;

    ImageView imgRoleIcon = view.FindViewById<ImageView>(Resource.Id.imgRoleIcon);

    switch (player.Role)
    {
        case Player.RoleEnum.Batsman:
            imgRoleIcon.SetImageResource(Resource.Drawable.Bat);
            break;

        case Player.RoleEnum.Bowler:
            imgRoleIcon.SetImageResource(Resource.Drawable.Ball);
            break;

        case Player.RoleEnum.WicketKeeper:
            imgRoleIcon.SetImageResource(Resource.Drawable.Wicket);
            break;

        case Player.RoleEnum.Allrounder:
            throw new NotImplementedException();
    }

    return view;
}

The complete adapter class looks like this.
private class AlternatingPlayerAdapter : BaseAdapter<Player>
{
    private Activity activity;
    private List<Player> data;

    public AlternatingPlayerAdapter(Activity activity, List<Player> data)
    {
        this.activity = activity;
        this.data = data;
    }

    public override Player this[int position]
    {
        get { return this.data[position]; }
    }

    public override int Count
    {
        get { return this.data.Count(); }
    }

    public override long GetItemId(int position)
    {
        return 0;
    }

    public override int ViewTypeCount
    {
        get
        {
            return 2;
        }
    }

    public override int GetItemViewType(int position)
    {
        int result = 0;

        if (position % 2 == 0)
        {
            result = 1;
        }

        return result;
    }

    public override View GetView(int position, View convertView, ViewGroup parent)
    {
        View view = convertView;

        if (view == null)
        {
            switch (this.GetItemViewType(position))
            {
                case 0:
                    view = this.activity.LayoutInflater.Inflate(Resource.Layout.PlayerListItem1, null);
                    break;

                case 1:
                    view = this.activity.LayoutInflater.Inflate(Resource.Layout.PlayerListItem2, null);
                    break;
            }
            
        }

        Player player = this.data[position];

        string name = player.Name;

        if (player.Captain)
        {
            name = string.Format("{0} (c)", name);
        }

        view.FindViewById<TextView>(Resource.Id.txtName).Text = name;
        view.FindViewById<TextView>(Resource.Id.txtTeam).Text = player.Team;

        ImageView imgRoleIcon = view.FindViewById<ImageView>(Resource.Id.imgRoleIcon);

        switch (player.Role)
        {
            case Player.RoleEnum.Batsman:
                imgRoleIcon.SetImageResource(Resource.Drawable.Bat);
                break;

            case Player.RoleEnum.Bowler:
                imgRoleIcon.SetImageResource(Resource.Drawable.Ball);
                break;

            case Player.RoleEnum.WicketKeeper:
                imgRoleIcon.SetImageResource(Resource.Drawable.Wicket);
                break;

            case Player.RoleEnum.Allrounder:
                throw new NotImplementedException();
        }

        return view;
    }
}

Xamarin Android ListViews - CustomAdapter

Monday, 6 October 2014

ArrayAdapters are OK for showing a quick list but most of the time you'll need more power - you'll need to create a custom adapter. In this article we'll look at creating a custom adapter and layout, and using it in an activity. The source code for all of my list view posts is here.

Custom Adapters

A custom adapter lets you bind objects to a layout that you control. Here we'll display a list of cricketers. To do this we'll need...
  • A list of data.
  • A layout to display the items.
  • An adapter to bind the data to the layout.
  • A ListActivity to display the list.
The end result looks like this.

The Layout

The layout is a standard axml layout. In this case we'll show an imageview and a couple of textviews.

The Adapter

The adapter is a class which inherits from BaseAdapter. It takes a list of Player objects and binds them to the layout as required. This is all the code for the class.

This is all pretty simple - the most interesting method is GetView which is where the data is bound to the layout. Android will try to reuse existing layouts which is why the layout is only inflated when the view is null. Because the views can be reused you need to make sure all the controls are handled each time the method is called, otherwise the 'old' data will still be displayed.

The Activity

The activity is basically the same as in the simple example. We create a list of data, an adapter (a PlayerAdapter this time), and assign it to the ListAdapter property.

Xamarin Android ListViews - Basics

This is the first in a series on Android ListViews in Xamarin. We look at how to show a basic list of strings using a ListActivity and an Array Adapter. We also look at handling clicks on list items.You can get the source code for all of my ListView articles here.

All of these examples are based on a ListActivity. By default this will give you an interface which is just a list. If you need a more sophisticated layout you can use a ListActivity with a custom layout (covered later in the series).
Here we use an ArrayAdapter as a ListAdapter. This is really simple, it takes a list of strings and then deals with showing them in the list. When it's running it looks like this...



Handling Item Clicks

To handle item clicks we can override OnListItemClick. Here we just popup some toast.

Alternatively you can subscribe to the click event. For long clicks you always need to subscribe to the event. Subscribe in the OnCreate method.
And then handle the click.