Android仿微信朋友圈5实现朋友圈列表
·
前言:
微信朋友圈网上有很多开源的例子,本文是自己手写,之前的几篇都是单个功能,感觉很零散,这次放出完整的点赞评论和朋友圈列表功能,大家有兴趣可以看一下
1.定义四种item类型,可以按后台接口自行定义类型:
2.CircleAdapter实现代码:
部分核心代码截图:
3.CircleAdapter完整代码:
/** * @作者: njb * @时间: 2019/7/25 10:47 * @描述: 朋友圈适配器 */ public class CircleAdapter extends BaseMultiItemQuickAdapter<CircleBean.DataBean,BaseViewHolder>{ private TextView tvAddress, tvDelete; private ImageView imageView; private ExpandTextView tvContent; private ImageWatcher imageWatcher; private RequestOptions mRequestOptions; private DrawableTransitionOptions mDrawableTransitionOptions; private LinearLayout llComment; private EditText etComment; private int x; private int y; private PopupWindow mPopupWindow; private Click click; public CircleAdapter(@Nullable List<CircleBean.DataBean> data, ImageWatcher imageWatcher, LinearLayout llComment, EditText etComment, Click click) { super(data); //文本 addItemType(Constants.TYPE_TEXT, R.layout.item_text); //图片 addItemType(Constants.TYPE_IMAGE, R.layout.item_image); //视频 addItemType(Constants.TYPE_VIDEO, R.layout.item_video); //网页 addItemType(Constants.TYPE_WEB, R.layout.item_web); this.imageWatcher = imageWatcher; this.mRequestOptions = new RequestOptions().centerCrop(); this.mDrawableTransitionOptions = DrawableTransitionOptions.withCrossFade(); this.llComment = llComment; this.etComment = etComment; this.click = click; } @Override protected void convert(@NonNull BaseViewHolder helper, CircleBean.DataBean item) { if(item == null){ return; } imageView = helper.getView(R.id.iv_photo); tvContent = helper.getView(R.id.tv_content); tvAddress = helper.getView(R.id.tv_address); tvDelete = helper.getView(R.id.tv_delete); switch (item.getItemType()) { //文本 case Constants.TYPE_TEXT: //用户名 if (item.getUser_name() != null && !item.getUser_name().equals("")) { helper.setText(R.id.tv_name, item.getUser_name()); } //评论时间 if (item.getCreateon() != null && !item.getCreateon().equals("")) { helper.setText(R.id.tv_time, item.getCreateon()); } break; //图片 case Constants.TYPE_IMAGE: if (item.getUser_name() != null && !item.getUser_name().equals("")) { helper.setText(R.id.tv_name, item.getUser_name()); } if (item.getCreateon() != null && !item.getCreateon().equals("")) { helper.setText(R.id.tv_time, item.getCreateon()); } NineGridView layout = helper.getView(R.id.layout_nine); layout.setSingleImageSize(80, 120); if (item.getFiles() != null && item.getFiles().size() > 0) { layout.setAdapter(new NineImageAdapter(mContext, mRequestOptions, mDrawableTransitionOptions, item.getFiles())); layout.setOnImageClickListener((position, view) -> { imageWatcher.show((ImageView) view, layout.getImageViews(), item.getImageUriList()); }); } break; //视频 case Constants.TYPE_VIDEO: if (item.getUser_name() != null && !item.getUser_name().equals("")) { helper.setText(R.id.tv_name, item.getUser_name()); } if (item.getCreateon() != null && !item.getCreateon().equals("")) { helper.setText(R.id.tv_time, item.getCreateon()); } ImageView ivVideo = helper.getView(R.id.video_view); //视频封面图 if (item.getFiles() != null && item.getFiles().size() > 0) { GlideUtils.loadImg(mContext, item.getFiles().get(0), ivVideo); } break; //网页 case Constants.TYPE_WEB: ImageView ivUser = helper.getView(R.id.iv_user); if (item.getUser_name() != null && !item.getUser_name().equals("")) { helper.setText(R.id.tv_name, item.getUser_name()); } if (item.getCreateon() != null && !item.getCreateon().equals("")) { helper.setText(R.id.tv_time, item.getCreateon()); } if (item.getShare_image() != null && !item.getShare_image().equals("")) { GlideUtils.loadImg(mContext, item.getShare_image(), ivUser, R.drawable.ic_launcher_background); } if (item.getShare_title() != null && !item.getShare_title().equals("")) { helper.setText(R.id.tv_text, item.getShare_title()); } else { helper.setText(R.id.tv_text, ""); } break; } //用户头像 if (!TextUtils.isEmpty(item.getHead_img())) { GlideUtils.loadImg(mContext, item.getHead_img(), imageView, R.drawable.ic_launcher_background); } else { imageView.setImageResource(R.drawable.ic_launcher_background); } //评论内容 if (TextUtils.isEmpty(item.getContent())) { tvContent.setVisibility(View.GONE); } else { tvContent.setVisibility(View.VISIBLE); tvContent.setText(item.getContent()); } if (!TextUtils.isEmpty(item.getPosition()) && !item.getPosition().equals("该位置信息暂无")) { tvAddress.setVisibility(View.VISIBLE); tvAddress.setText(item.getPosition()); } else { tvAddress.setVisibility(View.GONE); } tvDelete.setVisibility(View.VISIBLE); LinearLayout llLike = helper.getView(R.id.ll_like); PraiseListView rvLike = helper.getView(R.id.rv_like); CommentsView rvComment = helper.getView(R.id.rv_comment); View viewLike = helper.getView(R.id.view_like); helper.addOnClickListener(R.id.iv_edit); helper.addOnClickListener(R.id.tv_like); helper.addOnClickListener(R.id.tv_delete); helper.addOnClickListener(R.id.iv_user); helper.addOnClickListener(R.id.video_view); helper.addOnClickListener(R.id.iv_photo); helper.addOnClickListener(R.id.tv_name); helper.addOnClickListener(R.id.ll_share); helper.addOnLongClickListener(R.id.tv_content); if ((item.getLike_list() != null && item.getLike_list().size() > 0) && (item.getComments_list() != null && item.getComments_list().size() > 0)) { viewLike.setVisibility(View.VISIBLE); } else { viewLike.setVisibility(View.GONE); } if ((item.getLike_list() != null && item.getLike_list().size() > 0) || (item.getComments_list() != null && item.getComments_list().size() > 0)) { llLike.setVisibility(View.VISIBLE); if (item.getLike_list() != null && item.getLike_list().size() > 0) { rvLike.setVisibility(View.VISIBLE); LikeListAdapter likeListAdapter = new LikeListAdapter(item.getLike_list()); rvLike.setDatas(item.getLike_list()); } else { rvLike.setVisibility(View.GONE); } if (item.getComments_list() != null && item.getComments_list().size() > 0) { rvComment.setVisibility(View.VISIBLE); rvComment.setList(item.getComments_list()); rvComment.setOnCommentListener((position, bean, user_id) -> { etComment.setText(""); //如果当前用户id和评论用户id相同则删除 if (bean.getCommentsUser().getUserId().equals("1")) { showDeletePopWindow(rvComment, Integer.parseInt(bean.getId()), helper.getLayoutPosition() - 1, position); llComment.setVisibility(View.GONE); } else { //不相同回复 llComment.setVisibility(View.VISIBLE); etComment.setHint("回复:" + bean.getCommentsUser().getUserName()); if (View.VISIBLE == llComment.getVisibility()) { llComment.requestFocus(); //弹出键盘 KeyboardUtil.showSoftInput(etComment.getContext(), etComment); } else if (View.GONE == llComment.getVisibility()) { //隐藏键盘 KeyboardUtil.hideSoftInput(etComment.getContext(), etComment); } if (click != null) { click.Commend(helper.getLayoutPosition() - 1, bean); } } }); rvComment.notifyDataSetChanged(); } else { rvComment.setVisibility(View.GONE); } } else { llLike.setVisibility(View.GONE); } rvComment.setOnItemLongClickListener((position, bean) -> { showCopyPopWindow(rvComment, item.getComments_list().get(position).getContent()); }); } private void showCopyPopWindow(CommentsView rvComment, String content) { View contentView = getCopyPopupWindowContentView(content); mPopupWindow = new PopupWindow(contentView, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, true); // 如果不设置PopupWindow的背景,有些版本就会出现一个问题:无论是点击外部区域还是Back键都无法dismiss弹框 mPopupWindow.setBackgroundDrawable(new ColorDrawable()); // 设置好参数之后再show int[] windowPos = PopupWindowUtil.calculatePopWindowPos(rvComment, contentView, x, y); mPopupWindow.showAsDropDown(rvComment, 0, -60, windowPos[1]); mPopupWindow.setFocusable(true); mPopupWindow.setOutsideTouchable(true); } private View getCopyPopupWindowContentView(String content) { // 布局ID int layoutId = R.layout.popup_copy; View contentView = LayoutInflater.from(mContext).inflate(layoutId, null); View.OnClickListener menuItemOnClickListener = v -> { if (mPopupWindow != null) { mPopupWindow.dismiss(); } ClipboardManager mCM = (ClipboardManager) mContext.getSystemService(CLIPBOARD_SERVICE); mCM.setPrimaryClip(ClipData.newPlainText(null, content)); Toast.makeText(mContext, mContext.getString(R.string.copied), Toast.LENGTH_SHORT).show(); }; contentView.findViewById(R.id.menu_copy).setOnClickListener(menuItemOnClickListener); return contentView; } private void showDeletePopWindow(View view, int id, int layoutPosition, int position) { View contentView = getPopupWindowContentView(id, layoutPosition, position); mPopupWindow = new PopupWindow(contentView, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, true); // 如果不设置PopupWindow的背景,有些版本就会出现一个问题:无论是点击外部区域还是Back键都无法dismiss弹框 mPopupWindow.setBackgroundDrawable(new ColorDrawable()); // 设置好参数之后再show int[] windowPos = PopupWindowUtil.calculatePopWindowPos(view, contentView, x, y); mPopupWindow.showAsDropDown(view, 0, -40, windowPos[1]); mPopupWindow.setFocusable(true); mPopupWindow.setOutsideTouchable(true); } private View getPopupWindowContentView(int id, int layoutPosition, int position) { // 布局ID int layoutId = R.layout.popup_delete; View contentView = LayoutInflater.from(mContext).inflate(layoutId, null); View.OnClickListener menuItemOnClickListener = v -> { if (mPopupWindow != null) { mPopupWindow.dismiss(); } }; contentView.findViewById(R.id.menu_delete).setOnClickListener(menuItemOnClickListener); return contentView; } public interface Click { //回复评论 void Commend(int position, CommentListBean bean); } }
4.MainActivity代码:
部分代码截图:
5.MainActivity完整代码:
/** * @作者: 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 TextView tvCity; 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; @Override protected 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>() { @Override public void onSubscribe(Disposable d) { compositeDisposable.add(d); } @Override public void onNext(WeatherEvent weatherEvent) { Log.e("weather", weatherEvent.getTemperature() + "-**-" + weatherEvent.getCityName()); tvCity.setText(String.format("%s %s", weatherEvent.getCityName(), weatherEvent.getTemperature())); } @Override public void onError(Throwable e) { } @Override public void onComplete() { } }); } private void setListener() { tvSend.setOnClickListener(this); etComment.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { } @Override public 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(); } } @Override public 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(); comPosition = position; switch (view.getId()) { case R.id.iv_edit: //评论弹框 showLikePopupWindow(view, position); break; case R.id.tv_delete: //删除朋友圈 deleteCircleDialog(); 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() { @Override public void onPraiseClick(int position) { //调用点赞接口 likePopupWindow.dismiss(); } @Override public 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); } @Override public void onClickFrendCircleTopBg() { } @Override public void onDeleteItem(String id, int position) { } }).setTextView(isLike).setCurrentPosition(position); if (likePopupWindow.isShowing()) { likePopupWindow.dismiss(); } else { likePopupWindow.showPopupWindow(view); } } private void deleteCircleDialog() { final AlertDialog.Builder alert = new AlertDialog.Builder(this); alert.setTitle("提示"); alert.setMessage("你确定要删除吗?"); alert.setNegativeButton("取消", null); alert.setPositiveButton("确定", (dialog, which) -> { //调接口删除 dialog.dismiss(); }); 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) { //在这个demo中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); tvCity = findViewById(R.id.tv_city); 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() { circleAdapter = new CircleAdapter(dataBeans, imageWatcher, llComment, etComment, this); layoutManger = new ScrollSpeedLinearLayoutManger(this); recyclerView.setLayoutManager(layoutManger); layoutManger.setSpeedSlow(); recyclerView.addItemDecoration(new SpaceDecoration(this)); recyclerView.setAdapter(circleAdapter); } 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]; } @Override public 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(""); } @Override protected void onDestroy() { super.onDestroy(); //取消订阅 RxBus.rxBusUnbund(compositeDisposable); myHandler.removeCallbacksAndMessages(null); } @Override public 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(); } @Override public void load(Context context, Uri uri, ImageWatcher.LoadCallback loadCallback) { Glide.with(context).asBitmap().load(uri.toString()).into(new GlideSimpleTarget(loadCallback)); } @Override public 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-M savePhoto(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); } @Override public 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>() { @Override public 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; } @Override public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) { return false; } }).submit(); }
6.视频播放:
7.视频播放Activity,部分代码截图:
8.视频播放完整代码:
/** * @作者: njb * @时间: 2020/1/2 14:02 * @描述: 视频播放 */ public class PlayVideoActivity extends AppCompatActivity { private String url; private IjkVideoView videoView; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_play_video); initData(); initViews(); initPlayer(); startPlay(); } private void initViews() { //播放view videoView = findViewById(R.id.video_view); } private void initData() { if(getIntent()!= null&& getIntent().getExtras()!= null){ //视频url url = getIntent().getExtras().getString("url"); } } /** * 初始化Player */ private void initPlayer() { com.dueeeke.videocontroller.StandardVideoController controller = new StandardVideoController(this); IjkPlayer ijkPlayer = new IjkPlayer(this) { @Override public void setOptions() { super.setOptions(); mMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "dns_cache_clear", 1); } }; videoView.setPlayerConfig(new PlayerConfig.Builder().setCustomMediaPlayer(ijkPlayer).build()); videoView.setVideoController(controller); } /** * 开始播放 */ private void startPlay() { if (url != null) { videoView.setUrl(url); videoView.start(); videoView.isFullScreen(); } } @Override public void onConfigurationChanged(@NonNull Configuration newConfig) { super.onConfigurationChanged(newConfig); //横竖屏切换 refresh(); } /** * 横竖屏切换刷新 */ private void refresh() { boolean isBaseOnWidth = (getResources().getDisplayMetrics().widthPixels <= getResources().getDisplayMetrics().heightPixels); Window window = getWindow(); if(window != null){ window.getDecorView().post(() -> { window.getDecorView().setVisibility(View.GONE); AutoSizeCompat.autoConvertDensity(getResources(),420,isBaseOnWidth); window.getDecorView().setVisibility(View.VISIBLE); }); } } @Override public void onResume() { super.onResume(); if (videoView != null) { videoView.resume(); } } @Override public void onPause() { super.onPause(); if (videoView != null) { videoView.pause(); } } @Override public void onBackPressed() { if (!videoView.onBackPressed()) { super.onBackPressed(); } super.onBackPressed(); } @Override protected void onDestroy() { super.onDestroy(); //释放播放器 if (videoView != null) { videoView.release(); videoView = null; } } }
9.总结:
图片保存刚开始没用线程,导致要保存2次才能成功,后面改为handler发消息,后面会加上视频播放和点击item跳转网页详情,这一篇也是在前几篇的基础上,解决了很多问题,比如适配9.0http访问网络、约束布局的使用、评论时定位到当前位置、使用第三方状态栏库导致输入框焦点不弹出、评论成功后不是请求后台数据而是刷新本地数据等等.本例子是写的假数据,实时请求还需修改请求逻辑,基本的逻辑都写好了,如有问题及时反馈,我会积极改进.
10.最后放几张完整的效果图:
11.demo完整代码地址:
ExpandTextView: 实现仿微信朋友圈列表多类型布局,图片点击放大、保存,包含点赞、评论、消息提醒、视频播放等功能
更多推荐
已为社区贡献7条内容
所有评论(0)