Creating a contextual menu when long pressing item in android

拟墨画扇 提交于 2019-12-23 04:24:31

问题


I am creating a checklist and it allows the user to add new items to the list, I am trying to allow the user to delete an item when they want to. So I am creating a contextual menu using this that comes us when the user long-presses an item in the list. Right now, it recognizes the long-press but nothing happens, so the contextual menu doesn't appear.

Here is my activity page: (ViewTask.java)

package com.example.androidhive;

import java.util.ArrayList;
import java.util.List;

import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

public class ViewTask extends Activity {
    protected TaskerDbHelper db;
    List<Task> list;
    MyAdapter adapt;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_view_task);
        db = new TaskerDbHelper(this);
        list = db.getAllTasks();
        adapt = new MyAdapter(this, R.layout.list_inner_view, list);
        ListView listTask = (ListView) findViewById(R.id.listView1);
        listTask.setAdapter(adapt);
    }

    public void addTaskNow(View v) {
        EditText t = (EditText) findViewById(R.id.editText1);
        String s = t.getText().toString();
        if (s.equalsIgnoreCase("")) {
            Toast.makeText(this, "Enter a goal please!",
                    Toast.LENGTH_LONG);
        } else {
            Task task = new Task(s, 0);
            db.addTask(task);
            Log.d("tasker", "data added");
            t.setText("");
            adapt.add(task);
            adapt.notifyDataSetChanged();
        }

    }
    @Override
    public void onCreateContextMenu(ContextMenu menu, View v,
                                    ContextMenuInfo menuInfo) {
        super.onCreateContextMenu(menu, v, menuInfo);
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.layout.cmenu, menu);
    }

    @Override
    public boolean onContextItemSelected(MenuItem item) {
        AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
        switch (item.getItemId()) {
            case R.id.Delete_Task:
                db.deleteTask(info.id);
                return true;
            default:
                return super.onContextItemSelected(item);
        }
    }

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

    private class MyAdapter extends ArrayAdapter<Task> {

        Context context;
        List<Task> taskList = new ArrayList<Task>();
        int layoutResourceId;

        public MyAdapter(Context context, int layoutResourceId,
                List<Task> objects) {
            super(context, layoutResourceId, objects);
            this.layoutResourceId = layoutResourceId;
            this.taskList = objects;
            this.context = context;
        }

        /**
         * This method will DEFINe what the view inside the list view will
         * finally look like Here we are going to code that the checkbox state
         * is the status of task and check box text is the task name
         */
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            CheckBox chk = null;
            if (convertView == null) {
                LayoutInflater inflater = (LayoutInflater) context
                        .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                convertView = inflater.inflate(R.layout.list_inner_view,
                        parent, false);
                chk = (CheckBox) convertView.findViewById(R.id.chkStatus);
                convertView.setTag(chk);

                chk.setOnClickListener(new View.OnClickListener() {

                    public void onClick(View v) {
                        CheckBox cb = (CheckBox) v;
                        Task changeTask = (Task) cb.getTag();
                        changeTask.setStatus(cb.isChecked() == true ? 1 : 0);
                        db.updateTask(changeTask);
                        if(cb.isChecked())
                          {
                           Toast.makeText(
                             getApplicationContext(),
                             "Goal Accomplished!", Toast.LENGTH_LONG).show();
                          }
                    }

                });
            } else {
                chk = (CheckBox) convertView.getTag();
            }
            Task current = taskList.get(position);
            chk.setText(current.getTaskName());
            chk.setChecked(current.getStatus() == 1 ? true : false);
            chk.setTag(current);
            Log.d("listener", String.valueOf(current.getId()));
            return convertView;
        }

    }

}

Here is the xml page associated to this page:(activity_view_task.xml)

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#DE8126"
    android:orientation="vertical" >

    <!-- Header Start -->
    <LinearLayout
        android:id="@+id/header"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:background="@layout/header_gradient"
        android:orientation="vertical"
        android:paddingBottom="5dip"
        android:paddingTop="5dip" >

                <!-- Logo Start -->
        <ImageView
            android:id="@+id/logoButton"
            android:layout_width="match_parent"
            android:layout_height="132dp"
            android:src="@drawable/logo" />
                <!-- Logo Ends -->
    </LinearLayout>
             <!-- Header End -->

             <!-- Goals Title Start -->
      <LinearLayout 
          android:id="@+id/goalsTitle"
          android:layout_width="match_parent"
          android:layout_height="80dp"
          android:paddingTop="5dip"
          android:paddingBottom="5dip">

          <TextView 
              android:id="@+id/gTitle"
              android:layout_width="fill_parent"
              android:layout_height="fill_parent"
              android:text="My Goals"
              android:textSize="50sp"
              android:textScaleX="1.5"
              android:textStyle="bold"
              android:gravity="center"/>
      </LinearLayout>
            <!-- Goals Title End -->

<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"
    tools:context=".ViewTask" >

    <EditText
        android:id="@+id/editText1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:ems="10" >

        <requestFocus />
    </EditText>


    <Button
       android:id="@+id/button1"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:layout_alignParentRight="true"
       android:layout_alignParentTop="true"
       android:layout_marginRight="14dp"
       android:text="@string/Save"
       android:onClick="addTaskNow"/>


    <ListView
        android:id="@+id/listView1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_below="@+id/button1" >
    </ListView>
</RelativeLayout>
</LinearLayout>

And here is the menu itself: (cmenu.xml)

<?xml version="1.0" encoding="UTF-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/Edit_Task"></item>
    <item android:id="@+id/Delete_Task"></item>
</menu>

Thanks you for the responses, now I cannot get the item to actually be deleted.

