Android仿微信朋友圈全文、收起功能的实例代码

前言

一般在社交APP中都有类似朋友圈的功能,其中发表的动态内容很长的时候不可能让它全部显示。这里就需要做一个仿微信朋友圈全文、收起功能来解决该问题。在网上看到一个例子-->http://www.jb51.net/article/105251.htm,写的很不错,但是有个bug,他这个Demo只有在条目固定的时候才正常,当增加、删除条目的时候会出现全文、收起显示混乱的问题。原因是他使用了固定的position作为key来保存当前显示的状态。这篇文章在他的基础上进行优化。

效果图

具体代码

(详细解释在代码注释中都有,这里就省略了)

MainActivity.java

package com.wildma.wildmaexpandfoldtext;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;

import java.util.ArrayList;
import java.util.List;

/**
 * Author   wildma
 * DATE    2017/8/3
 * Des    ${TODO}
 */
public class MainActivity extends AppCompatActivity {
  private RecyclerView mRecyclerView;
  List<ExpandFoldTextBean> mList = new ArrayList<>();

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    initData();
    ExpandFoldTextAdapter adapter = new ExpandFoldTextAdapter(mList, this);
    mRecyclerView = (RecyclerView) findViewById(R.id.recyclerview);
    mRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
    mRecyclerView.setAdapter(adapter);
  }

  /**
   * 初始化数据
   */
  private void initData() {
    String longContent = "-->游泳、快走、慢跑、骑自行车,及一切有氧运动都能锻炼心脏。有氧运动好处多:能锻炼心肺、增强循环系统功能、燃烧脂肪、加大肺活量、降低血压,甚至能预防糖尿病,减少心脏病的发生。美国运动医学院建议,想知道有氧运动强度是否合适,可在运动后测试心率,以达到最高心率的60%—90%为宜。如果想通过有氧运动来减肥,可以选择低度到中度的运动强度,同时延长运动时间,这种方法消耗的热量更多。运动频率每周3—5次,每次20—60分钟。想要锻炼肌肉,可以练举重、做体操以及其他重复伸、屈肌肉的运动。肌肉锻炼可以燃烧热量、增强骨密度、减少受伤,尤其是关节受伤的几率,还能预防骨质疏松。 在做举重运动前,先测一下,如果连续举8次你最多能举多重的东西,就从这个重量开始练习。当你可以连续12次举起这个重量时,试试增加5%的重量。注意每次练习时,要连续举8—12次,这样可以达到肌肉最大耐力的70%—80%,锻炼效果较好。每周2—3次,但要避免连续两天锻炼同一组肌肉群, 以便让肌肉有充分的恢复时间。";
    String shortContent = "-->健身是一种体育项目,如各种徒手健美操、韵律操、形体操以及各种自抗力动作。";
    for (int i = 0; i < 20; i++) {
      ExpandFoldTextBean bean = new ExpandFoldTextBean();
      if (i % 2 == 0) {
        bean.setContent(i + shortContent);
        bean.setId(i);
      } else {
        bean.setContent(i + longContent);
        bean.setId(i);
      }
      mList.add(bean);
    }
  }
}

ExpandFoldTextAdapter.java

package com.wildma.wildmaexpandfoldtext;

import android.app.Activity;
import android.support.v7.widget.RecyclerView;
import android.util.SparseArray;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.TextView;

import java.util.List;

/**
 * Author   wildma
 * DATE    2017/8/3
 * Des    ${展开折叠文本适配器}
 */
public class ExpandFoldTextAdapter extends RecyclerView.Adapter<ExpandFoldTextAdapter.MyViewHolder> {
  private Activity mContent;

  private final int MAX_LINE_COUNT = 3;//最大显示行数

  private final int STATE_UNKNOW = -1;//未知状态

  private final int STATE_NOT_OVERFLOW = 1;//文本行数小于最大可显示行数

  private final int STATE_COLLAPSED = 2;//折叠状态

  private final int STATE_EXPANDED = 3;//展开状态

