0

I need to make an Activity with a ListView that could have more than 50 ImageButtons that each play a different Sound.

This is the main activity (that would have the buttons):

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"

    tools:context="com.werewolve.freaksound.sounds"
    android:background="@drawable/f_background_fit">

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/imageView"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="5dp"
        android:src="@drawable/f_logo" />

    <ListView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/soundList"
        android:layout_below="@+id/imageView"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="15dp" />
</RelativeLayout>

This is my custom layout for each line of the listview:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <TextView
        android:id="@+id/list_item_string"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_alignParentLeft="true"
        android:paddingLeft="8dp"
        android:paddingRight="8dp"
        android:textSize="18sp"
        android:textStyle="bold" />

    <ImageButton
        android:id="@+id/play_btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:background="#00000000"
        android:src="@drawable/f_button_s"
        android:layout_centerVertical="true"
        android:layout_marginRight="5dp" />

</RelativeLayout>

Each button will play a different sound with the onClick "play_btn" and a text according to the sound with the string "list_item_string".

Example:


* (Laugh Sound) * (Play Button) ***


ElAlonnso
  • 33
  • 6

2 Answers2

2

You should create a custom adapter like so:

public class PlaySoundsAdapter extends BaseAdapter implements View.OnClickListener {

    SoundExample[] sounds;
    Activity context;
    PlaySoundAlert soundPlayerAlert;

    public PlaySoundsAdapter(Activity context, SoundExample[] soundsArray) {
        this.context = context;
        this.sounds = soundsArray;

        // Hooks up the PlaySoundAlert.PlaySound in MainActivity
        this.soundPlayerAlert = (PlaySoundAlert)context;
    }

    @Override
    public int getCount() {
        return sounds == null ? 0 : sounds.length;
    }

    @Override
    public Object getItem(int i) {
        return sounds[i];
    }

    @Override
    public long getItemId(int i) {
        return 0;
    }

    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {

        SoundExample item = (SoundExample)getItem(i);

        if (view == null) // reuse existing view
            view = context.getLayoutInflater().inflate(R.layout.custom_sound_layout,
                    viewGroup, false);

        // Set the TextView to the name of the sound
        TextView t = (TextView)view.findViewById(R.id.txtName);
        t.setText(item.getSoundName());

        // Set the tag of the button to the sound resource id (uri)
        Button b = (Button)view.findViewById(R.id.play_btn);
        b.setTag(item.getSoundUri());

        // When the button is clicked, play the associated sound
        b.setOnClickListener(this);

        return view;
    }

    @Override
    public void onClick(View view) {
        Button b = (Button) view;
        if (b != null) {
            int soundUri = (int)b.getTag();

            // Notify listener (MainActivity) to play the required sound
            if (soundPlayerAlert != null) {
                soundPlayerAlert.playSound(soundUri);
            }
        }
    }
}

Next create an interface you can implement in your activity to play a sound like this:

public interface PlaySoundAlert {
    public void playSound(int uri);
}

As you can see the Adapter I created above uses this interface to fire off an event to play the required sound.

Your SoundExample class might like something like this:

public class SoundExample {

    private int soundUri;
    private String soundName;

    public String getSoundName() {
        return soundName;
    }

    public void setSoundName(String soundName) {
        this.soundName = soundName;
    }

    public int getSoundUri() {
        return soundUri;
    }

    public void setSoundUri(int soundUri) {
        this.soundUri = soundUri;
    }
}

And to use this inside your Activity or Fragment use the following:

public class MainActivity extends Activity implements PlaySoundAlert {

    ListView lstSounds;
    PlaySoundsAdapter soundsAdapter;
    SoundExample[] mySounds;

    // Media player for playing sounds
    MediaPlayer mp;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        lstSounds = (ListView) findViewById(R.id.soundList);

        // Create sound list & add two SoundExample objects
        mySounds = new SoundExample[2];
        SoundExample s1 = new SoundExample();
        SoundExample s2 = new SoundExample();

        // Set sound one to a beep
        s1.setSoundName("Beep Sound");
        s1.setSoundUri(R.raw.beep);

        // Set sound two to an applause sound
        s2.setSoundName("Applause Sound");
        // NOTE: I am using a sound titled applause.mp3 inside a folder called "raw"
        s2.setSoundUri(R.raw.applause);

        // Add sounds to the list
        mySounds[0] = s1;
        mySounds[1] = s2;

        // Instantiate the adapter and apply to the ListView
        soundsAdapter = new PlaySoundsAdapter(this, mySounds);
        lstSounds.setAdapter(soundsAdapter);
    }

    @Override
    public void playSound(int uri) {
        // Play sound
        mp = MediaPlayer.create(this, uri);
        if (!mp.isPlaying())
            mp.start();
    }
}

And that should be all you need!

