效果图
XML布局
item_wechat_message.xml
单个Item,自定义了一个圆角Layout,和一个消息角标
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:paddingLeft="15dp"
android:gravity="center"
android:layout_width="match_parent"
android:minHeight="72dp"
android:clipToPadding="false"
android:clipChildren="false"
android:background="@drawable/selector_main_wechat_chat"
android:layout_height="72dp">
<FrameLayout
android:clipToPadding="false"
android:clipChildren="false"
android:layout_width="48dp"
android:layout_height="48dp">
<com.example.myapplication.ui.widget.RoundLayout
android:background="#FFFFFF"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/iv_author"
android:scaleType="centerCrop"
android:layout_width="match_parent"
android:layout_height="match_parent"></ImageView>
</com.example.myapplication.ui.widget.RoundLayout>
<com.example.myapplication.ui.widget.MessageMarker
android:id="@+id/tv_message_marker"
android:text="3"
android:gravity="center"
android:layout_marginTop="-4dp"
android:layout_marginRight="-4dp"
android:textSize="10sp"
android:textColor="#ffffff"
android:background="@drawable/shape_message_marker"
android:layout_gravity="right"
android:minWidth="10dp"
android:minHeight="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</com.example.myapplication.ui.widget.MessageMarker>
</FrameLayout>
<RelativeLayout
android:layout_marginLeft="8dp"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_centerVertical="true"
android:paddingRight="15dp"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="25dp">
<TextView
android:id="@+id/tv_name"
android:textSize="17sp"
android:textColor="#000000"
android:gravity="center|left"
android:text="电子学院乒乓球"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent">
</TextView>
<TextView
android:id="@+id/tv_last_timer"
android:textSize="11sp"
android:textColor="#9e9e9e"
android:gravity="right"
android:text="早上12:22"
android:layout_width="80dp"
android:layout_height="wrap_content">
</TextView>
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="25dp">
<TextView
android:id="@+id/tv_perview_message"
android:textSize="12sp"
android:gravity="center|left"
android:text="[图片]"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent">
</TextView>
<TextView
android:gravity="right"
android:text=""
android:layout_width="50dp"
android:layout_height="wrap_content">
</TextView>
</LinearLayout>
</LinearLayout>
<View
android:layout_alignParentBottom="true"
android:background="@color/colorBaseLine"
android:layout_width="match_parent"
android:layout_height="2px"></View>
</RelativeLayout>
</LinearLayout>
wechat_activity_title.xml
顶部标题栏
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:paddingLeft="15dp"
android:gravity="center"
android:background="@color/colorMainTheme"
android:layout_height="48dp">
<TextView
android:textSize="18sp"
android:textColor="#000000"
android:layout_centerVertical="true"
android:text="微信(5)"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</TextView>
<RelativeLayout
android:gravity="center"
android:layout_toLeftOf="@+id/rl_add"
android:layout_width="48dp"
android:layout_height="48dp">
<ImageView
android:id="@+id/search"
android:background="@drawable/ic_search"
android:layout_width="wrap_content"
android:layout_height="wrap_content"></ImageView>
</RelativeLayout>
<RelativeLayout
android:id="@+id/rl_add"
android:gravity="center"
android:layout_alignParentRight="true"
android:layout_width="48dp"
android:layout_height="48dp">
<ImageView
android:id="@+id/add"
android:layout_alignParentRight="true"
android:background="@drawable/ic_add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"></ImageView>
</RelativeLayout>
</RelativeLayout>
wechat_buttom_nav.xml
底部导航栏
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:background="@color/colorMainTheme"
android:layout_height="56dp">
<View
android:background="@color/colorBaseLine"
android:layout_width="match_parent"
android:layout_height="2px"></View>
<LinearLayout
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="vertical"
android:gravity="center"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent">
<ImageView
android:background="@drawable/nav_item_index"
android:layout_width="wrap_content"
android:layout_height="wrap_content"></ImageView>
<TextView
android:layout_marginTop="2dp"
style="@style/MainNavItemTextView"
android:text="微信"
android:layout_width="wrap_content"
android:layout_height="wrap_content"></TextView>
</LinearLayout>
<LinearLayout
android:orientation="vertical"
android:gravity="center"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent">
<ImageView
android:background="@drawable/nav_firend"
android:layout_width="wrap_content"
android:layout_height="wrap_content"></ImageView>
<TextView
style="@style/MainNavItemTextView"
android:text="通讯录"
android:layout_width="wrap_content"
android:layout_height="wrap_content"></TextView>
</LinearLayout>
<LinearLayout
android:orientation="vertical"
android:gravity="center"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent">
<ImageView
android:background="@drawable/nav_share"
android:layout_width="wrap_content"
android:layout_height="wrap_content"></ImageView>
<TextView
android:layout_marginTop="2dp"
style="@style/MainNavItemTextView"
android:text="发现"
android:layout_width="wrap_content"
android:layout_height="wrap_content"></TextView>
</LinearLayout>
<LinearLayout
android:orientation="vertical"
android:gravity="center"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent">
<ImageView
android:background="@drawable/nav_home"
android:layout_width="wrap_content"
android:layout_height="wrap_content"></ImageView>
<TextView
android:layout_marginTop="2dp"
style="@style/MainNavItemTextView"
android:text="我"
android:layout_width="wrap_content"
android:layout_height="wrap_content"></TextView>
</LinearLayout>
</LinearLayout>
</LinearLayout>
activity_main.xml
主界面
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#FFFFFF"
android:fitsSystemWindows="true"
tools:context=".MainActivity">
<include layout="@layout/wechat_activity_title"></include>
<ListView
android:scrollbars="none"
android:dividerHeight="0dp"
android:divider="@null"
android:overScrollMode="never"
android:id="@+id/lv_main_chat"
android:layout_width="match_parent"
android:layout_weight="1"
android:layout_height="0dp">
</ListView>
<include layout="@layout/wechat_buttom_nav"></include>
</LinearLayout>
创建数据message_list.son,消息列表集合
[ { "mEnumMessageType": "1", "mUserName": "可可爱爱", "mUserUrl": "https://img2.woyaogexing.com/2019/11/01/3729c227bf5e40d98275efbb50589ec5!400x400.jpeg", "mPerviewMessage": "干嘛呢", "mLastTimer": 1572600035475, "mMessageMarkerCount": 1, "mNotify": false }, { "mEnumMessageType": "1", "mUserName": "刘", "mUserUrl": "https://img2.woyaogexing.com/2019/11/01/40f21ea149bb459798e9e6d320901bbc!400x400.jpeg", "mPerviewMessage": "[图片]", "mLastTimer": 1572500025475, "mMessageMarkerCount": 0, "mNotify": false }, { "mEnumMessageType": "1", "mUserName": "傻子", "mUserUrl": "https://img2.woyaogexing.com/2019/11/01/e7972dc51d634b68b0b2bd03ef10d355!400x400.jpeg", "mPerviewMessage": "行", "mLastTimer": 1572400025475, "mMessageMarkerCount": 2, "mNotify": false }, { "mEnumMessageType": "1", "mUserName": "杨旭", "mUserUrl": "https://img2.woyaogexing.com/2019/11/01/a6ad8bbf6f9e4e5aa11181c61b6ef998!400x400.jpeg", "mPerviewMessage": "拜拜", "mLastTimer": 1572300025475, "mMessageMarkerCount": 2, "mNotify": false }]
MainActivity.java
package com.example.myapplication;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ListView;
import com.example.myapplication.adapter.WechatChatBaseAdapter;
import com.example.myapplication.bean.BaseItemWechatEntity;
import com.example.myapplication.bean.FriendItemWechatEntity;
import com.example.myapplication.enums.EnumMessageType;
import com.example.myapplication.factory.ItemWeichatFactory;
import com.example.myapplication.utils.LogUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private ListView mListView;
private List<BaseItemWechatEntity> mChatList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
getWindow().getDecorView().setSystemUiVisibility( View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN|View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
}
setContentView(R.layout.activity_main);
initView();
initData();
}
private void initData(){
mChatList =new ArrayList<>();
try{
InputStream is = getResources().getAssets().open("message_list.json");
BufferedReader br =new BufferedReader(new InputStreamReader(is,"utf-8"));
StringBuffer stringBuffer =new StringBuffer();
while (true){
String temp =br.readLine();
if (temp==null){break;}
stringBuffer.append(temp);
}
br.close();
handerListJson(stringBuffer.toString());
}catch (IOException e){
e.printStackTrace();
}
mListView.setAdapter(new WechatChatBaseAdapter(mChatList,this));
}
private void handerListJson(String json){
try{
JSONArray jsonArray =new JSONArray(json);
for (int i = 0; i < jsonArray.length(); i++) {
LogUtils.i(jsonArray.getString(i));
mChatList.add( createItemEntity(jsonArray.getJSONObject(i), EnumMessageType.FRIEND_MESSAGE));
}
}catch (JSONException e){
e.printStackTrace();
}
}
private BaseItemWechatEntity createItemEntity(JSONObject json, EnumMessageType type){
return ItemWeichatFactory.createItemWechatEntyty(type,
json.optInt("mLastTimer"),
json.optInt("mMessageMarkerCount"),
json.optBoolean("mNotify"),
json.optString("mPerviewMessage"),
json.optString("mUserName"),json.optString("mUserUrl"));
}
private void initView(){
mListView =findViewById(R.id.lv_main_chat);
}
}
WechatChatBaseAdapter.java
适配器
package com.example.myapplication.adapter;
import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import com.example.myapplication.R;
import com.example.myapplication.bean.BaseItemWechatEntity;
import com.example.myapplication.utils.DateUtils;
import com.example.myapplication.utils.ImageLoader;
import com.example.myapplication.utils.LogUtils;
import java.util.List;
public class WechatChatBaseAdapter extends BaseAdapter {
private List<BaseItemWechatEntity> mChatList;
private Context mContext;
private LayoutInflater mInflater;
public WechatChatBaseAdapter(List<BaseItemWechatEntity> mChatList, Context mContext) {
this.mChatList = mChatList;
this.mContext = mContext;
mInflater=LayoutInflater.from(mContext);
}
@Override
public int getCount() {
return mChatList==null?0:mChatList.size();
}
@Override
public BaseItemWechatEntity getItem(int position) {
return mChatList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = mInflater.inflate(R.layout.item_wechat_message, null,false);
convertView.setTag(new ViewHolder(convertView));
}
initializeViews(getItem(position), (ViewHolder) convertView.getTag());
return convertView;
}
private void initializeViews(BaseItemWechatEntity entity, ViewHolder holder) {
LogUtils.i(entity.toString());
holder.tvName.setText(entity.getUserName());
holder.tvPerviewMessage.setText(entity.getPerviewMessage());
holder.tvMessageMarker.setText(entity.getMessageMarkerCount()+"");
holder.tvLastTimer.setText(DateUtils.getDiffDate(entity.getLastTimer()));
ImageLoader.with(mContext).load(entity.getUserUrl(),holder.ivAuthor);
if (entity.getMessageMarkerCount()==0){holder.tvMessageMarker.setVisibility(View.GONE);}
}
class ViewHolder{
private ImageView ivAuthor;
private TextView tvName;
private TextView tvLastTimer;
private TextView tvPerviewMessage;
private TextView tvMessageMarker;
public ViewHolder(View view) {
ivAuthor = (ImageView) view.findViewById(R.id.iv_author);
tvName = (TextView) view.findViewById(R.id.tv_name);
tvLastTimer = (TextView) view.findViewById(R.id.tv_last_timer);
tvPerviewMessage = (TextView) view.findViewById(R.id.tv_perview_message);
tvMessageMarker=(TextView)view.findViewById(R.id.tv_message_marker);
}
}
}
其中还有一个ImageLoad,用来加载图片
只是简单是使用BitmapFactory从流中构建一个Bitmap,没有做任何优化
package com.example.myapplication.utils;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.Looper;
import android.widget.ImageView;
import com.example.myapplication.R;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
public class ImageLoader {
private Context mContext;
private Handler mHandler = new Handler(Looper.getMainLooper());
public ImageLoader(Context context) {
this.mContext = context;
}
public static ImageLoader with(Context context) {
return new ImageLoader(context);
}
public void load(final String url, final ImageView imageView) {
new Thread() {
@Override
public void run() {
super.run();
Bitmap bitmap = getBitmapByUrl(url);
if (bitmap != null) {
loadImage(bitmap, imageView);
}
}
}.start();
}
private void loadImage(final Bitmap bitmap, final ImageView imageView) {
mHandler.post(new Runnable() {
@Override
public void run() {
imageView.setImageBitmap(bitmap);
}
});
}
private Bitmap getBitmapByUrl(String urlString) {
try {
LogUtils.i(Thread.currentThread().getName());
URL url = new URL(urlString);
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
InputStream inputStream = urlConnection.getInputStream();
Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
LogUtils.i(bitmap + "");
return bitmap;
} catch (IOException e) {
e.printStackTrace();
}
return getDefault();
}
private Bitmap getDefault() {
return BitmapFactory.decodeResource(mContext.getResources(), R.drawable.back);
}
}
BaseItemWechatEntity
实体类
package com.example.myapplication.bean;
import com.example.myapplication.enums.EnumMessageType;
public class BaseItemWechatEntity {
private EnumMessageType mEnumMessageType;
private String mUserUrl;
private String mUserName;
private String mPerviewMessage;
private long mLastTimer;
private int mMessageMarkerCount;
private boolean isNotify;
public BaseItemWechatEntity(Builder builder) {
this(builder,null);
}
public BaseItemWechatEntity(Builder builder,EnumMessageType type) {
this.mEnumMessageType =type;
this.isNotify=builder.isNotify;
this.mLastTimer=builder.mLastTimer;
this.mMessageMarkerCount=builder.mMessageMarkerCount;
this.mPerviewMessage=builder.mPerviewMessage;
this.mUserName=builder.mUserName;
this.mUserUrl=builder.mUserUrl;
}
public EnumMessageType getEnumMessageType() {
return mEnumMessageType;
}
public String getUserUrl() {
return mUserUrl;
}
public String getUserName() {
return mUserName;
}
public String getPerviewMessage() {
return mPerviewMessage;
}
public long getLastTimer() {
return mLastTimer;
}
public int getMessageMarkerCount() {
return mMessageMarkerCount;
}
public boolean isNotify() {
return isNotify;
}
@Override
public String toString() {
return "BaseItemWechatEntity{" +
"mEnumMessageType=" + mEnumMessageType +
", mUserUrl='" + mUserUrl + '\'' +
", mUserName='" + mUserName + '\'' +
", mPerviewMessage='" + mPerviewMessage + '\'' +
", mLastTimer=" + mLastTimer +
", mMessageMarkerCount=" + mMessageMarkerCount +
", isNotify=" + isNotify +
'}';
}
public static class Builder{
private String mUserUrl;
private String mUserName;
private String mPerviewMessage;
private long mLastTimer;
private int mMessageMarkerCount;
private boolean isNotify;
public Builder setUserUrl(String userUrl) {
mUserUrl = userUrl;
return this;
}
public Builder setUserName(String userName) {
mUserName = userName;
return this;
}
public Builder setPerviewMessage(String perviewMessage) {
mPerviewMessage = perviewMessage;
return this;
}
public Builder setLastTimer(long lastTimer) {
mLastTimer = lastTimer;
return this;
}
public Builder setMessageMarkerCount(int messageMarkerCount) {
mMessageMarkerCount = messageMarkerCount;
return this;
}
public Builder setNotify(boolean notify) {
isNotify = notify;
return this;
}
public BaseItemWechatEntity builder(){
return new BaseItemWechatEntity(this);
}
}
}
RoundLayout.java
圆角布局
package com.example.myapplication.ui.widget;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.RelativeLayout;
public class RoundLayout extends RelativeLayout {
private Paint mPaint;
private Path mPath;
private float mRadius=15;
// private Bitmap mBitmap;
// private int mStartX,mStartY;
// private int mDownX,mDownY;
private RectF rectF;
public RoundLayout(Context context) {
super(context);
init();
}
public RoundLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public RoundLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init(){
mPaint= new Paint();
mPath =new Path();
rectF =new RectF();
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
return false;
}
@Override
public void draw(Canvas canvas) {
canvas.clipPath(genPath());
super.draw(canvas);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
rectF.set(0,0,w,h);
}
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
}
private Path genPath() {
mPath.reset();
mPath.addRoundRect(rectF, mRadius, mRadius, Path.Direction.CW);
return mPath;
}
}