[Android 9.0 Pie Java] Implementieren Sie horizontales Wischen → Dialogfeldanzeige → Löschen in der Chat-App

Umgebung

Android9.0 Pie Java

Einführung

Ich habe kürzlich eine Chat-App auf Android Java erstellt und das Löschen von Chatlisten im LINE-Stil implementiert. Es gibt einige Artikel über die Listenanzeige- und Löschfunktion von RecyclerView.

Horizontal wischen → Dialogfeld anzeigen → Löschen MainActivity + Konfiguration mehrerer Fragmente

Ich konnte das Implementierungsbeispiel im japanischen Artikel nicht finden, daher werde ich es weitergeben. (Ich bin misstrauisch, wenn es sich um die beste Vorgehensweise handelt. Verwenden Sie sie daher bitte als Referenz. Sie können gerne darauf hinweisen!)

Sie können so implementieren 243e5a5ccb079ad0d385004d69a930ba.gif

URL des fertigen Produkts

Der Inhalt ist sehr lang. Wenn Sie das fertige Produkt nicht erhalten können, klicken Sie bitte hier. https://github.com/yuta-matsumoto/chat

Verzeichnisaufbau

Lassen Sie Build- und Manifestdateien weg

Chat  ├app/src/main/       ├java/       │ └com.example.chat/       │         ├fragments/       │         │    ├BaseFragment.java       │         │    ├ChatListFragment.java       │         │    └DeleteChatFragment.java       │         ├helpers/       │         │    ├ChatListAdapter.java       │         │    ├ViewHolder.java       │         │    └SwipeHelper.java       │         ├models/       │         │    ├ChatRowData.java       │         │    └DeleteChatRow.java       │         └MainAcitivity.java       ├res/       │ ├drawable/

  1. │ └ sample1.png (unten weggelassen)       │ ├layout/       │ │   ├activity_main.xml       │ │   ├chat_list_row.xml       │ │   └fragment_chat_list.xml       │ └values/       │     ├colors.xml       │     ├strings.xml       │     └styles.xml

Code

Abhängigkeiten

build.gradle


dependencies {
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    implementation 'androidx.legacy:legacy-support-v4:1.0.0'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
    implementation 'androidx.recyclerview:recyclerview:1.1.0' //Nachtrag
    implementation 'androidx.cardview:cardview:1.0.0' //Nachtrag
}

Activity MainActivity lädt nur Fragment. Fragment erbt die Basisklasse aller Fragmente namens BaseFragment, um "MainActivity + mehrere Fragmentkonfigurationen" zu realisieren.

Ich verweise auf die folgenden Artikel. https://www.slideshare.net/olrandir/android-the-single-activity-multiple-fragments-pattern-one-activity-to-rule-them-all

MainActivity.java


package com.example.chat;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;

import com.example.chat.fragments.BaseFragment;
import com.example.chat.fragments.ChatListFragment;

public class MainActivity extends AppCompatActivity {
    //Fragmentbasis
    private BaseFragment fragment;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //Stellen Sie das Fragment der Chat-Liste zum ersten Mal ein
        if (fragment == null) {
            fragment = new ChatListFragment();
        }
        // main_Setzen Sie Fragment auf Aktivität
        getSupportFragmentManager().beginTransaction()
                .replace(R.id.mainContainer, fragment)
                .commit();
    }
}

Fragment

Dies ist das Basisfragment. Ich habe es diesmal nicht aufgenommen, aber es ist praktisch, den Ereignis-Listener der allgemeinen Schaltfläche in BaseFragment aufzunehmen, da er kompakt sein wird.

BaseFragment.java


package com.example.chat.fragments;

import android.os.Bundle;
import androidx.fragment.app.Fragment;

/**
 *Basisfragment
 */
public abstract class BaseFragment extends Fragment {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }
}

Fragment des Chatlistenbildschirms.

ChatListFragment.java


package com.example.chat.fragments;

import android.graphics.Color;
import android.os.Bundle;

