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

Posted 陈蒙_

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 仿微信点赞和评论弹出框相关的知识,希望对你有一定的参考价值。

下载源码:http://download.csdn.net/detail/zhaizu/9790030

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

#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

以上是关于Android 仿微信点赞和评论弹出框的主要内容,如果未能解决你的问题,请参考以下文章

Android LayoutInflater

微信点赞功能测试用例

Redis缓存 + 定时写入DB,仿微信点赞模块设计

高仿微信朋友圈

iOS仿微信弹出框LPActionSheet

iOS仿微信弹出框LPActionSheet