5

My Problem:

I have 70 images, and on each image I want to put transparent button in such a way that when user taps on it, it plays a short audio regarding the spot on image. Images are displaying in a ViewPager.

My Solution:

Now what I have in mind is I can create 70 fragments each containing respective image as background and I can assign button on each spot easily and assign actions to those buttons which will play their respective audio.

But

this doesn’t look like a good approach to include 70 fragments in a single app.

So how can I achieve this, and what would be a better approach I can use?

halfer
  • 19,824
  • 17
  • 99
  • 186
Atiq
  • 14,435
  • 6
  • 54
  • 69

5 Answers5

1

We can just have one fragment and create an ArrayList of Map(Button, RelatedAudioFile) data structure for holding buttons and related audio files. ArrayList index represents the page number.

Example: Now lets say we have 3 viewPages. As most of the PagerAdapter index start from "0", let say Page-0 contains 3 buttons, Page-1 contains 1 button, Page-2 contains 2 buttons.

Pseudocode:

class PagerHolder extends Fragment {

//buttons list - here, arrayList index represents page number
//and at each index we have map of buttons (buttons in each of these pages) and the related audio files
private ArrayList<Map<Button, RelatedAudioFile>> pageButtonsList = new ArrayList<>();
//pager view
private ViewPager viewPager;
//pager adapter
private PagerAdapter pagerAdapter;
//current page number -- page in which we are in right now
private int currentpageNumber = 0;

//buttonListener -- one button listener for all the buttons in all the pages.
private View.OnClickListener listener = new View.OnClickListener() {
    @Override
    public void onClick(View buttonView) {
         //here you can play the audio.
         //buttonView -- is the same button-object that was pressed.
        ((RelatedAudioFile)pageButtonsList.get(currentpageNumber).get(buttonView)).play();

    }
};

 @Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    pagerAdapter = new PagerAdapter(getChildFragmentManager());

    //add buttons to the list
    //page 0 buttons
    HashMap<Button, RelatedAudioFile> page0Buttons = new HashMap<>();
    page0Buttons.put(new Button(context), new RelatedAudioFile());
    page0Buttons.put(new Button(context), new RelatedAudioFile());
    page0Buttons.put(new Button(context), new RelatedAudioFile());
    pageButtonsList.add(page0Buttons)

    //Adding page 1 buttons:
    HashMap<Button, RelatedAudioFile> page1Buttons = new HashMap<>();
    page1Buttons.put(new Button(context), new RelatedAudioFile());
    pageButtonsList.add(page1Buttons);

    //Adding page 2 buttons:
    HashMap<Button, RelatedAudioFile> page2Buttons = new HashMap<>();
    page2Buttons.put(new Button(context), new RelatedAudioFile());
    page2Buttons.put(new Button(context), new RelatedAudioFile());
    pageButtonsList.add(page2Buttons);

    for(Map<Button, RelatedAudioFile> pageButtons :pageButtonsList) {
       for(Button button : pageButtons.keySet()) {
           button.setOnClickListener(listener);
        }
    }

}



 @Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.fragment_editor_pager, container, false);

    viewPager = (ViewPager) v.findViewById(R.id.view_pager);
    viewPager.setAdapter(pagerAdapter);

    return v;
}



 private class PagerAdapter extends FragmentPagerAdapter {

    private ButtonFragment buttonFragment;

    private PagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public Fragment getItem(int pageNumber) {
        currentpageNumber = pageNumber;

       //pass the buttons to the fragment so that it can add these buttons to the screen 
        buttonFragment = ButtonFragment.newInstance(pageButtonsList.get(pageNumber).keySet());

        //to add buttons on screen programatically at certain position you can refer here:
        // http://stackoverflow.com/questions/3441475/android-change-absolute-position-of-a-view-programmatically
    }

    //number of pages
    @Override
    public int getCount() {
        return 70;
    }
}
Varini Ramesh
  • 251
  • 1
  • 4
0

You dont have to create 70 fragments. Instead, you could just use one ImageView as follows:

final List<Integer> list = new ArrayList<>();
list.add(R.drawable.img_0);
list.add(R.drawable.img_1);
...
list.add(R.drawable.img_69);

ImageView img = (ImageView)findViewById(R.id.imageView);
img.setBackgroundResource(list.get(yourIndex));
img.setOnClickListener(new OnClickListener());//plays the audio
Mark Shen
  • 346
  • 1
  • 5
  • but I need to include buttons on different spots of each image and when user clicks that spot it plays different short audios, which is different for each spot. – Atiq Apr 30 '16 at 08:31
  • you could play different audios in the OnClickListener after checking yourIndex – Mark Shen Apr 30 '16 at 08:36
0

You don't need to declare 70 fragments, just create one fragment and on that fragment declare global arrays of images and sound. Now when you redirect here at fragment just pass one integer variable in argument. So now you can display the image from array using that integer variable and on button click you can play audio from sound array using same integer number.

Vickyexpert
  • 3,147
  • 5
  • 21
  • 34
  • those images will be inside a `ViewPager`and each image has number of audios, 5 - 10 to play at different coordinates – Atiq May 18 '16 at 13:20
  • Ok, then you need to implement method of ViewPager to display image and that time setTag(position) to ImageView, so on click you can get position by getTag() and play audio from that position. Also you need to declare Array of sounds on viewPager file to access or you can declare it as global at main activity as static and then you can access it as MainActivity.sounds[position] for playing sound. – Vickyexpert May 18 '16 at 13:25
0

Use this custom view pager

import android.content.Context;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;

/**
 * Created by Jinesh on 06-01-2016.
 */
public class CustomViewPager extends ViewPager {
    private boolean enabled;
    public CustomViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.enabled = true;
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (this.enabled) {
            return super.onTouchEvent(event);
        }

        return false;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
/*
        if (this.enabled) {
            return super.onInterceptTouchEvent(event);
        }
*/

        return false;
    }

    public void setPagingEnabled(boolean enabled) {
        this.enabled = enabled;
    }
}

Add this tag to your xml

<Your_package_name.CustomViewPager xmlns:android="http://schemas.android.com/apk/res/android"
            android:id="@+id/vP_asq_Pager"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_weight="1" />

Then extend PagerAdapter

public class HomeAdapter extends PagerAdapter {
        public HomeAdapter(){

        }

        @Override
        public int getCount() {
            return mItemList.size();
        }


        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            LayoutInflater inflater = (LayoutInflater) container.getContext().getSystemService(LAYOUT_INFLATER_SERVICE);
          v = inflater.inflate(R.layout.adapter_surveyquestion_view, null);


         /*do your operations on your views here   
              store the 70 images in arraylist and return the size of the     arraylist in getCount() method of the adapter.show different images each time in
    getView based on the position variable.*/

         (container).addView(v);
         return v;
        }

        @Override
        public boolean isViewFromObject (View view, Object object){
            return view == ((View) object);
        }


        @Override
        public void restoreState (Parcelable arg0, ClassLoader arg1){
        }

        @Override
        public Parcelable saveState () {
            return null;
        }

        @Override
        public void destroyItem (ViewGroup container,int position, Object object){
            container.removeView((View) object);
        }


    }
Jinesh Francis
  • 3,377
  • 3
  • 22
  • 37
0

This is how I would do. Pleas note that this is a single class solution for example purpose, you can separate classes

  • This will keep only 5 fragments at a time
  • Screen is divided into 4 buttons you can set alpha value of buttons and size as per need currently i kept it half transparent for example
  • I am using Glide for image loading to avoid OOM problem because of image loading

What it look like

enter image description here

The Solution :-

package com.example.sample;

import java.util.ArrayList;

import com.bumptech.glide.Glide;

import android.content.Context;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.FrameLayout;
import android.widget.ImageView;

public class MainActivity extends FragmentActivity {

    private static ArrayList<Integer> imageList = new ArrayList<Integer>();

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

        // Load image data
        for (int i = 0; i < 70; i++) {
            imageList.add(R.drawable.ic_launcher);
        }