Leigh
  • 1,495
  • 2
  • 20
  • 42
  • I have added all you coded to my app.. changed some things that were not let me compile the app.. and finnally compiled it.. BUT, how do I add a new row with text and sound path to the list? – ElAlonnso Jan 16 '15 at 20:03
  • @ElAlonnso see my update. Note I have changed the `SoundExample soundUri` to an int. You will also need to add your sound or media files in a directory called `raw`. – Leigh Jan 16 '15 at 21:30
  • HERE: OK, now it throw me the following errors: (13, 37) error: cannot find symbol class PlaySoundAlert. Error: (47, 5) error: method does not override or implement a method from a supertype. May it be because I have changed some Private Classes to Public because those were send me "error"?.. AND: Button b = view.findViewById(R.id.play_btn); (says Incompatible Types Android.Widget.Button and Android.View.View) – ElAlonnso Jan 17 '15 at 01:38
  • It sounds like you're missing `public interface PlaySoundAlert`. You must make sure your `play_btn` is a `Button` otherwise you will get an incompatible type error. – Leigh Jan 17 '15 at 08:42
  • Change `Button b = view.findViewById(R.id.play_btn);` to `Button b = (Button) view.findViewById(R.id.play_btn);` – Leigh Jan 17 '15 at 09:52
  • Now.. LogCat Error: Unable to start Activity (main) sounds.. on line 37.. I will look up.. AND in my java files there are: sounds, SoundExample and PlaySoundsAdapter classes.. and I had the PlaySoundAlert interface.. but I put deleted it and put into PlaySoundsAdapter.. LATER: If it could help you with helping me.. I will send how I've put all the files in.. TY – ElAlonnso Jan 17 '15 at 17:25
  • Error is here --> Line #37: lstSounds.setAdapter(soundsAdapter); – ElAlonnso Jan 17 '15 at 17:26
  • Ok.. this is the folder with all you write.. (I think it may help you) https://www.dropbox.com/sh/qo2lhjtsbrrdxvi/AABwxjUgoRh79yQx9Ntlop_va?dl=0 – ElAlonnso Jan 17 '15 at 17:33
  • Here is the link for [Classes and the Logcat Error](https://www.dropbox.com/sh/qo2lhjtsbrrdxvi/AABwxjUgoRh79yQx9Ntlop_va?dl=0) I have put in thes folder.. – ElAlonnso Jan 18 '15 at 03:12
  • It looks like your `ListView` might be `null`. Have you initiated your `ListView`? `ListView lstView = view.findViewById(R.id.soundList);`. – Leigh Jan 18 '15 at 11:24
  • Added this:ListView listView = (ListView) findViewById(R.id.soundList); listView.setAdapter(soundsAdapter); Below this: ... mySounds[1] = s2; soundsAdapter = new PlaySoundsAdapter(this, mySounds); lstSounds.setAdapter(soundsAdapter); ... in MAINACTIVITY (sounds.java) But Still The error.... And I dont know realy how to initiate my ListView :/.. – ElAlonnso Jan 18 '15 at 20:05
  • @ElAlonnso I have added a complete working example of what you need. Please see my edit. – Leigh Jan 18 '15 at 20:45
  • Your first and second editions have a bunch of errors at first put.. but THE THIRD is only throwing me one.. in the line: int soundUri = (int)b.getTag(); of PlaySoundsAdapter.. (In android studio).. saying me cannot cast java.lang.object to int :/.. --- I read the code.. and looks great.. but it say me those red words :/// --- – ElAlonnso Jan 18 '15 at 21:07
  • Hmmm strange, I have run this in Android Studio and can confirm it is working. Do you see this error when running or in design time? You may also try replace with `Integer soundUri = (Integer)b.getTag();`. – Leigh Jan 18 '15 at 22:23
  • MAN.. MAN.. MAN.. NOW IT WORKS PERFECTLY!!.. EXACTLY WHAT I WANT.. YOU ARE SO ATTENDED FOR MY QUESTION.. YOU HAVE MY CONGRATULATIONS.. AND SORRY FOR MY ENGLISH BECAUSE I REALLY SPEAK SPANISH.. BUT YOU ARE BIG MAN THANKS YOU.. I WILL PUT YOU IN MY CREDITS PAGE OF MY APP TY!!!! – ElAlonnso Jan 18 '15 at 23:19
  • Ahh.. and.. Change that last error that was Integer soundUri = (Integer)b.getTag(); the solution to your edition.. for help other people too.. :D! – ElAlonnso Jan 18 '15 at 23:20
  • this is freaking awesome! – sirvon Jan 26 '15 at 14:10
0

The solution would be to create a custom ListView object that has both a TextView for displaying the name of the button and an ImageButton. You then add these objects to your ListView by using a custom Adapter. An alternative to the ImageButton is to simply use a regular image and make it Clickable. A great example for creating a ListView that can display custom objects (including how to create the custom Adapter) may be found here: http://www.androidinterview.com/android-custom-listview-with-image-and-text-using-arrayadapter/

Willis
  • 5,308
  • 3
  • 32
  • 61