  /**
   * 注意:保存文本状态集合的key一定要是唯一的,如果用position。
   * 如果使用position作为key,则删除、增加条目的时候会出现显示错乱
   */
  private SparseArray<Integer> mTextStateList;//保存文本状态集合

  List<ExpandFoldTextBean> mList;

  public ExpandFoldTextAdapter(List<ExpandFoldTextBean> list, Activity context) {
    mContent = context;
    this.mList = list;
    mTextStateList = new SparseArray<>();
  }

  @Override
  public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    return new MyViewHolder(mContent.getLayoutInflater().inflate(R.layout.item_expand_fold_text, parent, false));
  }

  @Override
  public void onBindViewHolder(final MyViewHolder holder, final int position) {
    int state = mTextStateList.get(mList.get(position).getId(), STATE_UNKNOW);
    //第一次初始化,未知状态
    if (state == STATE_UNKNOW) {
      holder.content.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
        @Override
        public boolean onPreDraw() {
          //这个回掉会调用多次,获取完行数后记得注销监听
          holder.content.getViewTreeObserver().removeOnPreDrawListener(this);
          //holder.content.getViewTreeObserver().addOnPreDrawListener(null);
          //如果内容显示的行数大于最大显示行数
          if (holder.content.getLineCount() > MAX_LINE_COUNT) {
            holder.content.setMaxLines(MAX_LINE_COUNT);//设置最大显示行数
            holder.expandOrFold.setVisibility(View.VISIBLE);//显示“全文”
            holder.expandOrFold.setText("全文");
            mTextStateList.put(mList.get(position).getId(), STATE_COLLAPSED);//保存状态
          } else {
            holder.expandOrFold.setVisibility(View.GONE);
            mTextStateList.put(mList.get(position).getId(), STATE_NOT_OVERFLOW);
          }
          return true;
        }
      });

      holder.content.setMaxLines(Integer.MAX_VALUE);//设置文本的最大行数,为整数的最大数值
      holder.content.setText(mList.get(position).getContent());
    } else {
      //如果之前已经初始化过了,则使用保存的状态。
      switch (state) {
        case STATE_NOT_OVERFLOW:
          holder.expandOrFold.setVisibility(View.GONE);
          break;
        case STATE_COLLAPSED:
          holder.content.setMaxLines(MAX_LINE_COUNT);
          holder.expandOrFold.setVisibility(View.VISIBLE);
          holder.expandOrFold.setText("全文");
          break;
        case STATE_EXPANDED:
          holder.content.setMaxLines(Integer.MAX_VALUE);
          holder.expandOrFold.setVisibility(View.VISIBLE);
          holder.expandOrFold.setText("收起");
          break;
      }
      holder.content.setText(mList.get(position).getContent());
    }

    //全文和收起的点击事件
    holder.expandOrFold.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        int state = mTextStateList.get(mList.get(position).getId(), STATE_UNKNOW);
        if (state == STATE_COLLAPSED) {
          holder.content.setMaxLines(Integer.MAX_VALUE);
          holder.expandOrFold.setText("收起");
          mTextStateList.put(mList.get(position).getId(), STATE_EXPANDED);
        } else if (state == STATE_EXPANDED) {
          holder.content.setMaxLines(MAX_LINE_COUNT);
          holder.expandOrFold.setText("全文");
          mTextStateList.put(mList.get(position).getId(), STATE_COLLAPSED);
        }
      }
    });

    //删除点击事件
    holder.delete.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View view) {
        mList.remove(position);
        notifyDataSetChanged();
      }
    });
  }

  @Override
  public int getItemCount() {
    return mList.size();
  }

  public class MyViewHolder extends RecyclerView.ViewHolder {
    public TextView nickname;
    public TextView content;
    public TextView delete;
    public TextView expandOrFold;

    public MyViewHolder(View itemView) {
      super(itemView);
      nickname = (TextView) itemView.findViewById(R.id.tv_nickname);
      content = (TextView) itemView.findViewById(R.id.tv_content);
      delete = (TextView) itemView.findViewById(R.id.tv_delete);
      expandOrFold = (TextView) itemView.findViewById(R.id.tv_expand_or_fold);
    }
  }
}

ExpandFoldTextBean.java

