Azurespot
Azurespot

Reputation: 3152

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>

Upvotes: 1

Views: 2621

Answers (5)

Hassi
Hassi

Reputation: 120

Asked by many, The TextViews in list should not have width match parent.

Even if you set the "Focusable" to false it wont work. Set the TextView Width to wrap_content

<TextView
    android:id="@+id/itemchild"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    ...

Upvotes: 0

Ahsan Idrees
Ahsan Idrees

Reputation: 11

This isn't your case, but I had similar problem with click on a custom layout item. After a hour of looking for solution a found out that I set android:inputType to TextView inside my layout file which was blocking onClick() listener (no idea why)

Don't use android:inputType with TextView.

It worked perfectly for me

Upvotes: 0

Amrit Pal Singh
Amrit Pal Singh

Reputation: 7132

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!

Upvotes: 2

asylume
asylume

Reputation: 544

I think the problem lies in this line:

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

Add log before to verify that method was invoked successfully.

Log.d("TextTab", "onItemLongClick");
if (adapter.getItem(pos) != sampleItem) {
    ...

Upvotes: 0

Deniz
Deniz

Reputation: 12530

Try setting the below tag fro your views inside list item view xml (text_listview_row.xml)

android:focusable="false"

so that list item click will work always perfectly

Upvotes: 0

Related Questions