Android仿微信朋友圈7实现点赞功能
前言:
之前一直有朋友问我点赞怎么实现?今天趁着休息时间整理出来,其实点赞的功能和用户评论差不多,都是显示一个用户列表,只不过评论有评论内容和回复评论功能。实现点赞的思路如下:
1.当用户点击点赞按钮后,根据点赞状态来判断和显示:
1.1 如果此用户的操作是点赞,就把此用户加入到点赞列表中,并且点赞状态设置为1,然后请求点赞接口,刷新本地数据;
1.2 如果此用户的操作是取消点赞,此时循环查询点赞列表,如果此用户在点赞列表中就把此用户从列表中移除,如果不在点赞列表中就把此用户加入点赞列表,并且把点赞状态设置为0,请求点赞接口,刷新本地数据.
2.实现以上逻辑的主要代码截图如下:
/*** 请求点赞接口,这里写的模拟数据*/ private void getLikeData() {if (likeBean != null ) {List<CircleBean.DataBean> list = circleAdapter.getData();if (isLike == 1) {Iterator it = list.get(comPosition).getLike_list().iterator();List<LikeListBean> likeListBeans = new ArrayList<>();while (it.hasNext()) {LikeListBean info = (LikeListBean) it.next();if (info.getUser_id().equals(String.valueOf(userId))) {it.remove();} else {likeListBeans.add(info);}}LikeListBean likeListBean = new LikeListBean();likeListBean.setUser_id(userId+"");likeListBean.setUser_name(userName);list.get(comPosition).setIs_like(0);list.get(comPosition).setLike_list(likeListBeans);ToastUtils.ToastShort("取消点赞");} else {LikeListBean likeListBean = new LikeListBean();likeListBean.setUser_id(userId + "");likeListBean.setUser_name(userName);list.get(comPosition).getLike_list().add(likeListBean);list.get(comPosition).setIs_like(1);ToastUtils.ToastShort("点赞成功");}circleAdapter.notifyDataSetChanged();} }
3.实现的效果截图如下:由于是写的模拟数据,所以效果和真实的差不多,大家只要理解逻辑就行.
4.MainActivity完整代码如下:
package com.example.expandtextview; import android.Manifest; import android.annotation.SuppressLint; import android.app.Activity; import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.Rect; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.provider.MediaStore; import android.text.Editable; import android.text.TextUtils; import android.text.TextWatcher; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewTreeObserver; import android.widget.EditText; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; import androidx.annotation.Nullable; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; import androidx.constraintlayout.widget.ConstraintLayout; import androidx.recyclerview.widget.RecyclerView; import com.bumptech.glide.Glide; import com.bumptech.glide.load.DataSource; import com.bumptech.glide.load.engine.GlideException; import com.bumptech.glide.request.RequestListener; import com.bumptech.glide.request.target.Target; import com.example.expandtextview.activity.PlayVideoActivity; import com.example.expandtextview.activity.WatchLiveActivity; import com.example.expandtextview.adapter.CircleAdapter; import com.example.expandtextview.bean.CircleBean; import com.example.expandtextview.bean.CommentListBean; import com.example.expandtextview.bean.LikeBean; import com.example.expandtextview.bean.LikeListBean; import com.example.expandtextview.bean.WeatherEvent; import com.example.expandtextview.util.AssetsUtil; import com.example.expandtextview.util.CommonUtils; import com.example.expandtextview.util.Constants; import com.example.expandtextview.util.GlideSimpleTarget; import com.example.expandtextview.util.KeyboardUtil; import com.example.expandtextview.util.RxBus; import com.example.expandtextview.util.StorageUtil; import com.example.expandtextview.util.ToastUtils; import com.example.expandtextview.util.Utils; import com.example.expandtextview.view.LikePopupWindow; import com.example.expandtextview.view.OnPraiseOrCommentClickListener; import com.example.expandtextview.view.ScrollSpeedLinearLayoutManger; import com.example.expandtextview.view.SpaceDecoration; import com.github.ielse.imagewatcher.ImageWatcher; import com.tbruyelle.rxpermissions2.RxPermissions; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Objects; import io.reactivex.Observer; import io.reactivex.disposables.CompositeDisposable; import io.reactivex.disposables.Disposable; /*** @作者: njb* @时间: 2019/7/22 10:53* @描述: 仿微信朋友圈实现*/ public class MainActivity extends AppCompatActivity implements View.OnClickListener, CircleAdapter.Click, ImageWatcher.OnPictureLongPressListener, ImageWatcher.Loader {private RecyclerView recyclerView;private CircleAdapter circleAdapter;private String content;private LikePopupWindow likePopupWindow;private EditText etComment;private LinearLayout llComment;private TextView tvSend;private LinearLayout llScroll;private int editTextBodyHeight;private int currentKeyboardH;private int selectCommentItemOffset;private int commentPosition;protected final String TAG = this.getClass().getSimpleName();CompositeDisposable compositeDisposable;private ScrollSpeedLinearLayoutManger layoutManger;private List<CircleBean.DataBean> dataBeans;ImageWatcher imageWatcher;private int isLike;private int comPosition;private String to_user_id;private String to_user_name;private String circle_id;private String userId;private String userName;private RxPermissions rxPermissions;private static MyHandler myHandler;private static String dstPath;private ImageView ivBg;private ImageView ivUser;private TextView tvName;private ConstraintLayout clMessage;private ImageView ivMessage;private TextView tvMessage;private List<LikeListBean> likeBean; @Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initViews();initData();initAdapter();setListener();initRxBus();} private void initRxBus() {compositeDisposable = new CompositeDisposable();RxBus.getInstance().toObservable(WeatherEvent.class).subscribe(new Observer<WeatherEvent>() {@Overridepublic void onSubscribe(Disposable d) {compositeDisposable.add(d);} @Overridepublic void onNext(WeatherEvent weatherEvent) {Log.e("weather", weatherEvent.getTemperature() + "-**-" + weatherEvent.getCityName());} @Overridepublic void onError(Throwable e) { } @Overridepublic void onComplete() { }});} private void setListener() {tvSend.setOnClickListener(this);etComment.addTextChangedListener(new TextWatcher() {@Overridepublic void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { } @Overridepublic void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {content = etComment.getText().toString();if (etComment.getText().length() == 500) {Toast.makeText(MainActivity.this, getResources().getString(R.string.the_content_of_the_comment_cannot_exceed_500_words), Toast.LENGTH_SHORT).show();}} @Overridepublic void afterTextChanged(Editable editable) {}});recyclerView.setOnTouchListener((view, motionEvent) -> {if (llComment.getVisibility() == View.VISIBLE) {updateEditTextBodyVisible(View.GONE);return true;}return false;});circleAdapter.setOnItemChildClickListener((adapter, view, position) -> {userId = Objects.requireNonNull(circleAdapter.getItem(position)).getId();userName = Objects.requireNonNull(circleAdapter.getItem(position)).getUser_name();isLike = Objects.requireNonNull(circleAdapter.getItem(position)).getIs_like();likeBean = new ArrayList<>(0);likeBean = circleAdapter.getData().get(position).getLike_list();comPosition = position;switch (view.getId()) {case R.id.iv_edit://评论弹框showLikePopupWindow(view, position);break;case R.id.tv_delete://删除朋友圈deleteCircleDialog();break;//点击视频按钮跳转到视频播放界面case R.id.video_view:Intent intent = new Intent(this, PlayVideoActivity.class);intent.putExtra("url", Objects.requireNonNull(circleAdapter.getItem(position)).getVideo());startActivity(intent);break;default:break;}});} private void showLikePopupWindow(View view, int position) {//item 底部y坐标final int mBottomY = getCoordinateY(view) + view.getHeight();if (likePopupWindow == null) {likePopupWindow = new LikePopupWindow(this, isLike);}likePopupWindow.setOnPraiseOrCommentClickListener(new OnPraiseOrCommentClickListener() {@Overridepublic void onPraiseClick(int position) {//调用点赞接口getLikeData();likePopupWindow.dismiss();} @Overridepublic void onCommentClick(int position) {llComment.setVisibility(View.VISIBLE);etComment.requestFocus();etComment.setHint("说点什么");to_user_id = null;KeyboardUtil.showSoftInput(MainActivity.this);likePopupWindow.dismiss();etComment.setText("");view.postDelayed(() -> {int y = getCoordinateY(llComment) - 20;//评论时滑动到对应item底部和输入框顶部对齐recyclerView.smoothScrollBy(0, mBottomY - y);}, 300);} @Overridepublic void onClickFrendCircleTopBg() { } @Overridepublic void onDeleteItem(String id, int position) { } }).setTextView(isLike).setCurrentPosition(position);if (likePopupWindow.isShowing()) {likePopupWindow.dismiss();} else {likePopupWindow.showPopupWindow(view);}} /*** 请求点赞接口,这里写的模拟数据*/private void getLikeData() {if (likeBean != null ) {List<CircleBean.DataBean> list = circleAdapter.getData();if (isLike == 1) {Iterator it = list.get(comPosition).getLike_list().iterator();List<LikeListBean> likeListBeans = new ArrayList<>();while (it.hasNext()) {LikeListBean info = (LikeListBean) it.next();if (info.getUser_id().equals(String.valueOf(userId))) {it.remove();} else {likeListBeans.add(info);}}LikeListBean likeListBean = new LikeListBean();likeListBean.setUser_id(userId+"");likeListBean.setUser_name(userName);list.get(comPosition).setIs_like(0);list.get(comPosition).setLike_list(likeListBeans);ToastUtils.ToastShort("取消点赞");} else {LikeListBean likeListBean = new LikeListBean();likeListBean.setUser_id(userId + "");likeListBean.setUser_name(userName);list.get(comPosition).getLike_list().add(likeListBean);list.get(comPosition).setIs_like(1);ToastUtils.ToastShort("点赞成功");}circleAdapter.notifyDataSetChanged();}} private void deleteCircleDialog() {final AlertDialog.Builder alert = new AlertDialog.Builder(this);alert.setTitle("提示");alert.setMessage("你确定要删除吗?");alert.setNegativeButton("取消", null);alert.setPositiveButton("确定", (dialog, which) -> {//调接口删除,这里写死dialog.dismiss();startActivity(new Intent(this, WatchLiveActivity.class));});alert.show();} private void setViewTreeObserver() {final ViewTreeObserver swipeRefreshLayoutVTO = llScroll.getViewTreeObserver();swipeRefreshLayoutVTO.addOnGlobalLayoutListener(() -> {Rect r = new Rect();llScroll.getWindowVisibleDisplayFrame(r);int statusBarH = Utils.getStatusBarHeight();//状态栏高度int screenH = llScroll.getRootView().getHeight();if (r.top != statusBarH) {//r.top代表的是状态栏高度,在沉浸式状态栏时r.top=0,通过getStatusBarHeight获取状态栏高度r.top = statusBarH;}int keyboardH = screenH - (r.bottom - r.top);Log.d(TAG, "screenH= " + screenH + " &keyboardH = " + keyboardH + " &r.bottom=" + r.bottom + " &top=" + r.top + " &statusBarH=" + statusBarH); if (keyboardH == currentKeyboardH) {//有变化时才处理,否则会陷入死循环return;}currentKeyboardH = keyboardH;editTextBodyHeight = llComment.getHeight();if (keyboardH < 150) {//说明是隐藏键盘的情况MainActivity.this.updateEditTextBodyVisible(View.GONE);return;}});} /*** 初始化控件*/private void initViews() {recyclerView = findViewById(R.id.recyclerView);llComment = findViewById(R.id.ll_comment);etComment = findViewById(R.id.et_comment);tvSend = findViewById(R.id.tv_send_comment);llScroll = findViewById(R.id.ll_scroll);imageWatcher = findViewById(R.id.imageWatcher);//初始化仿微信图片滑动加载器imageWatcher.setTranslucentStatus(Utils.calcStatusBarHeight(this));imageWatcher.setErrorImageRes(R.mipmap.error_picture);imageWatcher.setOnPictureLongPressListener(this);imageWatcher.setLoader(this);getPermissions();myHandler = new MyHandler(this);} /*** 初始化数据** @param*/private void initData() {dataBeans = new ArrayList<>();dataBeans = AssetsUtil.getStates(this);} /*** 设置adapter*/private void initAdapter() {View headCircle = LayoutInflater.from(MainActivity.this).inflate(R.layout.item_circle_head, null);initHead(headCircle);circleAdapter = new CircleAdapter(dataBeans, imageWatcher, llComment, etComment, this);layoutManger = new ScrollSpeedLinearLayoutManger(this);recyclerView.setLayoutManager(layoutManger);layoutManger.setSpeedSlow();circleAdapter.addHeaderView(headCircle);recyclerView.addItemDecoration(new SpaceDecoration(this));recyclerView.setAdapter(circleAdapter);} /*** 初始化消息提醒布局* @param headCircle*/private void initHead(View headCircle) {ivBg = headCircle.findViewById(R.id.iv_bg);ivUser = headCircle.findViewById(R.id.iv_user);tvName = headCircle.findViewById(R.id.tv_name);clMessage = headCircle.findViewById(R.id.cl_message);ivMessage = headCircle.findViewById(R.id.message_avatar);tvMessage = headCircle.findViewById(R.id.message_detail);ivBg.setOnClickListener(this);ivUser.setOnClickListener(this);//这里是调用接口数据,本例子写的假数据,可以自己根据需求来写clMessage.setVisibility(View.VISIBLE);tvMessage.setText("10条新信息");} public void updateEditTextBodyVisible(int visibility) {llComment.setVisibility(visibility);if (View.VISIBLE == visibility) {llComment.requestFocus();//弹出键盘CommonUtils.showSoftInput(etComment.getContext(), etComment); } else if (View.GONE == visibility) {//隐藏键盘CommonUtils.hideSoftInput(etComment.getContext(), etComment);}} /*** 获取控件左上顶点Y坐标** @param view* @return*/private int getCoordinateY(View view) {int[] coordinate = new int[2];view.getLocationOnScreen(coordinate);return coordinate[1];} @Overridepublic void onClick(View view) {int i = view.getId();if (i == R.id.tv_send_comment) {if (TextUtils.isEmpty(etComment.getText().toString())) {Toast.makeText(MainActivity.this, "请输入评论内容", Toast.LENGTH_SHORT).show();return;}//请求接口,在成功回调方法拼接评论信息,这里写死getComment();setViewTreeObserver();}} private void getComment() {List<CircleBean.DataBean> list = circleAdapter.getData();CommentListBean commentListBean = new CommentListBean();//userId为当前用户id,这里只是一个例子所以没有登录注册commentListBean.setUser_id(userId);//userName为当前用户名称commentListBean.setUser_name(userName);commentListBean.setTo_user_name(TextUtils.isEmpty(to_user_name) ? "" : to_user_name);commentListBean.setTo_user_id(TextUtils.isEmpty(to_user_id) ? "" : to_user_id);commentListBean.setCircle_id(circle_id);commentListBean.setContent(content);if (TextUtils.isEmpty(to_user_id)) {ToastUtils.ToastShort("评论成功");list.get(comPosition).getComments_list().add(commentListBean);} else {ToastUtils.ToastShort("回复成功");list.get(commentPosition).getComments_list().add(commentListBean);}circleAdapter.notifyDataSetChanged();KeyboardUtil.hideSoftInput(MainActivity.this);llComment.setVisibility(View.GONE);etComment.setText("");} @Overrideprotected void onDestroy() {super.onDestroy();//取消订阅RxBus.rxBusUnbund(compositeDisposable);myHandler.removeCallbacksAndMessages(null);} @Overridepublic void Commend(int position, CommentListBean bean) {circle_id = bean.getCircle_id();commentPosition = position;to_user_name = bean.getUser_name();to_user_id = bean.getUser_id();} @Overridepublic void load(Context context, Uri uri, ImageWatcher.LoadCallback loadCallback) {Glide.with(context).asBitmap().load(uri.toString()).into(new GlideSimpleTarget(loadCallback));} @Overridepublic void onPictureLongPress(ImageView v, Uri uri, int pos) {final AlertDialog.Builder alert = new AlertDialog.Builder(this);alert.setTitle("保存图片");alert.setMessage("你确定要保存图片吗?");alert.setNegativeButton("取消", null);alert.setPositiveButton("确定", (dialog, which) -> {rxPermissions.request(Manifest.permission.WRITE_EXTERNAL_STORAGE).subscribe(granted -> {if (granted) {if (uri != null) {// Always true pre-MsavePhoto(uri);}} else {ToastUtils.ToastShort("缺少必要权限,请授予权限");}});dialog.dismiss(); });alert.show();} @SuppressLint("HandlerLeak")private class MyHandler extends Handler {private WeakReference<Activity> mActivity;private Bitmap bitmap; private MyHandler(Activity activity) {mActivity = new WeakReference<>(activity);} @Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);final Activity activity = mActivity.get();if (activity != null) {if (msg.what == 1) {try {bitmap = (Bitmap) msg.obj;if (Utils.saveBitmap(bitmap, dstPath, false)) {try {ContentValues values = new ContentValues(2);values.put(MediaStore.Images.Media.MIME_TYPE, Constants.MIME_JPEG);values.put(MediaStore.Images.Media.DATA, dstPath);getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);ToastUtils.ToastShort(activity, getResources().getString(R.string.picture_save_to));} catch (Exception e) {ToastUtils.ToastShort(activity, getResources().getString(R.string.picture_save_fail));}} else {ToastUtils.ToastShort(activity, getResources().getString(R.string.picture_save_fail));}} catch (Exception e) {e.printStackTrace();ToastUtils.ToastShort(activity, getResources().getString(R.string.picture_save_fail));}}}}} private void getPermissions() {rxPermissions = new RxPermissions(this);} /*** 长按保存图片* @param uri 图片url地址*/private void savePhoto(Uri uri) {Glide.with(MainActivity.this).asBitmap().load(uri).listener(new RequestListener<Bitmap>() {@Overridepublic boolean onResourceReady(Bitmap resource, Object model, Target<Bitmap> target, DataSource dataSource, boolean isFirstResource) {String picPath = StorageUtil.getSystemImagePath();dstPath = picPath + (System.currentTimeMillis() / 1000) + ".jpeg";Message message = Message.obtain();message.what = 1;message.obj = resource;myHandler.sendMessage(message);return false;} @Overridepublic boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) {return false;}}).submit();} }
5.以上就是实现仿朋友圈点赞的简单实现,大家理解逻辑后可以自行尝试,如有问题及时提示,我一定会吸取好的建议,多多学习,一起成长。
6.项目的完整源码地址:
ExpandTextView: 实现仿微信朋友圈列表多类型布局,图片点击放大、保存,包含点赞、评论、消息提醒、视频播放等功能
Android仿微信朋友圈7实现点赞功能相关推荐
- Android仿微信朋友圈2自定义点赞评论弹框
最近在做类似微信朋友圈点赞评论的功能,有个点赞评论弹框交互,感觉效果很好,点击评论按钮弹框从按钮左边弹出,遇到了3个问题(弹出动画不对.弹框布局没有适配.弹出的位置显示不对),动画和布局好解决,弹出的 ...
- android 微信朋友圈 全功能,Android仿微信朋友圈文字展开全文功能 Android自定义TextView仿微信朋友圈文字展开全文功能...
Android自定义TextView仿微信朋友圈文字信息,展开全文功能 代码及注释如下: 首先写一个xml文件 showmore.xml: android:orientation="vert ...
- Android仿微信朋友圈,全文收起功能,附源码
在众多的社交类软件中,朋友圈是必不可少的,可以与好友.同学等分享自己的日常和有意思的事情,在开发社交类App时,朋友圈发表的内容你不可能让他全部显示,全部显示的话用户体验度会非常不好,这时就要用到全文 ...
- Android 仿微信朋友圈 全文,收起功能
一.添加依赖 implementation 'com.android.support:recyclerview-v7:28.0.0' 二.资源配置 1.drawable文件夹下的shape文件 < ...
- Android自定义弹窗模仿微信,Android 仿微信朋友圈点赞和评论弹出框功能
本文简单模仿微信朋友圈的点赞和评论弹出框,布局等细节请忽略,着重实现弹出框.发评论,及弹出位置的控制. 1. 微信弹出框 微信朋友圈的点赞和评论功能,有2个组成部分: 点击左下角的"更多&q ...
- Android仿微信朋友圈6之实现消息提醒功能
之前有朋友问我消息提醒咋实现,我一直没有整理出来,今天就放出来.微信朋友圈的消息提醒就是收到朋友的评论后背景底部显示消息条数和评论用户,顶部是一张相册背景和当前用户昵称头像. 1.消息提醒的布局如下: ...
- android 仿微信朋友圈 评论,2020年android 仿微信朋友圈 评论
2020年android 仿微信朋友圈 评论 1.如果有人问我:那些艰难的岁月你是怎么熬过来的?我想我只有一句话回答:我有一种强大的精神力量支撑着我,这种力量名字叫"想死又不敢" ...
- android com.mylhyl,Android 高仿微信朋友圈拍照上传功能
模仿微信朋友圈发布动态,输入文字支持文字多少高度自增,有一个最小输入框高度,输入文字有限制,不过这些都很easy! 1. photopicker的使用 这是一个支持选择多张图片,点击图片放大,图片之间 ...
- android 微信高仿,Android 高仿微信朋友圈拍照上传功能
模仿微信朋友圈发布动态,输入文字支持文字多少高度自增,有一个最小输入框高度,输入文字有限制,不过这些都很easy! 1. PhotoPicker的使用 这是一个支持选择多张图片,点击图片放大,图片之间 ...
最新文章
- 小程序生成二维码报错:40169:invalid length for scene, or the data is not json string
- strlen和mb_strlen的区别
- 计算机组成原理xchg,8088数据传送指令-计算机组成原理与汇编语言-电子发烧友网站...
- mysql hibernate 分页查询_Hibernate + MySQL 分页类的实现
- 被“薅羊毛”损失200多万!元气森林:系运营事故
- 动态规划 —— 求解通配符问题(wildcard)
- 在鼠标点击的位置 ,添加一个div ,类似手表右键菜单
- Windows内核原理与实现之Windows研究内核(WRK)
- 关键成功因素法(CrISical Success Factors,CSF)
- 树莓派python调用摄像头拍照
- 使用皮卡(pika)操作RabbitMQ
- Android车载技术之蓝牙通讯——如何蓝牙播放音乐
- SoX使用手册(中文版)
- 2014年 IT 行业校招待遇
- 关于crawl DZDP的城市商场名称和地址的参考
- 编程之美--3.5最短摘要的生成
- Keil软件Project显示隐藏.h头文件的方法
- word中图片不显示的解决办法
- EasyPlayer RTSP播放器:一个适用于安防行业的工具利器(EasyPlayer Windows v2.0.17.0709)
- 种草!超好用的PDF转换器上线啦~