Как реализовать TapTargetView на RecyclerView?

Вот мой fetchData.java (Activity)

      package com.example.expirytracker;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import com.getkeepsafe.taptargetview.TapTarget;
import com.getkeepsafe.taptargetview.TapTargetSequence;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.concurrent.TimeUnit;

public class fetchData extends AppCompatActivity {

    RecyclerView recyclerView;
    ArrayList<model> dataHolder;
    FloatingActionButton addEntry;
    Cursor cursor;
    long expirydaysleft;
    myAdapter.myviewholder myviewholder;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_fetch_data);
        recyclerView = findViewById(R.id.recview);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        addEntry = findViewById(R.id.addEntry);
        cursor = new DBHelper(this).readalldata();
        dataHolder = new ArrayList<>();
        addEntry.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent addEntry = new Intent(fetchData.this, AddItem.class);
                startActivity(addEntry);
            }
        });


        while (cursor.moveToNext()) {
            long itemaddedondate = cursor.getLong(4);
            long expirydatecountingfromitemaddedon = cursor.getLong(3);
            long msDiff = Calendar.getInstance().getTimeInMillis() - itemaddedondate;
            long daysDiffToday = TimeUnit.MILLISECONDS.toDays(msDiff);
            expirydaysleft = (expirydatecountingfromitemaddedon - daysDiffToday);

            model modelobj = new model(cursor.getString(1), cursor.getString(2),expirydaysleft,cursor.getInt(0));
            dataHolder.add(modelobj);
        }
        myAdapter adapter = new myAdapter(dataHolder, fetchData.this,this);
        recyclerView.setAdapter(adapter);
        

        new TapTargetSequence(this)
                .targets(
                        TapTarget.forView(recyclerView.findViewById(R.id.deleteEntry), "Click to Save Data","After filling the above fields, click on the save button to save the data into your list.")
                                .cancelable(false)
                                .outerCircleColor(R.color.red)
                                .transparentTarget(true),

                        TapTarget.forView(recyclerView.findViewById(R.id.editEntry), "Click to get the list of data", "Fetch all the data by clicking on show button. you will be able to delete and modify the data.")
                                .cancelable(false)
                                .outerCircleColor(R.color.red)
                                .transparentTarget(true))
                .listener(new TapTargetSequence.Listener() {
                    @Override
                    public void onSequenceFinish() {
                        Toast.makeText(getApplicationContext(), "TapTargetView Completed", Toast.LENGTH_SHORT).show();

                    }

                    @Override
                    public void onSequenceStep(TapTarget lastTarget, boolean targetClicked) {
                        // Perform action for the current target
                    }

                    @Override
                    public void onSequenceCanceled(TapTarget lastTarget) {
                        // Boo
                    }
                })
                .start();
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable @org.jetbrains.annotations.Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == 1) {
            recreate();
        }
    }
}

myAdapter.java (класс адаптера)

      package com.example.expirytracker;


import android.app.Activity;
import android.app.DatePickerDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.nfc.Tag;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.FragmentManager;
import androidx.recyclerview.widget.RecyclerView;

import org.jetbrains.annotations.NotNull;

import java.sql.Date;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.concurrent.TimeUnit;

import static android.content.ContentValues.TAG;

public class myAdapter extends RecyclerView.Adapter<myAdapter.myviewholder>
{
    ArrayList<model> dataHolder;
    Activity activity;
    DBHelper MyDB;
    int id;
    int mYear, mMonth, mDay;
    DBHelper DB;
    long msDiff, daysDiff;
    long itemaddedon;
    EditText updateditemname,updateddate;
    fetchData fd;
    Context context;

    public myAdapter(ArrayList<model> dataHolder, Activity activity, Context context) {
        this.context = context;
        this.dataHolder = dataHolder;
        this.activity = activity;
    }

    @NonNull
    @Override
    public myviewholder onCreateViewHolder(@NonNull ViewGroup parent, int viewType)
    {
       View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.singlerow,parent,false);

        Log.i(TAG,"OnCreateViewHolder Invoked");
       return  new myviewholder(view);
    }


    @Override
    public void onBindViewHolder(@NonNull @NotNull myAdapter.myviewholder holder, int position)
    {

            holder.ditemname.setText(dataHolder.get(position).getItemname());
            holder.dexpirydate.setText(dataHolder.get(position).getSelecteddate());
            if (dataHolder.get(position).getExpirydate() == 0) {
                holder.dexpirydays.setText("Expiring Today");
            } else if (dataHolder.get(position).getExpirydate() < 0) {
                holder.dexpirydays.setText("Expired.");
            }
            else {
                holder.dexpirydays.setText("Expiring In: " + dataHolder.get(position).getExpirydate() + "Days.");
            }
        holder.ddeleteEntry.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {

                    AlertDialog.Builder builder = new AlertDialog.Builder(v.getContext());
                    builder.setTitle("Confirmation !");
                    builder.setMessage("Are you sure you want to Delete this Entry ?");
                    builder.setIcon(android.R.drawable.ic_menu_delete);
                    builder.setCancelable(false);
                    builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            id = dataHolder.get(position).getId();
                            DBHelper dbHelper = new DBHelper(v.getContext());
                            dbHelper.deleteData(id);
                            dataHolder.remove(position);
                            notifyItemRemoved(position);

                        }
                    });
                    builder.setNegativeButton("No", null);
                    builder.show();
                }
            });

            holder.deditEntry.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent lastData = new Intent(context, updateDetails.class);
                    lastData.putExtra("lastItemName", dataHolder.get(position).getItemname());
                    lastData.putExtra("lastExpiryDate", dataHolder.get(position).getSelecteddate());
                    lastData.putExtra("id", dataHolder.get(position).getId());
                    activity.startActivityForResult(lastData, 1);
                    /*
                    Dialog dialog  = new Dialog(v.getContext());
                    dialog.setContentView(R.layout.customeditalertdialog);
                    dialog.setTitle("Update Details");
                    dialog.getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
                    dialog.setCancelable(false);

                    updateditemname = dialog.findViewById(R.id.updateitemname);
                    updateddate = dialog.findViewById(R.id.updatedDate);
                    Button update = dialog.findViewById(R.id.update);


                    updateddate.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            if (v == updateddate) {

                                // Get Current Date
                                final Calendar c = Calendar.getInstance();
                                mYear = c.get(Calendar.YEAR);
                                mMonth = c.get(Calendar.MONTH);
                                mDay = c.get(Calendar.DAY_OF_MONTH);


                                DatePickerDialog datePickerDialog = new DatePickerDialog(v.getContext(),
                                        new DatePickerDialog.OnDateSetListener() {

                                            @Override
                                            public void onDateSet(DatePicker view, int year,
                                                                  int monthOfYear, int dayOfMonth) {
                                                updateddate.setText(year + "-" + (monthOfYear + 1) + "-" + dayOfMonth);

                                            }
                                        }, mYear, mMonth, mDay);
                                datePickerDialog.show();
                            }
                        }

                    });
                    update.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            DB = new DBHelper(v.getContext());
                            Date date = Date.valueOf(updateddate.getText().toString());
                            msDiff = date.getTime() - Calendar.getInstance().getTimeInMillis();
                            daysDiff = TimeUnit.MILLISECONDS.toDays(msDiff) + 1;
                            String itemname = updateditemname.getText().toString();
                            String expdate = updateddate.getText().toString();
                            itemaddedon = Calendar.getInstance().getTimeInMillis();
                            java.sql.Date sqlDate = java.sql.Date.valueOf(expdate);
                            id = dataHolder.get(position).getId();
                            Boolean update = DB.updateDetails(id, itemname, sqlDate, daysDiff, itemaddedon);
                            if(update==true){

                                Toast.makeText(v.getContext(),
                                        "Details Updated Successfully", Toast.LENGTH_SHORT).show();
                                notifyDataSetChanged();
                               dialog.cancel();

                            }else{
                                Toast.makeText(v.getContext(),
                                        "Details Updation Failed. Please Try Again Later", Toast.LENGTH_SHORT).show();
                                dialog.dismiss();
                            }
                        }
                    });

                    dialog.show(); */
                }

            });

        Log.i(TAG,"OnBindViewHolder Invoked");
    }



    @Override
    public int getItemCount() {
        return dataHolder.size();
    }

    class myviewholder extends RecyclerView.ViewHolder
    {
        TextView ditemname,dexpirydate, dexpirydays;
        Button ddeleteEntry, deditEntry;
        public myviewholder(@NonNull View itemView)
        {
            super(itemView);
            ditemname=itemView.findViewById(R.id.displayitemname);
            dexpirydate=itemView.findViewById(R.id.displaydate);
            dexpirydays=itemView.findViewById(R.id.expiryindays);
            ddeleteEntry = itemView.findViewById(R.id.deleteEntry);
            deditEntry = itemView.findViewById(R.id.editEntry);
        }
    }

}

