androidandroid-listviewonitemlongclicklistener

ListView onItemClickListener works on part of custom row only


I have a custom ListView where each row consists of 3 items, a TextView (title), an ImageView (placeholder icon), and another TextView (content text). I have an OnItemLongClickListener set on the ListView and it is supposed to be that when a user clicks on the item in the ListView (which should be the entire row of 3 items all together as one), then a dialog comes up giving them the option to delete the whole item, which would then delete all 3 parts of that single list item.

But long clicking on the title view and the image do not trigger the listener. Only if the content TextView is long clicked, does the dialog box come up, which then deletes all 3, but clicking anywhere in the row should do that. However it doesn't. I need to find a solution because the user will not know to only click on the content TextView, they should be able to click anywhere.

I have looked on here to find a solution, and have tried adding these lines, but nothing has worked:

android:descendantFocusability="blocksDescendants" added to my ListView's LinearLayout.

android:clickable="false" to my ImageView.

android:focusable="false" and android:focusableInTouchMode="false" to both TextViews.

I don't have anything else to try. Any ideas?

enter image description here

UPDATE

When I added extra lines, like @Amrit suggested (code in his answer), the whole area when long clicked does now bring up the dialog box, but it creates this strange tint on the area I click, but only if I click the title TextView or the ImageView area. Oddly, that 2nd TextView still looks good and produces the dialog box as it should. Not sure how to get rid of this misaligned tint though:

enter image description here

TextTab.java

package org.azurespot.cutecollection.texttab;

import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.Environment;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ListView;

import org.azurespot.R;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;


/**
 * Created by mizu on 2/8/15.
 */
public class TextTab extends Fragment {

    private ArrayList<PoemListItem> poems = new ArrayList<>();
    private ListViewPoemAdapter adapter;
    private ListView listView;
    String[] allSDCardFiles = null;
    StringBuilder text;
    PoemListItem wordsFromFile;
    File[] files;
    PoemListItem sampleItem;


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

        // Inflate the layout for this fragment
        View v = inflater.inflate(R.layout.text_tab, container, false);
        adapter = new ListViewPoemAdapter(getActivity(), poems);
        // Attach the adapter to a ListView
        listView = (ListView) v.findViewById(R.id.text_list_view);
        listView.setAdapter(adapter);

        if(adapter.getCount() == 0) {
            // load contents of SD card
            loadSDCard();
        }

        setupListViewListener();

        return v;

    }

    private void loadSDCard(){

        try {
            // gets directory CuteWords from sd card
            File cuteWordsDir = new File(Environment.getExternalStoragePublicDirectory
                    (Environment.DIRECTORY_DOCUMENTS), "/Cute Words");

            if (!cuteWordsDir.exists()){
                cuteWordsDir.mkdir();
            }

            if (cuteWordsDir.isDirectory()) {
                // lists all files in CuteWords, loads in Files[] array
                files = cuteWordsDir.listFiles();

                for (File singleFile : files) {
                    //Read text from file, put each line into StringBuilder
                    text = new StringBuilder();

                    BufferedReader br = new BufferedReader(new FileReader(singleFile));
                    String line;

                    while ((line = br.readLine()) != null) {
                        text.append(line);
                        text.append('\n');

                        // get full file name with ext. and text in file
                        wordsFromFile = new PoemListItem(singleFile.getName(), text.toString());

                        adapter.add(wordsFromFile);
                        adapter.notifyDataSetChanged();
                    }
                }
            }

            // get number of files in CuteWords directory
            allSDCardFiles =  new String[files.length];

            // create a blank String version of PoemListItem
            sampleItem = new PoemListItem(" ", " ");

            // add the default icon/lines remaining to ArrayList (through adapter),
            // if less than 9 files on SD card
            for (int i = 0; i < (9 - allSDCardFiles.length); i++) {
                adapter.add(sampleItem);
            }
            adapter.notifyDataSetChanged();

        } catch(IOException e){
                e.printStackTrace();
            }
    }

    // so you can edit any of the list items
    private void setupListViewListener() {

        // to delete a list item
        listView.setOnItemLongClickListener(new ListView.OnItemLongClickListener() {
            @Override
            public boolean onItemLongClick(AdapterView<?> aView, View item,
                                                        final int pos, long id) {


                if (adapter.getItem(pos) != sampleItem) {

                    new AlertDialog.Builder(getActivity())
                            .setTitle("Delete")
                            .setMessage("Delete these cute words?")
                            .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
                                public void onClick(DialogInterface dialog, int which) {
                                    // delete from ArrayList first
                                    poems.remove(pos);
                                    adapter.notifyDataSetChanged();

                                    // get file name then delete it
                                    String name = files[pos].getName();
                                    File file = new File(Environment.getExternalStorageDirectory(),
                                            "/Documents/Cute Words/" + name);
                                    file.delete();

                                    // clear list and adapter
                                    poems.clear();
                                    adapter.clear();
                                    adapter.notifyDataSetChanged();

                                    // after each item delete, must refresh load with new arrangement
                                    loadSDCard();

                                }
                            })
                            .setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
                                public void onClick(DialogInterface dialog, int which) {

                                    // do nothing
                                    dialog.cancel();

                                }
                            })
                            .setIcon(android.R.drawable.ic_dialog_alert)
                            .show();

                    }

                return true;
            }
        });

    }
}

