目录
一、主要内容
二、核心代码
三、效果展示
完成好友聊天界面的开发和activity之间的数据传递
编写ChatActivity.xml好友聊天界面UI:
在网上公共库找到封装过的TextView样式进行导入(导入外部库):
修改如下文件settings.gradle
修改如下文件build.gradle(Module):
下面开始使用外部库
编写好友发送的聊天消息样式文件layout_message_left_item.xml:
编写自己发送的聊天消息样式文件layout_message_right_item.xml:
这里创建一个工具类DrawableUtil 进行图片转换为字节数组的操作(后面需要使用):
public class DrawableUtil {
public static Bitmap drawableToBitmap(Drawable drawable) {
int w = drawable.getIntrinsicWidth();
int h = drawable.getIntrinsicHeight();
// System.out.println("Drawable转Bitmap");
Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
Bitmap bitmap = Bitmap.createBitmap(w,h,config);
//注意,下面三行代码要用到,否在在View或者surfaceview里的canvas.drawBitmap会看不到图
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, w, h);
drawable.draw(canvas);
return bitmap;
}
public static byte[] bitmapToBytes(Bitmap bm){
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.PNG, 100, baos);
return baos.toByteArray();
}
}
然后编写activity_chat.xml中RecyclerView对应的MessageAdapter类:
注意: 使用ViewType属性动态控制MessageAdapter加载哪一个样式文件,用于区分好友发送的消息和自己发送的消息。
public class MessageAdapter extends RecyclerView.Adapter {
private final static int I = 0;
private final static int OTHERS = 1;
private Context context;
private List
修改ChatAdapter类(添加点击RecyclerView中的item的相关代码):
public class ChatAdapter extends RecyclerView.Adapter {
private Context context;
private List> data;
private OnItemClickListener onItemClickListener;
public ChatAdapter(Context context, List> data) {
this.context = context;
this.data = data;
}
/**
* 定义 RecyclerView 选项单击事件的回调接口
*/
public interface OnItemClickListener{
void onItemClick(View view, Map data);
}
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
@NonNull
@Override
public ChatViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new ChatViewHolder(LayoutInflater.from(context).inflate(R.layout.layout_chat_item, parent, false));
}
@Override
public void onBindViewHolder(@NonNull ChatViewHolder holder, int position) {
holder.textView1.setText(data.get(position).get("name").toString());
holder.textView2.setText(data.get(position).get("message").toString());
holder.textView3.setText(data.get(position).get("time").toString());
holder.imageView.setImageResource(Integer.parseInt(data.get(position).get("avatars").toString()));
}
@Override
public int getItemCount() {
return data.size();
}
public class ChatViewHolder extends RecyclerView.ViewHolder {
TextView textView1, textView2, textView3;
ImageView imageView;
public ChatViewHolder(@NonNull View itemView) {
super(itemView);
textView1 = itemView.findViewById(R.id.layout_chat_item_textView1);
textView2 = itemView.findViewById(R.id.layout_chat_item_textView2);
textView3 = itemView.findViewById(R.id.layout_chat_item_textView3);
imageView = itemView.findViewById(R.id.layout_chat_item_imageView);
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//此处回传点击监听事件
if(onItemClickListener!=null){
onItemClickListener.onItemClick(v, data.get(getLayoutPosition()));
}
}
});
}
}
}
修改ChatFragment类,调用chatAdapter类的点击事件,完成Activity之间的跳转和信息传递:
public class ChatFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener{
private View view;
private RecyclerView fragment_chat_recyclerView;
private SwipeRefreshLayout swipeRefreshLayout;
private ChatAdapter chatAdapter;
private Context context;
private List> chatData = new ArrayList<>();
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
view = inflater.inflate(R.layout.fragment_chat, container, false);
fragment_chat_recyclerView = view.findViewById(R.id.fragment_chat_recyclerView);
swipeRefreshLayout = view.findViewById(R.id.fragment_chat_swipeRefreshLayout);
context = getContext();
initData();
configSwipeRefreshLayout();
chatAdapter = new ChatAdapter(context, chatData);
chatAdapter.setOnItemClickListener(new ChatAdapter.OnItemClickListener() {
@Override
public void onItemClick(View view, Map data) {
ImageView avatars = view.findViewById(R.id.layout_chat_item_imageView);
TextView name = view.findViewById(R.id.layout_chat_item_textView1);
TextView message = view.findViewById(R.id.layout_chat_item_textView2);
TextView time = view.findViewById(R.id.layout_chat_item_textView3);
//跳转
Intent intent = new Intent(context, ChatActivity.class);
Bundle bundle = new Bundle();
//将图片转换成字节数组传递
Bitmap bitmap = DrawableUtil.drawableToBitmap(avatars.getDrawable());
byte[] bytes = DrawableUtil.bitmapToBytes(bitmap);
bundle.putByteArray("avatars", bytes);
bundle.putString("name", name.getText().toString());
bundle.putString("message", message.getText().toString());
bundle.putString("time", time.getText().toString());
if(message.getText().toString().contains("我:"))
{
bundle.putString("type", "I");
}
else
{
bundle.putString("type", "others");
}
bundle.putInt("requestCode", 1);
intent.putExtras(bundle);
startActivityForResult(intent, 1);
}
});
LinearLayoutManager manager = new LinearLayoutManager(context);
manager.setOrientation(RecyclerView.VERTICAL);
fragment_chat_recyclerView.setLayoutManager(manager);
fragment_chat_recyclerView.setAdapter(chatAdapter);
return view;
}
private void configSwipeRefreshLayout() {
swipeRefreshLayout.setSize(CircularProgressDrawable.LARGE);
swipeRefreshLayout.setColorSchemeResources(android.R.color.holo_blue_bright,
android.R.color.system_accent1_200, android.R.color.system_neutral2_300);
swipeRefreshLayout.setOnRefreshListener(this);
}
@Override
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == 1 && resultCode == 1)
{
Bundle bundle = data.getExtras();
String name = bundle.getString("name");
String message = bundle.getString("message");
String time = bundle.getString("time");
//更新聊天记录
for (int i = 0; i < chatData.size(); i++) {
if(chatData.get(i).get("name").toString().equals(name))
{
chatData.get(i).put("message", "我:" + message);
chatData.get(i).put("time", time);
chatAdapter.notifyItemChanged(i);
break;
}
}
}
}
private void initData() {
String[] name = {"倚楼听风雨", "璎婲", "の大脸猫", "静秋┐", ">.<",
"旧街凉风", "初見", "雨嘉ψ", "鸢尾*", "凉栀"};
String[] message = {"在吗?", "哈哈哈", "...", "呜呜呜", "呵呵",
"吃饭了吗?", "~~~", "今天有空吗?", "出去玩呀", "爱你哟"};
String[] time = {"12:10", "昨天", "3月15日", "3月15日", "3月15日",
"9:00", "5:00", "4月17日", "18:00", "9月1日"};
Integer[] avatars = {R.drawable.avatars1, R.drawable.avatars2, R.drawable.avatars3,
R.drawable.avatars4, R.drawable.avatars5, R.drawable.avatars6,
R.drawable.avatars7, R.drawable.avatars8, R.drawable.avatars9,
R.drawable.avatars10,};
for (int i = 0; i < name.length; i++) {
HashMap d = new HashMap<>();
d.put("name", name[i]);
d.put("message", message[i]);
d.put("time", time[i]);
d.put("avatars", avatars[i]);
chatData.add(d);
}
}
@Override
public void onRefresh() {
//延时2s
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
swipeRefreshLayout.setRefreshing(false);
}
}, 3000);
}
}
编写ChatActivity类,接受信息进行处理:
public class ChatActivity extends AppCompatActivity {
private List> data = new ArrayList<>();
private RecyclerView recyclerView;
private TextView textView1;
private ImageView back, more;
private Button button1;
private EditText editText;
private LinearLayout linearLayout;
private Boolean isSend = false;
private Map result = new HashMap<>();
private Intent intent;
private String name;
private MessageAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chat);
linearLayout = findViewById(R.id.activity_chat_layout);
recyclerView = findViewById(R.id.activity_chat_recyclerView);
textView1 = findViewById(R.id.activity_chat_textView1);
back = findViewById(R.id.activity_chat_imageView_back);
more = findViewById(R.id.activity_chat_imageView_more);
button1 = findViewById(R.id.activity_chat_button);
editText = findViewById(R.id.activity_chat_editText);
intent = getIntent();
Bundle bundle = intent.getExtras();
byte[] avatars = bundle.getByteArray("avatars");
name = bundle.getString("name");
String message = bundle.getString("message");
String time = bundle.getString("time");
String type = bundle.getString("type");
int requestCode = bundle.getInt("requestCode");
if(requestCode == 1)
{
textView1.setText(name);
Map map = new HashMap<>();
map.put("avatars", avatars);
map.put("message", message);
map.put("time", time);
map.put("type", type);
data.add(map);
adapter = new MessageAdapter(this, data);
LinearLayoutManager manager = new LinearLayoutManager(this);
manager.setOrientation(RecyclerView.VERTICAL);
recyclerView.setLayoutManager(manager);
recyclerView.setAdapter(adapter);
}
setbackListener();
setEditTextListener();
setSendMsgListener();
}
/**
* 监听输入框是否失去焦点进行按钮的切换
*/
private void setEditTextListener() {
editText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View view, boolean hasFocus) {
if(hasFocus)
{
more.setVisibility(View.GONE);
button1.setVisibility(View.VISIBLE);
}else
{
more.setVisibility(View.VISIBLE);
button1.setVisibility(View.GONE);
}
}
});
}
private void setSendMsgListener() {
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(!editText.getText().toString().trim().equals(""))
{
isSend = true;
result.put("message", editText.getText().toString());
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("MM月dd日 HH:mm");
simpleDateFormat.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
result.put("time", simpleDateFormat.format(new Date()));
result.put("type", "I");
data.add(result);
//清楚输入的聊天信息并失去焦点
editText.setText("");
editText.clearFocus();
adapter.notifyItemInserted(data.size() - 1);
}
}
});
}
/**
* 返回主菜单
*/
private void setbackListener() {
back.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//如果发送了新的消息,返回主界面时要更新信息
int resultCode = 0;
Bundle bundle = new Bundle();
if(isSend)
{
resultCode = 1;
bundle.putString("name", name);
bundle.putString("message", result.get("message").toString());
bundle.putString("time", result.get("time").toString());
bundle.putInt("resultCode", 1);
}
else
{
bundle.putInt("resultCode", 0);
}
intent.putExtras(bundle);
setResult(resultCode, intent);
finish();
}
});
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
// TODO Auto-generated method stub
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
// 获得当前得到焦点的View,一般情况下就是EditText(特殊情况就是轨迹求或者实体案件会移动焦点)
View v = getCurrentFocus();
if (isShouldHideInput(v, ev)) {
//关闭键盘,并让输入框失去焦点
hideSoftInput(v.getWindowToken());
}
}
return super.dispatchTouchEvent(ev);
}
/**
* 根据EditText所在坐标和用户点击的坐标相对比,来判断是否隐藏键盘,因为当用户点击EditText时没必要隐藏
*
* @param v
* @param event
* @return
*/
private boolean isShouldHideInput(View v, MotionEvent event) {
if (v != null && (v instanceof EditText)) {
int[] l = { 0, 0 };
v.getLocationInWindow(l);
int left = l[0], top = l[1], bottom = top + v.getHeight(), right = left + v.getWidth();
if (event.getX() > left && event.getX() < right && event.getY() > top && event.getY() < bottom) {
// 点击EditText的事件,忽略它。
return false;
} else {
return true;
}
}
// 如果焦点不是EditText则忽略,这个发生在视图刚绘制完,第一个焦点不在EditView上,和用户用轨迹球选择其他的焦点
return false;
}
/**
* 隐藏键盘
*
* @param token
*/
private void hideSoftInput(IBinder token) {
if (token != null) {
InputMethodManager im = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
im.hideSoftInputFromWindow(token, InputMethodManager.HIDE_NOT_ALWAYS);
}
}
}
1.好友聊天界面弹出键盘会影响页面布局:
修改AndroidManifest.xml,在相应的Activity添加一下两行解决:
android:screenOrientation="portrait" android:windowSoftInputMode="adjustPan"
2.设置button颜色不生效:
修改一下两个文件即可:
将 parent="Theme.MaterialComponents.DayNight.DarkActionBar"改Theme.MaterialComponents.DayNight.NoActionBar.Bridge,在设置按钮颜色即可
仓库地址:青松xyz/WechatForm