import androidx.fragment.app.FragmentManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.example.chat.models.DeleteChatRowData;
import com.example.chat.helpers.ChatListAdapter;
import com.example.chat.models.ChatRowData;
import com.example.chat.R;
import com.example.chat.helpers.SwipeHelper;

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

/**
 *Fragment für den Chatlistenbildschirm
 */
public class ChatListFragment extends BaseFragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_chat_list, container, false);
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        RecyclerView rv = view.findViewById(R.id.recyclerView);

        //Chatlistendatenliste
        final List list = getChatList();
        //Anzahl der Elemente in der Datenliste der Chatliste
        final int itemCount = list.size();

        //Chatlistenadapter
        final ChatListAdapter adapter = new ChatListAdapter(list) {
            @Override
            public void onItemClick(View view, int pos, List<ChatRowData> list) {
                //Der Prozess beim Klicken auf eine Zeile wurde hinzugefügt
            }
        };

        LinearLayoutManager llm = new LinearLayoutManager(getContext());

        rv.setHasFixedSize(true);

        rv.setLayoutManager(llm);

        rv.setAdapter(adapter);

        //Swipe implementieren
        SwipeHelper swipeHelper = new SwipeHelper(getContext(), rv) {
            @Override
            public void instantiateUnderlayButton(RecyclerView.ViewHolder viewHolder, List<UnderlayButton> underlayButtons) {
                underlayButtons.add(new SwipeHelper.UnderlayButton(
                        getResources().getString(R.string.chat_list_delete_button_label),
                        0,
                        Color.parseColor(getResources().getString(R.string.chat_list_delete_button_color)),
                        new SwipeHelper.UnderlayButtonClickListener() {
                            @Override
                            public void onClick(int pos) {
                                FragmentManager fragmentManager = getFragmentManager();
                                DeleteChatRowFragment fragment = new DeleteChatRowFragment();
                                //Legen Sie die zu löschenden Zeilendaten im Löschdialogfragment fest
                                DeleteChatRowData deleteChatRowData = new DeleteChatRowData();
                                deleteChatRowData.setList(list);
                                deleteChatRowData.setAdapter(adapter);
                                deleteChatRowData.setPosition(pos);
                                deleteChatRowData.setItemCount(itemCount);

                                //Daten mit Bundle weitergeben
                                Bundle bundle = new Bundle();
                                bundle.putSerializable(getResources().getString(R.string.delete_dialog_list_tag), deleteChatRowData);
                                fragment.setArguments(bundle);

                                //Dialoganzeige
                                fragment.show(fragmentManager, "delete chat list");
                            }
                        }
                ));
            }
        };
    }

    /**
     *Generierung von Chatdaten-Testdaten
     */
    private List<ChatRowData> getChatList() {
        List<ChatRowData> list = new ArrayList<>();

        ChatRowData data1 = new ChatRowData();
        data1.setName("Taro Tanaka");
        data1.setText("Hallo");
        data1.setMessageDateTime("2020/6/09 13:00");
        data1.setProfileImageId(R.drawable.sample1);
        list.add(data1);

        ChatRowData data2 = new ChatRowData();
        data2.setName("Shigeru Sato");
        data2.setText("Guten Morgen!");
        data2.setMessageDateTime("2020/6/08 8:10");
        data2.setProfileImageId(R.drawable.sample2);
        list.add(data2);

        ChatRowData data3 = new ChatRowData();
        data3.setName("taro");
        data3.setText("Wie spät ist es?");
        data3.setMessageDateTime("2020/6/07 20:09");
        data3.setProfileImageId(R.drawable.sample3);
        list.add(data3);

        ChatRowData data4 = new ChatRowData();
        data4.setName("hanako");
        data4.setText("Bitte leihen Sie mir ein Lehrbuch");
        data4.setMessageDateTime("2020/6/06 07:00");
        data4.setProfileImageId(R.drawable.sample4);
        list.add(data4);

        ChatRowData data5 = new ChatRowData();
        data5.setName("Tanaka");
        data5.setText("Unmöglich");
        data5.setMessageDateTime("2020/6/06 01:05");
        data5.setProfileImageId(R.drawable.sample5);
        list.add(data5);

        ChatRowData data6 = new ChatRowData();
        data6.setName("Kobayashi");
        data6.setText("OK");
        data6.setMessageDateTime("2020/6/05 14:22");
        data6.setProfileImageId(R.drawable.sample6);
        list.add(data6);

        ChatRowData data7 = new ChatRowData();
        data7.setName("Petagini");
        data7.setText("Ich will nach Hause gehen");
        data7.setMessageDateTime("2020/6/05 13:00");
        data7.setProfileImageId(R.drawable.sample7);
        list.add(data7);

        ChatRowData data8 = new ChatRowData();
        data8.setName("Hayato");
        data8.setText("Lass uns den Film sehen, Senior!");
        data8.setMessageDateTime("2020/6/04 21:50");
        data8.setProfileImageId(R.drawable.sample8);
        list.add(data8);

        ChatRowData data9 = new ChatRowData();
        data9.setName("Tom");
        data9.setText("lol");
        data9.setMessageDateTime("2020/5/30 2:30");
        data9.setProfileImageId(R.drawable.sample9);
        list.add(data9);

        ChatRowData data10 = new ChatRowData();
        data10.setName("y.matsumoto");
        data10.setText("Ich habs gemacht");
        data10.setMessageDateTime("2020/5/29 4:00");
        data10.setProfileImageId(R.drawable.sample10);
        list.add(data10);

        return list;
    }
}

