Monday, April 23, 2012

Listview, soundboard & Sherlock

Here we go again. This is a complete code for a simple listview with an image and a textview. When item is pressed, it plays a soundfile.
It features a listadapter, backpress toast and uses the Sherlock library found here: http://actionbarsherlock.com/. Dont forget including the Android compability library as well if you use Sherlock.

ActionBarSherlock

You can easily remake it to a normal listactivity by removing the "Sherlock" and just extend ListActivity.
Place the sound and imagefiles in assets folder named: 0.ogg, 1.ogg ... 0.png, 1.png ...

In my app, the result looks like this. The app is found here:
https://play.google.com/store/apps/details?id=se.ernell.sound.fartingzoo


Its easy to remake for your own looks and colors.
Just edit main.xml and list_item.xml

SoundboardActivity.java

public class SoundboardActivity extends SherlockListActivity {

    private final static String  TAG   = "SOUNDBOARD";
    private final static boolean debug = false;//debug mode
    private final static String  SOUND_EXTENSION = ".ogg";
    private final static String  IMAGE_EXTENSION = ".png";

    private MediaPlayer         mMediaPlayer;
    private AssetFileDescriptor mAssetFileDescriptor;

    private Toast mToast;
    private long  mLastBackPressTime = 0;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);
        setVolumeControlStream(AudioManager.STREAM_MUSIC);
        mMediaPlayer = new MediaPlayer();

        try{
            String[] titles = getResources().getStringArray(R.array.titles_array);
            List<String> al = new ArrayList<String>();
            for(int i=0;i<titles.length;i++)
                al.add(titles[i]);

            CustomAdapter ca = new CustomAdapter(this, R.layout.list_item, al);
            setListAdapter(ca);

            ListView lv = getListView();
            lv.setOnItemClickListener(new OnItemClickListener() {
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    try{
                        if ( mMediaPlayer.isPlaying() )
                            mMediaPlayer.stop();
                        mMediaPlayer.reset();
                        mAssetFileDescriptor = getAssets().openFd(position + SOUND_EXTENSION);
                        mMediaPlayer.setDataSource(mAssetFileDescriptor.getFileDescriptor(), mAssetFileDescriptor.getStartOffset(), mAssetFileDescriptor.getLength());
                        mMediaPlayer.prepare();
                        mMediaPlayer.start();
                    } catch (Exception e) {
                            Log.d(TAG, "Exception: "+e.getLocalizedMessage());
                    }
                }
            });
        } catch (Exception e) {
            Log.d(TAG, "Exception in onCreate(): "+e.getLocalizedMessage());
        }
    }

    @Override
    public void onBackPressed() {
        if ( mLastBackPressTime < (System.currentTimeMillis() - 3000) ) {
            mToast = Toast.makeText(this, "Press back again to close the app", 4000);
            mToast.show();
            mLastBackPressTime = System.currentTimeMillis();
        } else {
            if (mToast != null)
                mToast.cancel();
            super.onBackPressed();
        }
    }

    public static class CustomAdapter extends ArrayAdapter<String>{

        private static LayoutInflater mInflater;
        private static List<String>   mItems;
        private static int            mTextViewResourceId;
        private static Context        mContext;

        public CustomAdapter(SoundboardActivity context, int textViewResourceId, List<String> items) {
            super(context, textViewResourceId, items);
            mContext = context;
            if(textViewResourceId == 0)
                mTextViewResourceId = R.layout.list_item;
            else
                mTextViewResourceId = textViewResourceId;
            mItems = items;
            mInflater = LayoutInflater.from(context);
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {

            ViewHolder holder;

            if (convertView == null) {
                convertView = mInflater.inflate(mTextViewResourceId, null);
                holder = new ViewHolder();
                holder.text = (TextView)  convertView.findViewById(R.id.text);
                holder.icon = (ImageView) convertView.findViewById(R.id.img);
                convertView.setTag(holder);
            } else {
                holder = (ViewHolder) convertView.getTag();
            }
            holder.text.setText(  mItems.get(position) );
            String filename = position + IMAGE_EXTENSION;
            try{
                Bitmap bm = getBitmapFromAsset(filename);
                if(bm != null){
                    holder.icon.setVisibility(View.VISIBLE);
                    holder.icon.setImageBitmap(bm);
                }else{
                    Log.d(TAG,"Error: Bitmap asset ["+filename+"] == null");
                }
            }catch(IOException ioe){
                Log.d(TAG,"IOException: Error retrieving image ["+filename+"] from asset folder. Message: "+ioe.getLocalizedMessage());
                holder.icon.setVisibility(View.GONE);
            }
            return convertView;

        }

        private static Bitmap getBitmapFromAsset(String strName) throws IOException{
            AssetManager assetManager = mContext.getAssets();
            InputStream istr = assetManager.open(strName);
            Bitmap bitmap = BitmapFactory.decodeStream(istr);
            istr.close();
            return bitmap;
        }

        static class ViewHolder {
            TextView text;
            ImageView icon;
        }

    }

}


main.xml


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res/se.ernell.adp"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <!-- ListView -->

    <ListView
        android:id="@android:id/list"
        android:layout_marginTop="5dp"
        android:layout_width="fill_parent"
        android:layout_height="0dip"
        android:layout_weight="1"
        android:background="@android:color/transparent"
        android:cacheColorHint="#00000000"
        android:divider="#ff33b5e5"
        android:dividerHeight="0.1dp"
        android:drawSelectorOnTop="false"
        android:footerDividersEnabled="false"
        android:headerDividersEnabled="false"
        android:paddingBottom="0dp"
        android:paddingLeft="10dp"
        android:paddingRight="10dp"
        android:paddingTop="0dp" />

</LinearLayout>



list_item.xml

Change imageview layout_width+height to your prefs.


<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" >

    <ImageView
        android:id="@+id/img"
        android:scaleType="centerCrop"
        android:layout_width="100dp"
        android:layout_height="100dp" />

    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:paddingLeft="10dp"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" >

        <TextView
            android:layout_width="fill_parent"
            android:id="@+id/text"
            android:layout_height="wrap_content"
            android:textStyle="bold"
            android:textColor="#33b5e5"
            android:textSize="24dp" />
    </LinearLayout>

</LinearLayout>

Include this in strings.xml
For every item in the array, make sure there is a .ogg + .png file in assets.
In this case you need 0.ogg, 1.ogg, 2.ogg, 0.png, 1.png, 2.png

    <!-- Sound titles -->
    <string-array name="titles_array">
        <item>Itemtext 0</item>
        <item>Itemtext 1</item>
        <item>Itemtext 2</item>
    </string-array>

Use the code as you wish.
/r0b

1 comment: