打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
Android 仿微信点赞和评论弹出框

贡献/下载源码:https://github.com/mmlovesyy/PopupWindowDemo

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

1. 微信弹出框

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

  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();    }}

6. 感谢

本文中 listview 的布局改编自 http://download.csdn.net/download/weiyirong/6709151,感谢该作者的分享。

本文持续更新,转载请注明出处:http://blog.csdn.net/zhaizu/article/details/48103351

这是本人做的关于眼睛健康的微信公众号,专注 IT 人,只出精品图文,更有护眼知识闯关游戏,欢迎关注。



本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Android下拉刷新功能实现过程详解
ListView实现漂亮的自定义表格实例
android ListView和GridView拖拽移位具体实现及拓展
Android中WIFI开发总结(二)
LayoutInflater作用及使用
java-更新与数据库行相对应的ListView行中的CheckBox
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服