Fragment des Löschdialogs.

DeleteChatRowFragment.java


package com.example.chat.fragments;

import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.Gravity;
import android.widget.TextView;

import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.DialogFragment;
import androidx.recyclerview.widget.RecyclerView;

import com.example.chat.R;
import com.example.chat.models.DeleteChatRowData;

import java.util.List;

/**
 *Fragment für Löschdialog
 */
public class DeleteChatRowFragment extends DialogFragment {
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        // setCancelable(false)Wird nicht geschlossen, auch wenn Sie außerhalb des Dialogfelds mit drücken
        this.setCancelable(false);
        TextView title = new TextView(getContext());
        title.setText(getResources().getString(R.string.delete_dialog_message));
        title.setPadding(10, 50, 10, 10);
        title.setGravity(Gravity.CENTER);

        return new AlertDialog.Builder(getActivity())
                .setCustomTitle(title)
                //Wenn OK gedrückt wird
                .setPositiveButton("OK", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        //Prozess löschen
                        Bundle bundle = getArguments();
                        DeleteChatRowData deleteChatRowData =
                                (DeleteChatRowData) bundle.getSerializable(getResources().getString(R.string.delete_dialog_list_tag));
                        List list = deleteChatRowData.getList();
                        RecyclerView.Adapter adapter = deleteChatRowData.getAdapter();
                        int pos = deleteChatRowData.getPosition();
                        int itemCount = deleteChatRowData.getItemCount();
                        //Das Element der Positionsreihenfolge der gedrückten Zeile wurde aus der Liste der Chatlisten entfernt
                        list.remove(pos);
                        //Benachrichtigen Sie den Adapter, dass das Element gelöscht wurde
                        deleteChatRowData.getAdapter().notifyItemRemoved(pos);
                        //Benachrichtigen Sie, dass sich die Chat-Liste geändert hat, und binden Sie erneut
                        adapter.notifyItemRangeChanged(pos, itemCount);
                    }
                })
                //Wenn Abbrechen gedrückt wird
                .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        //Wischen Sie zurück
                        Bundle bundle = getArguments();
                        DeleteChatRowData deleteChatRowData =
                                (DeleteChatRowData) bundle.getSerializable(getResources().getString(R.string.delete_dialog_list_tag));
                        RecyclerView.Adapter adapter = deleteChatRowData.getAdapter();
                        int pos = deleteChatRowData.getPosition();

                        //Wischen Sie zurück
                        adapter.notifyItemChanged(pos);
                    }
                })
                .create();
    }

    //Beenden Sie nicht, wenn die App in den Hintergrund tritt
    @Override
    public void onPause() {
        super.onPause();
        dismiss();
    }
}

Helfer

Wird in der Chatlistenanzeige verwendet.