package com.wildma.wildmaexpandfoldtext;

/**
 * Author   wildma
 * DATE    2017/8/3
 * Des    ${TODO}
 */
public class ExpandFoldTextBean {

  private String content;//内容

  private int id;//该条数据的id

  public String getContent() {
    return content;
  }

  public void setContent(String content) {
    this.content = content;
  }

  public int getId() {
    return id;
  }

  public void setId(int id) {
    this.id = id;
  }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
  android:id="@+id/activity_main"
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:paddingBottom="@dimen/activity_vertical_margin"
  android:paddingLeft="@dimen/activity_horizontal_margin"
  android:paddingRight="@dimen/activity_horizontal_margin"
  android:paddingTop="@dimen/activity_vertical_margin">

  <android.support.v7.widget.RecyclerView
    android:id="@+id/recyclerview"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
  </android.support.v7.widget.RecyclerView>

</RelativeLayout>

item_expand_fold_text.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:orientation="vertical"
       android:paddingBottom="@dimen/activity_vertical_margin"
       android:paddingLeft="@dimen/activity_horizontal_margin"
       android:paddingRight="@dimen/activity_horizontal_margin"
       android:paddingTop="@dimen/activity_vertical_margin">

  <LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="center_vertical"
    android:orientation="horizontal">

    <ImageView
      android:layout_width="40dp"
      android:layout_height="40dp"
      android:layout_marginRight="16dp"
      android:gravity="center"
      android:scaleType="centerCrop"
      android:src="@mipmap/ic_launcher"/>

    <RelativeLayout
      android:layout_width="match_parent"
      android:layout_height="wrap_content">

      <TextView
        android:id="@+id/tv_nickname"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="wildma"
        android:textColor="@android:color/black"
        android:textSize="14sp"/>

      <TextView
        android:id="@+id/tv_delete"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_marginLeft="12dp"
        android:paddingLeft="5dp"
        android:paddingRight="5dp"
        android:text="删除"
        android:textColor="@android:color/holo_red_dark"
        android:textSize="14sp"/>
    </RelativeLayout>

  </LinearLayout>

  <LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginLeft="56dp"
    android:orientation="vertical"
    android:paddingBottom="8dp">

    <TextView
      android:id="@+id/tv_content"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_marginBottom="8dp"
      android:alpha="0.85"
      android:ellipsize="end"
      android:text="内容"
      android:textColor="@android:color/black"
      android:textSize="14sp"/>

    <TextView
      android:id="@+id/tv_expand_or_fold"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="全文"
      android:textColor="@color/colorPrimaryDark"
      android:textSize="14sp"/>
  </LinearLayout>

