Android 仿微信朋友圈点赞和评论弹出框功能

本文简单模仿微信朋友圈的点赞和评论弹出框,布局等细节请忽略,着重实现弹出框、发评论,及弹出位置的控制。

1. 微信弹出框

微信朋友圈的点赞和评论功能,有2个组成部分:

点击左下角的“更多”按钮,弹出对话框;

点击评论,弹出输入框,添加评论并在页面中实时显示;

Android 仿微信朋友圈点赞和评论弹出框功能

微信朋友圈点赞和评论功能

2. 实际效果

本文将建一个 ListView,在其 Item 中简单模仿微信的布局,然后着重实现弹出窗,并能发评论,忽略具体布局细节。具体效果如下:

Android 仿微信朋友圈点赞和评论弹出框功能

 

3. 知识点清单

ListView

自定义 Adapter,重写 getView()方法;

PopupWindow

弹出框使用PopupWindow实现,这是点赞和评论的载体,具体要涉及 PopupWindow 点击非窗口位置和再次点击消失以及显示位置的问题(根据相应更多按钮的位置确定 PopupWindow 的显示位置,关于 PopupWindow 的显示位置,可以参考我的另一篇文章 Android PopupWindow 的显示位置);

LayoutInflater

使用LayoutInflater 动态加载PopupWindow 的布局,关于 LayoutInflater 的更多知识,参见我的另一篇博客 Android LayoutInflater ;

Activity 和 Item 的双向通信

通过自定义 OnCommentListener() 来实现 MainActivity(具体来说是屏幕底部评论框中的输入的内容)和 ItemView(动态的获得上述输入的评论内容并展示在该ItemView 中) 的通信,更多知识参见我的另一篇博客《 燕过留声:由 Activity 和 Fragment 的通信方法想到的》;

自定义控件

ListView 中的每个 Item 是一个自定义的 ItemView,记得要重写构造方法,否则会抛出 Android.view.InflateException 异常;

如果想实现微信评论那样用户名和内容回复文字字体颜色不同,而且点击评论用户名触发页面跳转等功能,请参见 《布局优化技巧笔记》 之 ClickableSpan 章节;

4. 美工素材

由于 .apk 本质上是个压缩包,我们可以通过解压得到该 .apk 文件的图片素材和布局文件,更多获得素材的方法参见我的另一篇博文 如何获得Android素材图片。通过这种方式得到颜色、更多按钮的样式等素材,仅供学习之用,请勿做侵犯版权之事。尊重知识版权既是大势所趋,也是终将使每个开发者受益的事。

Android 仿微信朋友圈点赞和评论弹出框功能

 

文件夹r里存放图片

Android 仿微信朋友圈点赞和评论弹出框功能

5. 关键代码

开发环境:Android Studio 1.4.1 for Mac ADT 21 JDK 1.8.0。

MainAcitivity.Java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
package main.zhaizu.com.popupwindowdemo;
import android.content.Context;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.EditText;
import android.widget.ListView;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import main.zhaizu.com.popupwindowdemo.model.Comment;
import main.zhaizu.com.popupwindowdemo.model.Item;
import main.zhaizu.com.popupwindowdemo.ui.ItemView;
public class MainActivity extends AppCompatActivity {
private ListView mListView;
private View mCommentView;
private MyAdapter myAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mListView = (ListView) findViewById(R.id.listview);
myAdapter = new MyAdapter(this, getData());
mListView.setAdapter(myAdapter);
mCommentView = findViewById(R.id.comment_view);
}
// build data
private ArrayList getData() {
int ITEM_COUNT = 20;
ArrayList data = new ArrayList<>();
data.add(new Item(R.drawable.xiaona, "薄荷栗", "我学过跆拳道,都给我跪下唱征服", "昨天"));
data.add(new Item(R.drawable.xueyan, "欣然", "走遍天涯海角,唯有我家风景最好,啊哈哈", "昨天"));
data.add(new Item(R.drawable.leishao, "陈磊_CL", "老子以后要当行长的,都来找我借钱吧,now", "昨天"));
data.add(new Item(R.drawable.yuhong, "永恒依然", "房子车子都到碗里来", "昨天"));
data.add(new Item(R.drawable.lanshan, "蓝珊", "你们这群傻×,我笑而不语", "昨天"));
return data;
}
// custom adapter
private class MyAdapter extends BaseAdapter implements ItemView.OnCommentListener {
private Context context;
private ArrayList mData;
private Map<Integer, ItemView> mCachedViews = new HashMap<>();
public MyAdapter(Context context, ArrayList mData) {
this.context = context;
this.mData = mData;
}
@Override
public int getCount() {
return mData.size();
}
@Override
public Object getItem(int position) {
return mData.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view;
if (convertView != null) {
view = convertView;
} else {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.listview_item, null, false);
}
if (view instanceof ItemView) {
Item data = (Item) getItem(position);
((ItemView) view).setData(data);
((ItemView) view).setPosition(position);
((ItemView) view).setCommentListener(this);
cacheView(position, (ItemView) view);
}
return view;
}
@Override
public void onComment(int position) {
showCommentView(position);
}
private void cacheView(int position, ItemView view) {
Iterator<Map.Entry<Integer, ItemView>> entries = mCachedViews.entrySet().iterator();
while (entries.hasNext()) {
Map.Entry<Integer, ItemView> entry = entries.next();
if (entry.getValue() == view && entry.getKey() != position) {
mCachedViews.remove(entry.getKey());
break;
}
}
mCachedViews.put(position, view);
}
private void showCommentView(final int position) {
mCommentView.setVisibility(View.VISIBLE);
mCommentView.findViewById(R.id.submit).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
EditText et = (EditText) mCommentView.findViewById(R.id.edit);
String s = et.getText().toString();
if (!TextUtils.isEmpty(s)) {
// update model
Comment comment = new Comment(s);
mData.get(position).getComments().add(comment);
// update view maybe
ItemView itemView = mCachedViews.get(position);
if (itemView != null && position == itemView.getPosition()) {
itemView.addComment();
}
et.setText("");
mCommentView.setVisibility(View.GONE);
}
}
});
}
}
}