ChatListAdapter.java


package com.example.chat.helpers;

import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;

import androidx.recyclerview.widget.RecyclerView;

import com.example.chat.R;
import com.example.chat.models.ChatRowData;

import java.util.List;

/**
 *Adapterklasse zum Anzeigen der Chat-Liste
 */
public class ChatListAdapter extends RecyclerView.Adapter<ViewHolder> {
    private List<ChatRowData> list;

    public ChatListAdapter(List<ChatRowData> list) {
        this.list = list;
    }

    /**
     *Erstellen Sie ViewHolder für die Chat-Liste
     */
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        //Laden Sie eine Layoutzeile in View
        View inflate = LayoutInflater.from(parent.getContext()).inflate(R.layout.chat_list_row, parent, false);
        final ViewHolder vh = new ViewHolder(inflate);

        //Registrieren Sie Click Listener
        inflate.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //Ermitteln Sie die Position der angeklickten Zeile
                int position = vh.getAdapterPosition();
                //Da der Vorgang von View von Activity oder Fragment ausgeführt werden muss, wird die eigentliche Verarbeitung nicht geschrieben.
                onItemClick(v, position, list);
            }
        });

        //Registrieren Sie den Touch Listener
        inflate.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                //Da der Vorgang von View von Activity oder Fragment ausgeführt werden muss, wird die eigentliche Verarbeitung nicht geschrieben.
                return onItemTouch(v);
            }
        });
        return vh;
    }

    /**
     *Binden Sie die Daten der Chat-Listenliste an ViewHolder
     */
    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        String messageDateTime = list.get(position).getMessageDateTime();
        holder.nameView.setText(list.get(position).getName());
        holder.textView.setText(list.get(position).getText());
        holder.timeView.setText(messageDateTime);
        holder.profileView.setImageResource(list.get(position).getProfileImageId());
    }

    /**
     *Legen Sie die Anzahl der Elemente in der Chatlistenliste fest
     */
    @Override
    public int getItemCount() {
        return list.size();
    }

    /**
     *Mit ChatListFragment überschreiben und verarbeiten
     */
    public void onItemClick(View view, int pos, List<ChatRowData> list) {
        ;
    }

    /**
     *Mit ChatListFragment überschreiben und verarbeiten
     */
    public boolean onItemTouch(View view) {
        return false;
    }
}

ViewHolder.java


package com.example.chat.helpers;

import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.recyclerview.widget.RecyclerView;

import com.example.chat.R;

/**
 *ViewHolder-Klasse
 *Definieren Sie die Ansicht, aus der eine Zeile besteht
 */
public class ViewHolder extends RecyclerView.ViewHolder {
    public TextView nameView;
    public TextView textView;
    public TextView timeView;
    public ImageView profileView;

    public ViewHolder(View itemView) {
        super(itemView);
        nameView = itemView.findViewById(R.id.name);
        textView = itemView.findViewById(R.id.text);
        timeView = itemView.findViewById(R.id.time);
        profileView = itemView.findViewById(R.id.profileImage);
    }
}

Wird für horizontale Wischbewegungen verwendet. Ich habe ziemlich viel auf diesen Artikel verwiesen.

https://www.it-swarm.dev/ja/android/%E3%82%B9%E3%83%AF%E3%82%A4%E3%83%97%E3%81%AErecyclerview-itemtouchhelper%E3%83%9C%E3%82%BF%E3%83%B3/833735822/amp/

SwipeHelper.java


package com.example.chat.helpers;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.RectF;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;

import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.RecyclerView;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;

/**
 *Swipe Helfer Klasse
 */
public abstract class SwipeHelper extends ItemTouchHelper.SimpleCallback {
    //Löschen Sie die Tastenbreite, die durch Wischen angezeigt wird
    public static final int BUTTON_WIDTH = 230;
    private RecyclerView recyclerView;
    private List<UnderlayButton> buttons;
    private GestureDetector gestureDetector;
    private int swipedPos = -1;
    private float swipeThreshold = 0.5f;
    private Map<Integer, List<UnderlayButton>> buttonsBuffer;
    private Queue<Integer> recoverQueue;

