java – Creating a context menu on clicking an object in a ListView with a custom adapter

Question:

After creating your own adapter and applying it to the ListView, clicking on the item stopped working and the item's context menu stopped opening after a long tap.

package com.vkdocs;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.TextView;

import java.util.ArrayList;


public class DocsAdapter extends BaseAdapter implements AdapterView.OnItemClickListener {
Context ctx;
LayoutInflater lInflayter;
ArrayList<DocsElement> objects;

DocsAdapter(Context context, ArrayList<DocsElement> docs)
{
    ctx = context;
    objects = docs;
    lInflayter = (LayoutInflater) ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}

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

@Override
public Object getItem(int position) {
    return objects.get(position);
}

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

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View view = convertView;
    if(view == null)
    {
        view = lInflayter.inflate(R.layout.item, parent, false);
    }

    DocsElement d = getDoc(position);

    ((TextView) view.findViewById(R.id.tvName)).setText(d.name);

    CheckBox checkDoc = (CheckBox) view.findViewById(R.id.cbBox);

    checkDoc.setOnCheckedChangeListener(myChangeListener);
    checkDoc.setTag(position);
    checkDoc.setChecked(d.box);

    return view;
}

DocsElement getDoc(int position)
{
    return ((DocsElement)getItem(position));
}

ArrayList<DocsElement> getBox()
{
    ArrayList<DocsElement> box = new ArrayList<DocsElement>();
    for(DocsElement d : objects)
    {
        if(d.box)
            box.add(d);
    }
    return box;
}

CompoundButton.OnCheckedChangeListener myChangeListener =
        new CompoundButton.OnCheckedChangeListener() {
    @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        getDoc((Integer) buttonView.getTag()).box = isChecked;
    }
};

@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

}
}

Layout to display the list

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<LinearLayout
    android:id="@+id/linearLayout1"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_marginLeft="5dp"
    android:layout_weight="1"
    android:orientation="vertical">
    <TextView
        android:id="@+id/tvName"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:text=""
        android:textSize="20sp">
    </TextView>
</LinearLayout>

<CheckBox
    android:id="@+id/cbBox"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">
</CheckBox>
</LinearLayout>

Answer:

  1. Hang a listener in the getView adapter:

     view.setOnLongClickListener(...);
  2. The ripple effect animation for custom markup will not turn on by itself. You can connect it with a third-party library

UPD_0:

Create an interface in the adapter, pass it to it through the constructor and call it on long press:

public class DocsAdapter extends BaseAdapter implements 
{
    public interface MyOnLongClick
    {
        public void onClick(View v, int position);
    }

    ...
    MyOnLongClick interface;

    DocsAdapter(Context context, ArrayList<DocsElement> docs, MyOnLongClick interface)
    {
        ...
        this.interface = interface;
    }

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        View view = convertView;
        if(view == null)
        {
            view = lInflayter.inflate(R.layout.item, parent, false);
        }
        view.setOnLongClickListener(new View.OnLongClickListener()
        {
            @Override
            public boolean onLongClick(View v)
            {
                Log.d("TAG", "onLongClick in adapter");
                interface.onClick(v, position);
                return false;
            }
        });
        ...
    }
}

In actviti, implement this interface and pass a reference to it to the adapter when it is created:

public class ActivityMain extends AppCompatActivity implements DocsAdapter.MyOnLongClick
{
    ...
    @Override
    onClick(View v, int position)
    {
        Log.d("Tag", "onClick method from intercace called in activity class for position: "+position);
    }

    @Override
    public void onCreate(Bundle b)
    {
        ...
        DocsAdapter adapter = new DocsAdapter(context, docs, this); 
    }
} 
Scroll to Top