Android9.0 Pie Java
J'ai récemment créé une application de chat sur Android Java et mis en œuvre la suppression de la liste de chat de style LINE. Il existe de nombreux articles sur l'affichage de la liste et la fonction de suppression de RecyclerView,
Glisser horizontalement → Afficher la boîte de dialogue → Supprimer MainActivity + Configuration de fragments multiples
Je n'ai pas trouvé l'exemple d'implémentation de dans l'article japonais, donc je vais le partager. (Je me méfie si c'est la meilleure pratique, alors veuillez l'utiliser comme référence.
Vous pouvez mettre en œuvre comme ça
Le contenu est très long, donc si vous ne pouvez pas obtenir le produit fini, veuillez cliquer ici. https://github.com/yuta-matsumoto/chat
Omettre les fichiers de construction et les fichiers manifestes
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/ │ │ └ sample1.png (omis ci-dessous) │ ├layout/ │ │ ├activity_main.xml │ │ ├chat_list_row.xml │ │ └fragment_chat_list.xml │ └values/ │ ├colors.xml │ ├strings.xml │ └styles.xml
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' //Postscript
implementation 'androidx.cardview:cardview:1.0.0' //Postscript
}
Activity
MainActivity ne charge que Fragment.
Fragment hérite de la classe de base de tous les fragments appelée BaseFragment pour réaliser MainActivity + plusieurs configurations de fragments
.
Je me réfère aux articles suivants. 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 {
//Base de fragment
private BaseFragment fragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Définir un fragment de liste de discussion pour la première fois
if (fragment == null) {
fragment = new ChatListFragment();
}
// main_Définir le fragment sur activité
getSupportFragmentManager().beginTransaction()
.replace(R.id.mainContainer, fragment)
.commit();
}
}
Fragment
C'est le fragment de base. Je ne l'ai pas inclus cette fois, mais il est pratique d'inclure l'écouteur d'événements du bouton commun dans BaseFragment car il sera compact.
BaseFragment.java
package com.example.chat.fragments;
import android.os.Bundle;
import androidx.fragment.app.Fragment;
/**
*Fragment de base
*/
public abstract class BaseFragment extends Fragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
}
Fragment de l'écran de la liste de discussion.
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 pour l'écran de la liste de discussion
*/
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);
//Liste de données de la liste de discussion
final List list = getChatList();
//Nombre d'éléments dans la liste de données de la liste de discussion
final int itemCount = list.size();
//Adaptateur de liste de discussion
final ChatListAdapter adapter = new ChatListAdapter(list) {
@Override
public void onItemClick(View view, int pos, List<ChatRowData> list) {
//Ajout du processus en cliquant sur une ligne
}
};
LinearLayoutManager llm = new LinearLayoutManager(getContext());
rv.setHasFixedSize(true);
rv.setLayoutManager(llm);
rv.setAdapter(adapter);
//Mettre en œuvre le balayage
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();
//Définissez les données de ligne à supprimer dans le fragment de boîte de dialogue de suppression
DeleteChatRowData deleteChatRowData = new DeleteChatRowData();
deleteChatRowData.setList(list);
deleteChatRowData.setAdapter(adapter);
deleteChatRowData.setPosition(pos);
deleteChatRowData.setItemCount(itemCount);
//Transmettre les données à l'aide du bundle
Bundle bundle = new Bundle();
bundle.putSerializable(getResources().getString(R.string.delete_dialog_list_tag), deleteChatRowData);
fragment.setArguments(bundle);
//Affichage de la boîte de dialogue
fragment.show(fragmentManager, "delete chat list");
}
}
));
}
};
}
/**
*Génération de données de test de liste de discussion
*/
private List<ChatRowData> getChatList() {
List<ChatRowData> list = new ArrayList<>();
ChatRowData data1 = new ChatRowData();
data1.setName("Taro Tanaka");
data1.setText("Bonjour");
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("Bonjour!");
data2.setMessageDateTime("2020/6/08 8:10");
data2.setProfileImageId(R.drawable.sample2);
list.add(data2);
ChatRowData data3 = new ChatRowData();
data3.setName("taro");
data3.setText("Quelle heure est-il?");
data3.setMessageDateTime("2020/6/07 20:09");
data3.setProfileImageId(R.drawable.sample3);
list.add(data3);
ChatRowData data4 = new ChatRowData();
data4.setName("hanako");
data4.setText("Veuillez me prêter un manuel");
data4.setMessageDateTime("2020/6/06 07:00");
data4.setProfileImageId(R.drawable.sample4);
list.add(data4);
ChatRowData data5 = new ChatRowData();
data5.setName("Tanaka");
data5.setText("Impossible");
data5.setMessageDateTime("2020/6/06 01:05");
data5.setProfileImageId(R.drawable.sample5);
list.add(data5);
ChatRowData data6 = new ChatRowData();
data6.setName("Kobayashi");
data6.setText("D'accord");
data6.setMessageDateTime("2020/6/05 14:22");
data6.setProfileImageId(R.drawable.sample6);
list.add(data6);
ChatRowData data7 = new ChatRowData();
data7.setName("Petagini");
data7.setText("je veux aller a la maison");
data7.setMessageDateTime("2020/6/05 13:00");
data7.setProfileImageId(R.drawable.sample7);
list.add(data7);
ChatRowData data8 = new ChatRowData();
data8.setName("Hayato");
data8.setText("Allons voir le film, 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("je l'ai fait");
data10.setMessageDateTime("2020/5/29 4:00");
data10.setProfileImageId(R.drawable.sample10);
list.add(data10);
return list;
}
}
Fragment de la boîte de dialogue de suppression.
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 pour la boîte de dialogue de suppression
*/
public class DeleteChatRowFragment extends DialogFragment {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// setCancelable(false)Ne ferme pas même si vous appuyez en dehors de la boîte de dialogue avec
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)
//Lorsque vous appuyez sur OK
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
//Supprimer le processus
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();
//Suppression de l'élément de l'ordre de position de la ligne pressée de la liste de discussion Liste
list.remove(pos);
//Informez l'adaptateur que l'élément a été supprimé
deleteChatRowData.getAdapter().notifyItemRemoved(pos);
//Notifier qu'il y a un changement dans la liste de discussion et relier
adapter.notifyItemRangeChanged(pos, itemCount);
}
})
//Lorsque vous appuyez sur Annuler
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
//Balayez vers l'arrière
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();
//Balayez vers l'arrière
adapter.notifyItemChanged(pos);
}
})
.create();
}
//Ne quittez pas lorsque l'application passe en arrière-plan
@Override
public void onPause() {
super.onPause();
dismiss();
}
}
Utilisé dans l'affichage de la liste de discussion.
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;
/**
*Classe d'adaptateur utilisée pour afficher la liste de discussion
*/
public class ChatListAdapter extends RecyclerView.Adapter<ViewHolder> {
private List<ChatRowData> list;
public ChatListAdapter(List<ChatRowData> list) {
this.list = list;
}
/**
*Créer ViewHolder pour la liste de discussion
*/
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//Charger une ligne de mise en page dans View
View inflate = LayoutInflater.from(parent.getContext()).inflate(R.layout.chat_list_row, parent, false);
final ViewHolder vh = new ViewHolder(inflate);
//Enregistrer l'écouteur de clics
inflate.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//Obtenez la position de la ligne cliquée
int position = vh.getAdapterPosition();
//Étant donné que l'opération de View doit être gérée par Activity ou Fragment, le traitement réel n'est pas écrit.
onItemClick(v, position, list);
}
});
//Enregistrer l'écouteur tactile
inflate.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
//Étant donné que l'opération de View doit être gérée par Activity ou Fragment, le traitement réel n'est pas écrit.
return onItemTouch(v);
}
});
return vh;
}
/**
*Lier les données de la liste de discussion à afficher dans 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());
}
/**
*Définir le nombre d'éléments dans la liste de discussion Liste
*/
@Override
public int getItemCount() {
return list.size();
}
/**
*Remplacer et traiter avec ChatListFragment
*/
public void onItemClick(View view, int pos, List<ChatRowData> list) {
;
}
/**
*Remplacer et traiter avec ChatListFragment
*/
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;
/**
*Classe ViewHolder
*Définissez la vue qui constitue une ligne
*/
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);
}
}
Utilisé pour le mouvement de balayage horizontal. J'ai beaucoup parlé de cet article.
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;
/**
*Classe d'assistance de balayage
*/
public abstract class SwipeHelper extends ItemTouchHelper.SimpleCallback {
//SUPPRIMER la largeur du bouton affichée en faisant glisser
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();
//Jeu de couleurs d'arrière-plan
p.setColor(color);
c.drawRect(rect, p);
//SUPPRIMER le jeu de couleurs de texte
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);
}
}
Remplissez les données pour une ligne de la liste de discussion.
ChatRowData.java
package com.example.chat.models;
/**
*Une ligne de classe de modèle de données
*/
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;
}
}
Emballez les données nécessaires pour la boîte de dialogue de suppression.
ChatRowData.java
package com.example.chat.models;
/**
*Une ligne de classe de modèle de données
*/
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;
}
}
Seul FrameLayout pour l'insertion de Fragment est décrit dans activity_main. En fait, si l'en-tête et le pied de page sont également transformés en parties communes, la maintenabilité s'améliorera, mais
-Le fait que l'animation de transition vers l'écran de chat à ajouter (sentiment que la couche de l'écran de chat couvre tout l'écran à partir de la droite) devient difficile. ・ Le fait que je suis tombé en enfer quand j'ai combiné le comportement de la touche arrière
J'ai oublié de faire des parties communes. .. Je serais très heureux si je pouvais entendre parler de mesures d'amélioration pour les experts dans le prochain article. ..
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>
Disposition des fragments pour l'écran de la liste de discussion.
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>
Il s'agit d'une mise en page pour une ligne de la liste de discussion.
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 C'est le fichier constant à utiliser
colors.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--Couleur de police noir-->
<color name="font_color_black">#5E5E5E</color>
<!--Police 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>
<!--séparateur d'arrière-plan-->
<color name="background_border">#838383</color>
<!--fond transparent-->
<color name="background_transparent">#00E5E5E5</color>
</resources>
strings.xml
<?xml version="1.0" encoding="utf-8"?>
<!--Fichier de gestion constant-->
<resources>
<!--nom de l'application-->
<string name="app_name">Chat</string>
<!--Écran de liste de discussion-->
<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">Même si vous supprimez cet historique de chat\n Etes-vous sûr?</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>
Je pense que le code ci-dessus peut reproduire le mouvement de l'échantillon au début. La source est également disponible ici, veuillez donc la vérifier si vous le souhaitez. https://github.com/yuta-matsumoto/chat
J'ai écrit un article pratique pour la première fois, mais je ne sais pas trop combien je devrais expliquer. .. Je serais très heureux si quelqu'un pouvait m'aider!
Recommended Posts