    private GestureDetector.SimpleOnGestureListener gestureListener = new GestureDetector.SimpleOnGestureListener() {
        @Override
        public boolean onSingleTapConfirmed(MotionEvent e) {
            for (UnderlayButton button : buttons) {
                if (button.onClick(e.getX(), e.getY()))
                    break;
            }

            return true;
        }
    };

    private View.OnTouchListener onTouchListener = new View.OnTouchListener() {
        @Override
        public boolean onTouch(View view, MotionEvent e) {
            if (swipedPos < 0) return false;
            Point point = new Point((int) e.getRawX(), (int) e.getRawY());

            RecyclerView.ViewHolder swipedViewHolder = recyclerView.findViewHolderForAdapterPosition(swipedPos);
            View swipedItem = swipedViewHolder.itemView;
            Rect rect = new Rect();
            swipedItem.getGlobalVisibleRect(rect);

            if (e.getAction() == MotionEvent.ACTION_DOWN
                    || e.getAction() == MotionEvent.ACTION_UP
                    || e.getAction() == MotionEvent.ACTION_MOVE) {
                if (rect.top < point.y && rect.bottom > point.y)
                    gestureDetector.onTouchEvent(e);
                else {
                    recoverQueue.add(swipedPos);
                    swipedPos = -1;
                    recoverSwipedItem();
                }
            }
            return false;
        }
    };

    public SwipeHelper(Context context, RecyclerView recyclerView) {
        super(0, ItemTouchHelper.LEFT);
        this.recyclerView = recyclerView;
        this.buttons = new ArrayList<>();
        this.gestureDetector = new GestureDetector(context, gestureListener);
        this.recyclerView.setOnTouchListener(onTouchListener);
        buttonsBuffer = new HashMap<>();
        recoverQueue = new LinkedList<Integer>() {
            @Override
            public boolean add(Integer o) {
                if (contains(o))
                    return false;
                else
                    return super.add(o);
            }
        };

        attachSwipe();
    }


    @Override
    public boolean onMove(RecyclerView recyclerView,
                          RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
        return false;
    }

    @Override
    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
        int pos = viewHolder.getAdapterPosition();

        if (swipedPos != pos)
            recoverQueue.add(swipedPos);

        swipedPos = pos;

        if (buttonsBuffer.containsKey(swipedPos))
            buttons = buttonsBuffer.get(swipedPos);
        else
            buttons.clear();