ListViewPoemAdapter

package org.azurespot.cutecollection.texttab;

import android.content.Context;
import android.text.InputType;
import android.text.method.ScrollingMovementMethod;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import org.azurespot.R;

import java.util.ArrayList;

/**
 * Created by mizu on 2/8/15.
 */
public class ListViewPoemAdapter extends ArrayAdapter<PoemListItem> {

    private TextView poemText;
    private TextView poemTitle;
    private ImageView poemPlaceholder;


    public ListViewPoemAdapter(Context context, ArrayList<PoemListItem> poems) {
        super(context, 0, poems);

    }

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

        PoemListItem poemListItem = getItem(position);

        if (convertView == null) {
            convertView = LayoutInflater.from(getContext())
                    .inflate(R.layout.text_listview_row, parent, false);
        }

        poemTitle = (TextView) convertView.findViewById(R.id.text_title);
        poemText = (TextView) convertView.findViewById(R.id.text);
        poemPlaceholder = (ImageView)convertView.findViewById(R.id.icon_placeholder_poem);

        poemText.setInputType(InputType.TYPE_CLASS_TEXT |
                              InputType.TYPE_TEXT_FLAG_MULTI_LINE |
                              InputType.TYPE_TEXT_FLAG_CAP_SENTENCES);

        poemText.setMovementMethod(new ScrollingMovementMethod());

        poemPlaceholder.setBackgroundResource(R.drawable.ic_poem_placeholder);
        poemPlaceholder.setScaleType(ImageView.ScaleType.CENTER_CROP);
        poemPlaceholder.setLayoutParams(new LinearLayout.LayoutParams(150, 150));

        poemTitle.setText(poemListItem.getTitle());
        poemText.setText(poemListItem.getPoem());

        return convertView;

    }


}

text_tab.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:descendantFocusability="blocksDescendants"
    android:background="#2198bb">

    <ListView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/text_list_view"
        android:layout_centerHorizontal="true"
        android:layout_margin="10dp"
        android:scrollbarStyle="outsideOverlay"
        android:verticalScrollbarPosition="right"
        android:divider="@null"/>

</LinearLayout>

text_listview_row.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentTop="true"
    android:paddingBottom="20dp">

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

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:clickable="false"
            android:id="@+id/icon_placeholder_poem"
            android:layout_marginRight="15dp"
            android:layout_marginEnd="15dp"/>

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/text_title"
            android:focusable="false"
            android:focusableInTouchMode="false"
            android:textSize="25sp"
            android:textStyle="bold|italic"
            android:hint="Title"
            android:ellipsize="start"/>


    </LinearLayout>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/text"
        android:focusable="false"
        android:focusableInTouchMode="false"
        android:gravity="top"
        android:maxLines="10"
        android:inputType="textMultiLine"
        android:scrollHorizontally="false"
        android:scrollbars="vertical"
        android:textSize="20sp"
        android:ems="10"
        android:textStyle="italic"
        android:hint="Quote or poem, here."
        android:ellipsize="start"/>

    <!--Line in-between the rows-->
    <View
        android:layout_width="fill_parent"
        android:layout_height="2dp"
        android:background="#7e8287"
        android:paddingTop="20dp" />


</LinearLayout>

Solution

  • Set all child views inside listView items to not focusable or clickable.

    android:focusable="false"
    android:clickable="false"
    

    If it is not enough try setting

    android:descendantFocusability="blocksDescendants
    

    to text_listview_row.xml linearlayout &

    android:textIsSelectable="false"
    

    to textview's inside text_listview_row.xml

    UPDATE

    Actually all that I needed was that one line android:descendantFocusability="blocksDescendants" but inside of my LinearLayout parent of the text_listiew_row.xml (not needed in text_tab.xml). Thank you!