  <View
    android:layout_width="match_parent"
    android:layout_height="0.5dp"
    android:background="@android:color/black"/>
</LinearLayout>

源码地址:https://github.com/wildma/WildmaExpandFoldText

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

时间: 2017-08-01

Android仿微信朋友圈全文收起功能示例(附源码)

在众多的社交类软件中,朋友圈是必不可少的,可以与好友.同学等分享自己的日常和有意思的事情,在开发社交类App时,朋友圈发表的内容你不可能让他全部显示,全部显示的话用户体验度会非常不好,这时就要用到全文.收缩的功能,朋友如果想要看你发的动态,只要点一下全文就可以查看所有的全部的内容了,如果不想看,也没有必要把这一篇文章全部都滑到底部,才能看下一条内容. 下边将源码贴出来供大家参考:(代码不是最简便的,但是功能是可以的) 首先写一个布局,这个布局是每个子项的布局 item_text_list.xml

android实现微信朋友圈发布动态功能

本文实例为大家分享了android仿微信朋友圈发布动态功能的具体代码,供大家参考,具体内容如下 效果图: 本文概述 用到的开源库:仿照微信的图片选择器,Luban压缩图片,glide 上面红圈部分,当用户选中图片时,当=9张时,那个加号图片就会消失! 本文主要仿照微信的发布动态功能,主要时针对微信发布动态时,选中图片后的变化状态! 整体布局 这可以看到,控制图片状态的地方就是一个recyclerview 思路 利用recyclerview的多行视图来实现! 微信上的效果是,先选中图片后才会进入这

Android 仿微信朋友圈点赞和评论弹出框功能

贡献/下载源码:https://github.com/mmlovesyy/PopupWindowDemo 本文简单模仿微信朋友圈的点赞和评论弹出框,布局等细节请忽略,着重实现弹出框.发评论,及弹出位置的控制. 1. 微信弹出框 微信朋友圈的点赞和评论功能,有2个组成部分: 点击左下角的"更多"按钮,弹出对话框: 点击评论,弹出输入框,添加评论并在页面中实时显示: 微信朋友圈点赞和评论功能 2. 实际效果 本文将建一个 ListView,在其 Item 中简单模仿微信的布局,然后着重实现

Android仿微信朋友圈实现滚动条下拉反弹效果

微信朋友圈上面的图片封面,QQ空间说说上面的图片封面都有下拉反弹的效果,这些都是使用滚动条实现的.下拉,当松开时候,反弹至原来的位置.下拉时候能看到背景图片.那么这里简单介绍一下这种效果的实现. 1.效果图 这部手机显示的分辨率有限,很老的手机调试. 2.具有反弹效果BounceScrollView package com.org.scroll; import android.content.Context; import android.graphics.Rect; import androi

Android仿微信朋友圈点赞和评论功能

最近在做朋友圈的项目,所以写一个Android仿朋友圈点赞和评论功能Demo,代码就是简单实现了一下功能,没有做优化,凑合看 图文排列是用的RecyclerView实现的,弹窗效果是用的自定义的PopupWindow,点赞应该是在本地请求数据库,设置一个flag,获取当前用户的id后,带着id向服务器post一个flag,评论就比较简单了,也是获取当前朋友id(或者昵称),带着内容,向服务器post 贴代码: package com.example.lenovo.dianzandemo; imp

微信小程序显示下拉列表功能【附源码下载】

本文实例讲述了微信小程序显示下拉列表功能.分享给大家供大家参考,具体如下: 1.效果展示 2.关键代码 app.json文件: { "pages":[ "views/views", "views/navigators/navigator1/navigator1", "views/navigators/navigator2/navigator2", "views/navigators/navigator3/naviga

vue项目实现记住密码到cookie功能示例(附源码)

本文介绍了vue项目实现记住密码到cookie功能示例,分享给大家,具体如下: 登陆页面 实现功能: 1.记住密码勾选,点登陆时,将账号和密码保存到cookie,下次登陆自动显示到表单内 2.不勾选,点登陆时候则清空之前保存到cookie的值,下次登陆需要手动输入 大体思路就是通过存/取/删cookie实现的:每次进入登录页,先去读取cookie,如果浏览器的cookie中有账号信息,就自动填充到登录框中,存cookie是在登录成功之后,判断当前用户是否勾选了记住密码,如果勾选了,则把账号信息存

Android仿微信朋友圈添加图片的实例代码

老习惯,先上图,着急用的朋友,直接带走Demo,先拿来用吧,毕竟老板催的紧,先把工作完成了,再看也来得及,是吧! 在项目中这种添加图片上传的效果应该是非常常见的,后面有个添加的按钮应该让有些童鞋不知道咋办了吧,其实没那么复杂,通过GridView就可以实现了 先说明一下,这里主要是讲添加图片的效果,至于图片选择器用的是第三方库photopicker,6.0权限用的是第三方库EasyPermission 1.首先这是用GridView实现的 <?xml version="1.0"

PHP发表心情投票功能示例(附源码)

当浏览新闻页面或者其它页面的时候会有阅读后的感受,比如给力.淡定.打酱油.加油.坑爹等等的表情.让读者打分,看看自己的感受是否与其他读者一样.很不错的交互! 立即下载:mood_jb51.rar 本文需要熟悉jquery,mysql,ajax相关的知识,不过用的不多.本文有三个文件:index.html,mood.php,sql.php index.html,页面展示和请求ajax数据 mood.php,后台文件 处理get请求来的数据,并返回数据 sql.php,数据库文件,存数据库信息 直接