        buttonsBuffer.clear();
        swipeThreshold = 0.5f * buttons.size() * BUTTON_WIDTH;
        recoverSwipedItem();
    }

    @Override
    public float getSwipeThreshold(RecyclerView.ViewHolder viewHolder) {
        return swipeThreshold;
    }

    @Override
    public float getSwipeEscapeVelocity(float defaultValue) {
        return 0.1f * defaultValue;
    }

    @Override
    public float getSwipeVelocityThreshold(float defaultValue) {
        return 5.0f * defaultValue;
    }

    @Override
    public void onChildDraw(Canvas c, RecyclerView recyclerView,
                            RecyclerView.ViewHolder viewHolder,
                            float dX, float dY, int actionState, boolean isCurrentlyActive) {
        int pos = viewHolder.getAdapterPosition();
        float translationX = dX;
        View itemView = viewHolder.itemView;

        if (pos < 0) {
            swipedPos = pos;
            return;
        }

        if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
            if (dX < 0) {
                List<UnderlayButton> buffer = new ArrayList<>();

                if (!buttonsBuffer.containsKey(pos)) {
                    instantiateUnderlayButton(viewHolder, buffer);
                    buttonsBuffer.put(pos, buffer);
                } else {
                    buffer = buttonsBuffer.get(pos);
                }

                translationX = dX * buffer.size() * BUTTON_WIDTH / itemView.getWidth();
                drawButtons(c, itemView, buffer, pos, translationX);
            }
        }

        super.onChildDraw(c, recyclerView, viewHolder, translationX, dY, actionState, isCurrentlyActive);
    }

    private synchronized void recoverSwipedItem() {
        while (!recoverQueue.isEmpty()) {
            int pos = recoverQueue.poll();
            if (pos > -1) {
                recyclerView.getAdapter().notifyItemChanged(pos);
            }
        }
    }

    private void drawButtons(Canvas c, View itemView, List<UnderlayButton> buffer, int pos, float dX) {
        float right = itemView.getRight();
        float dButtonWidth = (-1) * dX / buffer.size();

        for (UnderlayButton button : buffer) {
            float left = right - dButtonWidth;
            button.onDraw(
                    c,
                    new RectF(
                            left,
                            itemView.getTop(),
                            right,
                            itemView.getBottom()
                    ),
                    pos
            );

            right = left;
        }
    }

    public void attachSwipe() {
        ItemTouchHelper itemTouchHelper = new ItemTouchHelper(this);
        itemTouchHelper.attachToRecyclerView(recyclerView);
    }

    public abstract void instantiateUnderlayButton(RecyclerView.ViewHolder viewHolder, List<UnderlayButton> underlayButtons);

    public static class UnderlayButton {
        private String text;
        private int imageResId;
        private int color;
        private int pos;
        private RectF clickRegion;
        private UnderlayButtonClickListener clickListener;

        public UnderlayButton(String text, int imageResId, int color, UnderlayButtonClickListener clickListener) {
            this.text = text;
            this.imageResId = imageResId;
            this.color = color;
            this.clickListener = clickListener;
        }

        public boolean onClick(float x, float y) {
            if (clickRegion != null && clickRegion.contains(x, y)) {
                clickListener.onClick(pos);
                return true;
            }

            return false;
        }

        public void onDraw(Canvas c, RectF rect, int pos) {
            Paint p = new Paint();

            //Hintergrundfarbsatz
            p.setColor(color);
            c.drawRect(rect, p);

            //Textfarbsatz LÖSCHEN
            p.setColor(Color.WHITE);
            p.setTextSize(50);

            Rect r = new Rect();
            float cHeight = rect.height();
            float cWidth = rect.width();
            p.setTextAlign(Paint.Align.LEFT);
            p.getTextBounds(text, 0, text.length(), r);
            float x = cWidth / 2f - r.width() / 2f - r.left;
            float y = cHeight / 2f + r.height() / 2f - r.bottom;
            c.drawText(text, rect.left + x, rect.top + y, p);

            clickRegion = rect;
            this.pos = pos;
        }
    }

    public interface UnderlayButtonClickListener {
        void onClick(int pos);
    }
}

Modell-

Füllen Sie die Daten für eine Zeile der Chat-Liste.

ChatRowData.java


package com.example.chat.models;

/**
 *Eine Zeile der Datenmodellklasse
 */
public class ChatRowData {
    private String name;
    private String text;
    private String messageDateTime;
    private int profileImageId;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public String getMessageDateTime() {
        return messageDateTime;
    }

    public void setMessageDateTime(String messageDateTime) {
        this.messageDateTime = messageDateTime;
    }

    public int getProfileImageId() {
        return profileImageId;
    }

    public void setProfileImageId(int profileImageId) {
        this.profileImageId = profileImageId;
    }
}

Packen Sie die für den Löschdialog benötigten Daten.

ChatRowData.java


package com.example.chat.models;

/**
 *Eine Zeile der Datenmodellklasse
 */
public class ChatRowData {
    private String name;
    private String text;
    private String messageDateTime;
    private int profileImageId;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public String getMessageDateTime() {
        return messageDateTime;
    }

    public void setMessageDateTime(String messageDateTime) {
        this.messageDateTime = messageDateTime;
    }

    public int getProfileImageId() {
        return profileImageId;
    }

    public void setProfileImageId(int profileImageId) {
        this.profileImageId = profileImageId;
    }
}

Layout

In activity_main wird nur FrameLayout zum Einfügen von Fragment beschrieben. Wenn Kopf- und Fußzeile ebenfalls zu gemeinsamen Teilen verarbeitet werden, verbessert sich die Wartbarkeit zwar, aber