        if (savedInstanceState == null) {
            getSupportFragmentManager().beginTransaction()
                    .add(R.id.container, new PlaceholderFragment()).commit();
        }
    }

    /**
     * A placeholder fragment containing a simple view.
     */
    public static class PlaceholderFragment extends Fragment {

        public PlaceholderFragment() {
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                Bundle savedInstanceState) {
            View rootView = inflater.inflate(R.layout.fragment_main, container,
                    false);

            ViewPager viewPager = (ViewPager) rootView
                    .findViewById(R.id.image_pager);

            // Limit number of pages that should be retained to either
            // side of the current page
            viewPager.setOffscreenPageLimit(2);

            viewPager.setAdapter(new SongDetailAdapter(getActivity()));

            return rootView;
        }
    }

    public static class SongDetailAdapter extends PagerAdapter {

        Context mContext;
        LayoutInflater mLayoutInflater;

        public SongDetailAdapter(Context context) {
            mContext = context;
            mLayoutInflater = (LayoutInflater) mContext
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        }

        @Override
        public int getCount() {

            return imageList.size();
        }

        @Override
        public boolean isViewFromObject(View view, Object object) {
            return view == ((FrameLayout) object);
        }

        @Override
        public Object instantiateItem(ViewGroup container, final int position) {
            View itemView = mLayoutInflater.inflate(
                    R.layout.image_place_holder, container, false);

            ImageView imageView = (ImageView) itemView
                    .findViewById(R.id.background);

            itemView.findViewById(R.id.button1).setOnClickListener(
                    new OnClickListener() {

                        @Override
                        public void onClick(View v) {
                            playSound(1);

                        }
                    });

            itemView.findViewById(R.id.button2).setOnClickListener(
                    new OnClickListener() {

                        @Override
                        public void onClick(View v) {

                            playSound(2);

                        }
                    });

            itemView.findViewById(R.id.button3).setOnClickListener(
                    new OnClickListener() {

                        @Override
                        public void onClick(View v) {
                            playSound(3);

                        }
                    });

            itemView.findViewById(R.id.button4).setOnClickListener(
                    new OnClickListener() {

                        @Override
                        public void onClick(View v) {
                            playSound(4);

                        }
                    });

            Glide.with(mContext).load("").placeholder(imageList.get(position))
                    .crossFade(300).into(imageView);

            container.addView(itemView);

            return itemView;
        }

        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            container.removeView((FrameLayout) object);
        }

        @Override
        public Object instantiateItem(View arg0, int arg1) {
            // TODO Auto-generated method stub
            return null;
        }

        @Override
        public Parcelable saveState() {
            // TODO Auto-generated method stub
            return null;
        }

        /*
         * Play sound
         */
        private void playSound(int buttonNumber) {

            switch (buttonNumber) {
            case 1: // play sound for Button1
            case 2: // play sound for Button2
            case 3: // play sound for Button3
            case 4: // play sound for Button4
            default: // play sound for Button n

                // Playing default notification here for example
                Uri notification = RingtoneManager
                        .getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
                Ringtone r = RingtoneManager
                        .getRingtone(mContext, notification);
                r.play();
                break;
            }

        }

    }
}

Layouts

Main Activity layout activity_main.xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.sample.MainActivity"
    tools:ignore="MergeRootFrame" />

Main fragment layout fragment_main.xml

<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:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.sample.MainActivity$PlaceholderFragment" >

    <android.support.v4.view.ViewPager
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/image_pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</RelativeLayout>

Image place holder with dummy buttons imae_place_holder.xml

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

    <ImageView
        android:id="@+id/background"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_weight="1.0"
            android:orientation="horizontal" >

            <Button
                android:id="@+id/button1"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_weight="1.0"
                android:alpha=".5"
                android:background="@android:color/white"
                android:text="Button" />

            <Button
                android:id="@+id/button2"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_weight="1.0"
                android:alpha=".5"
                android:background="@android:color/holo_green_light"
                android:text="Button" />
        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_weight="1.0"
            android:orientation="horizontal" >

            <Button
                android:id="@+id/button3"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_weight="1.0"
                android:alpha=".5"
                android:background="@android:color/holo_blue_light"
                android:text="Button" />

            <Button
                android:id="@+id/button4"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_weight="1.0"
                android:alpha=".5"
                android:background="@android:color/holo_red_light"
                android:text="Button" />
        </LinearLayout>
    </LinearLayout>

</FrameLayout>
Hitesh Sahu
  • 41,955
  • 17
  • 205
  • 154