ItemView.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package main.zhaizu.com.popupwindowdemo.ui;
import android.content.Context;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.PopupWindow;
import android.widget.TextView;
import main.zhaizu.com.popupwindowdemo.R;
import main.zhaizu.com.popupwindowdemo.model.Comment;
import main.zhaizu.com.popupwindowdemo.model.Item;
/**
* Created by cmm on 15/10/31.
*/
public class ItemView extends LinearLayout implements View.OnClickListener {
private int mPosition;
private Item mData;
private ImageView mPortraitView;
private TextView mUserNameView;
private TextView mContentView;
private TextView mCreatedAtView;
private LinearLayout mCommentLayout;
private View mMoreView;
private PopupWindow mMorePopupWindow;
private int mShowMorePopupWindowWidth;
private int mShowMorePopupWindowHeight;
private OnCommentListener mCommentListener;
public ItemView(Context context) {
super(context);
}
public ItemView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public interface OnCommentListener {
void onComment(int position);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mPortraitView = (ImageView) findViewById(R.id.portrait);
mUserNameView = (TextView) findViewById(R.id.nick_name);
mContentView = (TextView) findViewById(R.id.content);
mCreatedAtView = (TextView) findViewById(R.id.created_at);
mCommentLayout = (LinearLayout) findViewById(R.id.comment_layout);
mMoreView = findViewById(R.id.more_btn);
}
public void setPosition(int mPosition) {
this.mPosition = mPosition;
}
public void setCommentListener(OnCommentListener l) {
this.mCommentListener = l;
}
public void setData(Item data) {
mData = data;
mPortraitView.setImageResource(data.getPortraitId());
mUserNameView.setText(data.getNickName());
mContentView.setText(data.getContent());
updateComment();
mMoreView.setOnClickListener(this);
}
/**
* 弹出点赞和评论框
*
* @param moreBtnView
*/
private void showMore(View moreBtnView) {
if (mMorePopupWindow == null) {
LayoutInflater li = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View content = li.inflate(R.layout.layout_more, null, false);
mMorePopupWindow = new PopupWindow(content, ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
mMorePopupWindow.setBackgroundDrawable(new BitmapDrawable());
mMorePopupWindow.setOutsideTouchable(true);
mMorePopupWindow.setTouchable(true);
content.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
mShowMorePopupWindowWidth = content.getMeasuredWidth();
mShowMorePopupWindowHeight = content.getMeasuredHeight();
View parent = mMorePopupWindow.getContentView();
TextView like = (TextView) parent.findViewById(R.id.like);
TextView comment = (TextView) parent.findViewById(R.id.comment);
// 点赞的监听器
comment.setOnClickListener(this);
}
if (mMorePopupWindow.isShowing()) {
mMorePopupWindow.dismiss();
} else {
int heightMoreBtnView = moreBtnView.getHeight();
mMorePopupWindow.showAsDropDown(moreBtnView, -mShowMorePopupWindowWidth,
-(mShowMorePopupWindowHeight heightMoreBtnView) / 2);
}
}
private void updateComment() {
if (mData.hasComment()) {
mCommentLayout.removeAllViews();
mCommentLayout.setVisibility(View.VISIBLE);
for (Comment c : mData.getComments()) {
TextView t = new TextView(getContext());
t.setLayoutParams(new LinearLayout.LayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)));
t.setBackgroundColor(getResources().getColor(R.color.colorCommentLayoutBg));
t.setTextSize(16);
t.setPadding(5, 2, 0, 3);
t.setLineSpacing(3, (float) 1.5);
t.setText(c.getComment());
mCommentLayout.addView(t);
}
} else {
mCommentLayout.setVisibility(View.GONE);
}
}
@Override
public void onClick(View v) {
int id = v.getId();
if (id == R.id.more_btn) {
showMore(v);
} else if (id == R.id.comment) {
if (mCommentListener != null) {
mCommentListener.onComment(mPosition);
if (mMorePopupWindow != null && mMorePopupWindow.isShowing()) {
mMorePopupWindow.dismiss();
}
}
}
}
public int getPosition() {
return mPosition;
}
public void addComment() {
updateComment();
}
}
  • 版权声明: 本文源自互联网,由整理发表,其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请自行核实相关内容,如果侵犯,请及时通知我们,我们将在第一时间删除; 于2个月前发布,共 9016字。

发表评论

您必须 登录 才能发表留言!