-Der Punkt, an dem die Übergangsanimation zum hinzuzufügenden Chat-Bildschirm (das Gefühl, dass die Ebene des Chat-Bildschirms den gesamten Bildschirm von rechts abdeckt) schwierig wird. ・ Der Punkt, an dem ich in die Hölle gefallen bin, als ich das Verhalten der Zurück-Taste kombiniert habe

Ich habe vergessen, gemeinsame Teile zu machen. .. Ich würde mich sehr freuen, wenn ich im nächsten Artikel von Verbesserungsmaßnahmen für Experten erfahren könnte. ..

activity_main.xml


<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:focusableInTouchMode="true"
    tools:context=".MainActivity">

    <FrameLayout
        android:id="@+id/mainContainer"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">
    </FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

Fragmentlayout für den Chatlistenbildschirm.

fragment_chat_list.xml


<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/background_light_gray"
    tools:context=".fragments.ChatListFragment">

    <View
        android:id="@+id/headerView"
        android:layout_width="wrap_content"
        android:layout_height="50dp"
        android:background="@color/background_dark_gray"
        android:contextClickable="false"
        android:layerType="none"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="1.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/chatListSubject"
        android:layout_width="63dp"
        android:layout_height="19dp"
        android:text="@string/chat_list_subject_label"
        android:textAlignment="center"
        android:textAppearance="@style/TextAppearance.AppCompat.Medium"
        android:textColor="@color/font_color_black"
        app:layout_constraintBottom_toBottomOf="@+id/headerView"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="@+id/headerView"
        app:layout_constraintVertical_bias="0.48" />

    <View
        android:id="@+id/headerBorder"
        android:layout_width="match_parent"
        android:layout_height="0.5dp"
        android:layout_marginTop="48dp"
        android:background="@color/background_border"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="@+id/headerView" />

    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:isScrollContainer="false"
        app:layout_constraintBottom_toTopOf="@+id/footerBorder"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/headerView"
        app:layout_constraintVertical_bias="0.0">

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recyclerView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
    </LinearLayout>

    <View
        android:id="@+id/background"
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        android:background="@color/background_dark_gray"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="@+id/footerBorder" />

    <ImageButton
        android:id="@+id/homeButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="80dp"
        android:background="@color/background_transparent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="@+id/footerBorder"
        app:srcCompat="@drawable/home" />

    <ImageButton
        android:id="@+id/chatListButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@color/background_transparent"
        app:layout_constraintEnd_toStartOf="@+id/userButton"
        app:layout_constraintStart_toEndOf="@+id/homeButton"
        app:layout_constraintTop_toTopOf="@+id/homeButton"
        app:srcCompat="@drawable/fukidashi" />

    <ImageButton
        android:id="@+id/userButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="80dp"
        android:background="@color/background_transparent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="@+id/chatListButton"
        app:srcCompat="@drawable/person" />

    <View
        android:id="@+id/footerBorder"
        android:layout_width="match_parent"
        android:layout_height="0.5dp"
        android:layout_marginBottom="72dp"
        android:background="@color/background_border"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

Es ist ein Layout für eine Zeile der Chat-Liste.

chat_list_row.xml


<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <androidx.cardview.widget.CardView
        android:id="@+id/chatListCardView"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        app:cardCornerRadius="15dp"
        app:cardElevation="0dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <ImageView
            android:id="@+id/profileImage"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="centerCrop"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:srcCompat="@mipmap/ic_launcher" />
    </androidx.cardview.widget.CardView>

    <TextView
        android:id="@+id/name"
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        android:layout_marginStart="16dp"
        android:text="name"
        android:textColor="@color/font_color_black"
        android:textSize="12sp"
        android:textStyle="bold"
        app:layout_constraintStart_toEndOf="@+id/chatListCardView"
        app:layout_constraintTop_toTopOf="@+id/chatListCardView" />

    <TextView
        android:id="@+id/time"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:text="time"
        android:textColor="@color/font_color_black"
        android:textSize="8sp"
        app:layout_constraintBottom_toBottomOf="@+id/name"
        app:layout_constraintStart_toEndOf="@+id/name" />

    <TextView
        android:id="@+id/text"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="16dp"
        android:layout_marginBottom="8dp"
        android:text="text"
        android:textColor="@color/font_color_black"
        android:textSize="12sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="@+id/name"
        app:layout_constraintTop_toBottomOf="@+id/name" />

    <View
        android:id="@+id/line"
        android:layout_width="match_parent"
        android:layout_height="0.3dp"
        android:layout_marginTop="8dp"
        android:background="@color/background_border"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/chatListCardView" />

