Android 仿微信朋友圈点赞和评论弹出框功能
贡献/下载源码:https://github.com/mmlovesyy/popupwindowdemo
本文简单模仿微信朋友圈的点赞和评论弹出框,布局等细节请忽略,着重实现弹出框、发评论,及弹出位置的控制。
1. 微信弹出框
微信朋友圈的点赞和评论功能,有2个组成部分:
点击左下角的“更多”按钮,弹出对话框;
点击评论,弹出输入框,添加评论并在页面中实时显示;
微信朋友圈点赞和评论功能
2. 实际效果
本文将建一个 listview,在其 item 中简单模仿微信的布局,然后着重实现弹出窗,并能发评论,忽略具体布局细节。具体效果如下:
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素材图片。通过这种方式得到颜色、更多按钮的样式等素材,仅供学习之用,请勿做侵犯版权之事。尊重知识版权既是大势所趋,也是终将使每个开发者受益的事。
文件夹r里存放图片
找到更多按钮
5. 关键代码
开发环境:android studio 1.4.1 for mac + adt 21 + jdk 1.8.0。
mainacitivity.java
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<item> getdata() { int item_count = 20; arraylist<item> 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<item> mdata; private map<integer, itemview> mcachedviews = new hashmap<>(); public myadapter(context context, arraylist<item> 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
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(); } }
以上所述是小编给大家介绍的android 仿微信朋友圈点赞和评论弹出框功能,希望对大家有所帮助