Search code examples
androidandroid-fragmentsandroid-fragmentactivityandroid-listfragment

Buttons within a ListFragment not clickable


I have an Activity that lays out ListFragments side by side (as many as a user wants) in a HorizontalScrollView upon choosing an option in the ActionBar.

Each ListFragment item contains TextViews and a Button. A SimpleAdapter populates data for each item in every ListFragment.

The issue I am facing now is that the buttons in each list item do not respond to clicks. The layout can be summarized as follows: Button inside a ListFragment inside a FragmentActivity, going from the innermost child element to the parent at the root view.

I have spent many hours on this problem and I am unable to arrive at a solution to make the buttons respond to clicks. Some of the approaches I have used include obtaining the button's view and attaching onClickListeners, 2) implementing the OnClickListener interface for the ListFragment. I am also aware of the onInterceptTouchEvent method for a ViewGroup class, however my lack of experience with Android prevents me from arriving at a solution. Any guidance or direction towards solving this problem would be most appreciated.

Here is the code for the ListFragment:

package com.example.androidlistfragmenttest;

import java.util.ArrayList;
import java.util.HashMap;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.SimpleAdapter;


public class MyFragment extends ListFragment {

private ArrayList<HashMap<String,String>> arraylist;


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {

    // Inflate the layout for this fragment

    View view = inflater.inflate(R.layout.fragment_layout, container, false);
    Button button = (Button) view.findViewById(R.id.button);
    button.setOnClickListener(new OnClickListener(){


       //THIS DOES NOT PRINT IN LOGCAT. BUTTON DOES NOT RESPOND TO CLICKS.

        @Override
        public void onClick(View arg0) {
            Log.v("GODZILLA","ATOMIC BREATH");

        }

    });
    return view;
}

@Override
public void onActivityCreated(Bundle savedInstanceState){
    super.onActivityCreated(savedInstanceState);
    arraylist = dataGenerator();
    SimpleAdapter adapter = new SimpleAdapter(getActivity().getApplicationContext(), arraylist, R.layout.fragment_layout,new String[]{"KEY"},new int[]{R.id.text_id});
    setListAdapter(adapter);

}


/*
 * Method to populate an adapter's data list.
 */

public ArrayList<HashMap<String,String>> dataGenerator(){

    HashMap<String,String> hashMap1 = new HashMap<String,String>();
    hashMap1.put("KEY", "A");

    HashMap<String,String> hashMap2 = new HashMap<String,String>();
    hashMap2.put("KEY", "B");

    HashMap<String,String> hashMap3 = new HashMap<String,String>();
    hashMap3.put("KEY", "C");

    HashMap<String,String> hashMap4 = new HashMap<String,String>();
    hashMap4.put("KEY", "D");

    HashMap<String,String> hashMap5 = new HashMap<String,String>();
    hashMap5.put("KEY", "E");

    ArrayList<HashMap<String,String>> arraylist = new ArrayList<HashMap<String,String>>();
    arraylist.add(hashMap1);
    arraylist.add(hashMap2);
    arraylist.add(hashMap3);
    arraylist.add(hashMap4);
    arraylist.add(hashMap5);


    return arraylist;
}

} //End of MyFragment

And this is the code for the Activity containing the Fragment(s):

package com.example.androidlistfragmenttest;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Stack;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.app.NavUtils;
import android.view.Menu;
import android.view.MenuItem;

public class MainActivity extends FragmentActivity {

    private Stack<String> tagStack;
    private Integer last_tag_number;

public MainActivity(){

    last_tag_number = new Integer("0");
    tagStack = new Stack<String>();
}

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

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {

    case R.id.add_fragment:
        addColumn();
        return true;


    case R.id.remove_column:
        removeColumn();
        return true;


    case android.R.id.home:
        // This ID represents the Home or Up button. In the case of this
        // activity, the Up button is shown. Use NavUtils to allow users
        // to navigate up one level in the application structure. For
        // more details, see the Navigation pattern on Android Design:
        //
        // http://developer.android.com/design/patterns/navigation.html#up-vs-back
        //
        NavUtils.navigateUpFromSameTask(this);
        return true;

    }
    return super.onOptionsItemSelected(item);
}

/*
 * This method adds a fragment to the screen    
 */

public void addColumn(){

    FragmentManager fragmentManager = getSupportFragmentManager();
    FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
    MyFragment fragment = new MyFragment();
    fragmentTransaction.add(R.id.fragment_activity, fragment,tagGenerator());
    fragmentTransaction.commit();

}

/*
 * This method removes a fragment from the screen
 */

public void removeColumn(){

    if(tagStack.size() != 0){
        FragmentManager fragmentManager = getSupportFragmentManager();
        Fragment fragment = fragmentManager.findFragmentByTag(tagStack.pop());
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        fragmentTransaction.remove(fragment);
        fragmentTransaction.commit();
    }
}

/*
 * This function generates tags for each fragment that is displayed on the screen
 * The tags pose as unique identifiers for each fragment
 */

public String tagGenerator(){

    Integer tag_number; 

    if(last_tag_number.intValue() == 0){
        tag_number = last_tag_number;   
        int temp = last_tag_number.intValue();
        temp+=1;
        last_tag_number = Integer.valueOf(temp);
    }
    else{
        tag_number = new Integer(last_tag_number.intValue());
        int temp = last_tag_number.intValue();
        temp+=1;
        last_tag_number = Integer.valueOf(temp);
    }
    String tag = tag_number.toString();
    tagStack.push(tag);

    return tag;
}



} //End of MainActivity

As well as the layouts for the FragmentActivity:

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

<HorizontalScrollView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"

>

<LinearLayout  
     android:id="@+id/fragment_activity"
     android:layout_width="fill_parent" 
     android:layout_height = "fill_parent"
     android:orientation = "horizontal"
     android:gravity="center"       
 > 

</LinearLayout>  
</HorizontalScrollView>

And the ListFragment:

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

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="300dp"
    android:layout_height="match_parent"
    android:orientation="vertical" 
    android:layout_weight="1"
    android:layout_margin="5dp"
    android:descendantFocusability="blocksDescendants" >

<ListView android:id="@id/android:list"
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
/> 

<LinearLayout 
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" 
    android:orientation="horizontal" 
    android:layout_gravity="center"  >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/label" 
        android:layout_gravity="start"

    />

    <TextView 
        android:id="@+id/text_id"
        android:layout_width="0dp"
        android:layout_height="wrap_content" 
        android:layout_weight="1"
        android:layout_gravity="end"
    />

</LinearLayout>

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

     <Button
         android:id="@+id/button"
         android:layout_height="wrap_content"
         android:layout_width="wrap_content"
         android:text="@string/button"
         android:layout_margin="2dp"
         android:layout_marginLeft="2dp"
         android:layout_marginRight="2dp"
      />

 </LinearLayout>

</LinearLayout>

Solution

  • The problem is that the ListItem is consuming the click and it is not getting passed to the button below.

    You need to set the list items to inactive and handle the clicks yourself. In your custom Adapter add the following methods to disable the items (They override methods from BaseAdapter):

    @Override
    public boolean areAllItemsEnabled() {
        return false;
    }
    
    @Override
    public boolean isEnabled(int position) {
       return false;
    }
    

    Edit: Here is a related question that may offer a better solution, it depends on your design.