here is my database helper page:(TaskerDbHelper.java)

package com.example.androidhive;

import java.util.ArrayList;
import java.util.List;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;


public class TaskerDbHelper extends SQLiteOpenHelper{
    private static final int DATABASE_VERSION = 1;

    // Database Name
    private static final String DATABASE_NAME = "taskerManager";

    // tasks table name
    private static final String TABLE_TASKS = "tasks";

    // tasks Table Columns names
    private static final String KEY_ID = "id";
    private static final String KEY_TASKNAME = "taskName";
    private static final String KEY_STATUS = "status";

    public TaskerDbHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {

        String sql = "CREATE TABLE IF NOT EXISTS " + TABLE_TASKS + " ( "
                + KEY_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
                + KEY_TASKNAME+ " TEXT, "
                + KEY_STATUS + " INTEGER)";
        db.execSQL(sql);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldV, int newV) {
         // Drop older table if existed
        db.execSQL("DROP TABLE IF EXISTS " + TABLE_TASKS);
        // Create tables again
        onCreate(db);
    }

    public void addTask(Task task) {
        SQLiteDatabase db = this.getWritableDatabase();

        ContentValues values = new ContentValues();
        values.put(KEY_TASKNAME, task.getTaskName()); // task name
         // status of task- can be 0 for not done and 1 for done
        values.put(KEY_STATUS, task.getStatus());

        // Inserting Row
        db.insert(TABLE_TASKS, null, values);
        db.close(); // Closing database connection
    }
    public boolean deleteTask(long task) 
    {
        SQLiteDatabase db = this.getWritableDatabase();
        return db.delete(TABLE_TASKS, KEY_TASKNAME + "=" + task, null) > 0;
    }

    public List<Task> getAllTasks() {
        List<Task> taskList = new ArrayList<Task>();
        // Select All Query
        String selectQuery = "SELECT  * FROM " + TABLE_TASKS;
        SQLiteDatabase db = this.getWritableDatabase();
        Cursor cursor = db.rawQuery(selectQuery, null);
        // looping through all rows and adding to list
        if (cursor.moveToFirst()) {
            do {
                Task task = new Task();
                task.setId(cursor.getInt(0));
                task.setTaskName(cursor.getString(1));
                task.setStatus(cursor.getInt(2));
                // Adding contact to list
                taskList.add(task);
            } while (cursor.moveToNext());
        }
        // return task list
        return taskList;
    }

    public void updateTask(Task task) {
        // updating row
        SQLiteDatabase db = this.getWritableDatabase();
        ContentValues values = new ContentValues();
        values.put(KEY_TASKNAME, task.getTaskName());
        values.put(KEY_STATUS, task.getStatus());
        db.update(TABLE_TASKS, values, KEY_ID + " = ?",new String[] {String.valueOf(task.getId())});
        db.close();
    }

}

That file above contains my deleteTask().


回答1:


I don't see registerForContextMenu() anywhere. This is necessary for the list to actually know that it has a contextmenu.

  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_view_task);
      db = new TaskerDbHelper(this);
      list = db.getAllTasks();
      adapt = new MyAdapter(this, R.layout.list_inner_view, list);
      ListView listTask = (ListView) findViewById(R.id.listView1);
      listTask.setAdapter(adapt);
      registerForContextMenu(listTask); // <-- Register!
  }

In addition you should put a String value in your menu xml file. Obviously it is better to refer to your string xml file for the actual string.

<item
    android:id="@+id/Edit_Task"
    android:title="Edit">
</item>
<item
    android:id="@+id/Delete_Task"
    android:title="Delete">
</item>

Concerning the delete task: To delete your task from the sql database you need some kind of identifier. As far as I can tell, you have only a task name and a status integer. If you allow tasks to have the same name, this cannot be used as an unique identifier. Perhaps you should add that to your Task class. You can then use this to find and remove the specific task in your database. (Your info.id will not work, because it is merely the identifier of the view) You can use info.position to retrieve the position of the Task in taskList, or more specifically, the current list in the adapter.

    case R.id.Delete_Task:
         Task task = list.get(info.position);                
         if (db.deleteTask(task.getUniqueIdentifier())) { // <-- Determine the unique id
             list.Remove(info.position);
             listTask.invalidate();
             return true;
         }
         return false;

I'm not sure whether invalidate() will do the trick. But give it a try. You could also give the adapter the new list and call notifyDataSetChanged() as you do for the addTaskNow().




回答2:


You need to add this line to your onCreate method

registerForContextMenu(listTask);

Your onCreateContextMenu() needs to look like this

@Override
public void onCreateContextMenu(ContextMenu menu, View v,
        ContextMenuInfo menuInfo) {

    if (v.getId() == R.id.listView1) {  //YOUR VIEW THAT IS ATTACHED TO LISTASK

        AdapterView.AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;

        menu.setHeaderTitle("Options");
        String[] menuItems = { "Option1", "Option2", "Option3", "Option4"} };
        for (int i = 0; i < menuItems.length; i++) {
            menu.add(Menu.NONE, i, i, menuItems[i]);
        }

    }
}

and finally your OnContextMenuItemSelected()

@Override
public boolean onContextItemSelected(android.view.MenuItem item) {

    AdapterView.AdapterContextMenuInfo info = (AdapterContextMenuInfo) item
            .getMenuInfo();
    menuItemIndex = item.getItemId();

    String[] menuItems = { "Option 1, Option 2, Option 3" };
    String menuItemName = menuItems[menuItemIndex];




    return true;
}


来源:https://stackoverflow.com/questions/16471764/creating-a-contextual-menu-when-long-pressing-item-in-android

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!