Singlerow.xml

      <?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_gravity="center_horizontal"
    app:cardUseCompatPadding="true"
    app:cardCornerRadius="6dp"
    android:elevation="4dp"
    android:layout_margin="5dp"
    >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        android:background="@color/cardbg"
        android:orientation="vertical"
        android:padding="12dp">


        <TextView
            android:id="@+id/displayitemname"
            android:layout_width="204dp"
            android:layout_height="wrap_content"
            android:layout_marginTop="3dp"
            android:text="Item Name"
            android:textSize="25sp" />

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

            <TextView
                android:id="@+id/displaydate"
                android:layout_width="204dp"
                android:layout_height="wrap_content"
                android:layout_marginTop="3dp"
                android:text="Expiry Date"
                android:textSize="25sp" />

            <TextView
                android:id="@+id/expiryindays"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginLeft="10dp"
                android:text="TextView"
                android:textColor="#F40F0F" />

        </LinearLayout>

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

            <Button
                android:id="@+id/deleteEntry"
                android:layout_width="170dp"
                android:layout_height="wrap_content"
                android:backgroundTint="#E36D6D"
                android:text="Delete" />
            <Button
                android:id="@+id/editEntry"
                android:layout_width="170dp"
                android:layout_height="wrap_content"
                android:layout_marginLeft="10dp"
                android:backgroundTint="#E36D6D"
                android:text="Edit"/>
        </LinearLayout>

    </LinearLayout>

</androidx.cardview.widget.CardView>

Как реализовать TapTargetView в действии fetchData, которое является recyclerView?

Приведенный выше код не работает, когда не работает. Когда я вызываю это действие fetchdata, оно показывает мне ошибку:

E/AndroidRuntime: FATAL EXCEPTION: основной процесс: com.example.expirytracker, PID: 28859java.lang.RuntimeException: невозможно запустить действие ComponentInfo{com.example.expirytracker/com.example.expirytracker.fetchData}: java.lang.IllegalArgumentException: задано нулевое представление для таргетинга на android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3374) на android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3513) на android.app.servertransaction.LaunchActivityItemctivityItem (LaunchActivityItem.execute. java: 83) на android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) на android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) на android.app.ActivityThread $H.handleMessage (Activity .java: 2109) на android.os.Handler.dispatchMessage(Handler.java:107) на android.os.Looper.loop(Looper.java:214) в android.app.ActivityThread.main (ActivityThread.java:7682) в java.lang.reflect.Method.invoke (собственный метод) в com.android.internal.os.RuntimeInit $ MethodAndArgsCaller.run(RuntimeInit.java:516) в com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950) Вызвано: java.lang.IllegalArgumentException: задано нулевое представление для целевого объекта com.getkeepsafe.taptargetview. ViewTapTarget. (ViewTapTarget.java:31) в com.getkeepsafe.taptargetview.TapTarget.forView(TapTarget.java:175) в com.example.expirytracker.fetchData.onCreate(fetchData.java:62) в android.app.Activity. PerformCreate(Activity.java:7815) в android.app.Activity.performCreate(Activity.java:7804) в android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1318) в android.app.ActivityThread.performLaunchActivity (ActivityThread.java : 3349) в android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3513) на android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83) на android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) на android. .TransactionExecutor.execute(TransactionExecutor.java:95) в android.app.ActivityThread $H.handleMessage (ActivityThread.java:2109) в android.os.Handler.dispatchMessage(Handler.java:107) в android.os.Looper. цикл (Looper.java:214) в android.app.ActivityThread.main (ActivityThread.java:7682) в java.lang.reflect.Method.invoke (собственный метод) в com.android.internal.os.RuntimeInit $ MethodAndArgsCaller. запустить (RuntimeInit.java:516) в com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)servertransaction.LaunchActivityItem.execute (LaunchActivityItem.java:83) в android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) в android.app.servertransaction.TransactionExecutor.execute (TransactionExecutor.execute (TransactionExecutor.execute (TransactionExecutor.exe) .ActivityThread $H.handleMessage (ActivityThread.java:2109) в android.os.Handler.dispatchMessage(Handler.java:107) в android.os.Looper.loop(Looper.java:214) в android.app.ActivityThread. main (ActivityThread.java:7682) в java.lang.reflect.Method.invoke (собственный метод) в com.android.internal.os.RuntimeInit $ MethodAndArgsCaller.run(RuntimeInit.java:516) в com.android.internal. os.ZygoteInit.main (ZygoteInit.java:950)servertransaction.LaunchActivityItem.execute (LaunchActivityItem.java:83) в android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) в android.app.servertransaction.TransactionExecutor.execute (TransactionExecutor.execute (TransactionExecutor.execute (TransactionExecutor.exe) .ActivityThread $H.handleMessage (ActivityThread.java:2109) в android.os.Handler.dispatchMessage(Handler.java:107) в android.os.Looper.loop(Looper.java:214) в android.app.ActivityThread. main (ActivityThread.java:7682) в java.lang.reflect.Method.invoke (собственный метод) в com.android.internal.os.RuntimeInit $ MethodAndArgsCaller.run(RuntimeInit.java:516) в com.android.internal. os.ZygoteInit.main (ZygoteInit.java:950)executeCallbacks (TransactionExecutor.java:135) на android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) на android.app.ActivityThread $H.handleMessage (ActivityThread.java:2109) на android.os.Handler.dispatchMessage(Handler.java:107) в android.os.Looper.loop(Looper.java:214) в android.app.ActivityThread.main (ActivityThread.java:7682) в java.lang.reflect.Method.invoke (собственный метод ) в com.android.internal.os.RuntimeInit $ MethodAndArgsCaller.run(RuntimeInit.java:516) в com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)executeCallbacks (TransactionExecutor.java:135) на android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) на android.app.ActivityThread $H.handleMessage (ActivityThread.java:2109) на android.os.Handler.dispatchMessage(Handler.java:107) в android.os.Looper.loop(Looper.java:214) в android.app.ActivityThread.main (ActivityThread.java:7682) в java.lang.reflect.Method.invoke (собственный метод ) в com.android.internal.os.RuntimeInit $ MethodAndArgsCaller.run(RuntimeInit.java:516) в com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)214) в android.app.ActivityThread.main (ActivityThread.java:7682) в java.lang.reflect.Method.invoke (собственный метод) в com.android.internal.os.RuntimeInit $ MethodAndArgsCaller.run (RuntimeInit.java: 516) на com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)214) в android.app.ActivityThread.main (ActivityThread.java:7682) в java.lang.reflect.Method.invoke (собственный метод) в com.android.internal.os.RuntimeInit $ MethodAndArgsCaller.run (RuntimeInit.java: 516) на com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950) 

0 ответов

Другие вопросы по тегам