Android9.0 Pie Java
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
Der Inhalt ist sehr lang. Wenn Sie das fertige Produkt nicht erhalten können, klicken Sie bitte hier. https://github.com/yuta-matsumoto/chat
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/
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();
}
}
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);
}
}
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;
}
}
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
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