</androidx.constraintlayout.widget.ConstraintLayout>

values Dies ist die zu verwendende Konstantendatei

colors.xml


<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!--Schriftfarbe schwarz-->
    <color name="font_color_black">#5E5E5E</color>
    <!--Schriftart orange-->
    <color name="font_color_orange">#FF9900</color>
    <!-- background body -->
    <color name="background_light_gray">#EBEBEB</color>
    <!-- background header, footer -->
    <color name="background_dark_gray">#E5E5E5</color>
    <!--Hintergrundtrennzeichen-->
    <color name="background_border">#838383</color>
    <!--Hintergrund transparent-->
    <color name="background_transparent">#00E5E5E5</color>
</resources>

strings.xml


<?xml version="1.0" encoding="utf-8"?>
<!--Konstante Verwaltungsdatei-->
<resources>
    <!--App Name-->
    <string name="app_name">Chat</string>
    <!--Chat-Listenbildschirm-->
    <string name="chat_list_subject_label">CHATS</string>
    <string name="chat_list_delete_button_color">#FF9900</string>
    <string name="chat_list_delete_button_label">DELETE</string>
    <string name="delete_dialog_message">Auch wenn Sie diesen Chatverlauf löschen\n Bist du sicher?</string>
    <string name="delete_dialog_list_tag">chatList</string>
</resources>


styles.xml


<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorAccent">@color/font_color_orange</item>
        <item name="windowActionBar">false</item>
        <item name="windowNoTitle">true</item>
    </style>
</resources>


Ich denke, dass der obige Code die Bewegung des Samples am Anfang reproduzieren kann. Die Quelle ist auch hier verfügbar. Bitte überprüfen Sie sie, wenn Sie möchten. https://github.com/yuta-matsumoto/chat

Schließlich

Ich habe zum ersten Mal einen praktischen Artikel geschrieben, bin aber sehr verwirrt darüber, wie viel ich erklären sollte. .. Ich würde mich sehr freuen, wenn jemand helfen könnte!

Recommended Posts

[Android 9.0 Pie Java] Implementieren Sie horizontales Wischen → Dialogfeldanzeige → Löschen in der Chat-App
Nachrichtendialog mit Java anzeigen (persönliches Memo)
[Android 9.0 Pie Java] Implementieren Sie setOnTouchListener am Rand von RecyclerView und schließen Sie die Softtastatur
[Android 9.0 Pie Java] Chat-Listenbildschirm im LINE-Stil → Übergangsanimation für den persönlichen Chat-Bildschirm implementiert (mit Beispiel-App)
[Android] Überprüfungsdialoganzeige
Erstellen wir eine Taschenrechner-App mit Java ~ Zeigen Sie das Anwendungsfenster an
So implementieren Sie eine einzeilige Anzeige von TextView in der Android-Entwicklung
Implementieren Sie die Anwendungsfunktion in Rails
Implementierung der zweistufigen Authentifizierung in Java
Implementieren Sie die Standardauthentifizierung in Java
Implementieren Sie eine Kombination aus Mathematik in Java
2 Implementieren Sie eine einfache Syntaxanalyse in Java
[Android] Implementieren Sie Adblock in WebView
Implementieren Sie das Senden von E-Mails in Java
Implementieren Sie eine funktionsähnliche schnelle Sortierung in Java
Implementieren Sie rm -rf in Java.
Implementieren Sie die XML-Signatur in Java
Quelle zur Anzeige des Zeichenarrays mit numberPicker in Android Studio (Java)
Lassen Sie uns eine TODO-App in Java 5 erstellen. Schalten Sie die Anzeige von TODO um