首页 > 系统 > Android > 正文

Android仿QQ空间动态界面分享功能

2019-12-12 03:00:02
字体:
来源:转载
供稿:网友

先看看效果:

用极少的代码实现了 动态详情 及 二级评论 的 数据获取与处理 和 UI显示与交互,并且高解耦、高复用、高灵活。

动态列表界面MomentListFragment支持 下拉刷新与上拉加载 和 模糊搜索,反复快速滑动仍然非常流畅。

缓存机制使得数据可在启动界面后瞬间加载完成。

动态详情界面MomentActivity支持 (取消)点赞、(删除)评论、点击姓名跳到个人详情 等。

只有1张图片时图片放大显示,超过1张则按九宫格显示。

用到的CommentContainerView和MomentView都是独立的组件,既可单独使用,也可用于ListView或添加至其它ViewGroup等。

CommentContainerView复用

CommentContainerView.java

setOnCommentClickListener    : 设置点击评论监听createView           : 创建ViewbindView            : 绑定数据并显示ViewsetMaxShowCount         : 设置最多显示数量,超过则折叠setComment           : 设置评论addCommentView         : 添加评论View

 package apijson.demo.client.view;

import android.annotation.SuppressLint;import android.app.Activity;import android.content.res.Resources;import android.view.LayoutInflater;import android.view.View;import android.view.View.OnClickListener;import android.view.View.OnLongClickListener;import android.view.ViewGroup;import java.util.ArrayList;import java.util.List;import apijson.demo.client.R;import apijson.demo.client.model.CommentItem;import apijson.demo.client.view.CommentView.OnCommentClickListener;import zuo.biao.library.base.BaseView;import zuo.biao.library.util.Log;import zuo.biao.library.util.StringUtil;/**评论容器 * @author Lemon * @useCommentContainerView commentContainerView = new CommentContainerView(context, inflater);adapter中使用convertView = commentContainerView.getView();//[具体见.DemoAdapter] 或 其它类中使用containerView.addView(commentContainerView.getConvertView());commentContainerView.bindView(data);commentContainerView.setOnClickPictureListener(onClickPictureListener);//非必需commentContainerView.setOnDataChangedListener(onDataChangedListener);data = commentContainerView.getData();//非必需commentContainerView.setOnClickListener(onClickListener);//非必需... */public class CommentContainerView extends BaseView<List<CommentItem>> {  private static final String TAG = "CommentContainerView";  private OnCommentClickListener onCommentClickListener;  /**设置点击评论监听   * @param onCommentClickListener   */  public void setOnCommentClickListener(OnCommentClickListener onCommentClickListener) {    this.onCommentClickListener = onCommentClickListener;  }  public CommentContainerView(Activity context, Resources resources) {    super(context, resources);  }  private LayoutInflater inflater;  public ViewGroup llCommentContainerViewContainer;  public View tvCommentContainerViewMore;  @SuppressLint("InflateParams")  @Override  public View createView(LayoutInflater inflater) {    this.inflater = inflater;    convertView = inflater.inflate(R.layout.comment_container_view, null);    llCommentContainerViewContainer = findViewById(R.id.llCommentContainerViewContainer);    tvCommentContainerViewMore = findViewById(R.id.tvCommentContainerViewMore);    return convertView;  }  @Override  public void bindView(List<CommentItem> list){    llCommentContainerViewContainer.setVisibility(list == null || list.isEmpty() ? View.GONE : View.VISIBLE);    if (list == null) {      Log.w(TAG, "bindView data_ == null >> data_ = new List<CommentItem>();");      list = new ArrayList<CommentItem>();    }    this.data = list;    // 评论    setComment(list);  }  private int maxShowCount = 3;  /**设置最多显示数量,超过则折叠   * @param maxShowCount <= 0 ? 显示全部 : 超过则折叠   */  public void setMaxShowCount(int maxShowCount) {    this.maxShowCount = maxShowCount;  }  /**设置评论   * @param list   */  public void setComment(List<CommentItem> list) {    int count = list == null ? 0 : list.size();    boolean showMore = maxShowCount > 0 && count > maxShowCount;    tvCommentContainerViewMore.setVisibility(showMore ? View.VISIBLE : View.GONE);    llCommentContainerViewContainer.removeAllViews();    llCommentContainerViewContainer.setVisibility(count <= 0 ? View.GONE : View.VISIBLE);    if (count > 0) {      if (showMore) {        list = list.subList(0, maxShowCount);      }      for (int i = 0; i < list.size(); i++) {        addCommentView(i, list.get(i));      }    }  }  /**添加评论   * @param index   * @param comment   */  @SuppressLint("InflateParams")  private void addCommentView(final int index, final CommentItem comment) {    if (comment == null) {      Log.e(TAG, "addCommentView comment == null >> return; ");      return;    }    String content = StringUtil.getTrimedString(comment.getComment().getContent());    if (StringUtil.isNotEmpty(content, true) == false) {      Log.e(TAG, "addCommentView StringUtil.isNotEmpty(content, true) == false >> return; ");      return;    }    CommentTextView commentView = (CommentTextView) inflater.inflate(R.layout.comment_item, null);    commentView.setView(comment);    if (onCommentClickListener != null) {      commentView.setOnClickListener(new OnClickListener() {        @Override        public void onClick(View v) {          onCommentClickListener.onCommentClick(comment, position, index, false);        }      });      commentView.setOnLongClickListener(new OnLongClickListener() {        @Override        public boolean onLongClick(View v) {          onCommentClickListener.onCommentClick(comment, position, index, true);          return true;        }      });    }    llCommentContainerViewContainer.addView(commentView);  }}

comment_container_view.xml

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  style="@style/ll_vertical_match_wrap" >  <LinearLayout    android:id="@+id/llCommentContainerViewContainer"    style="@style/ll_vertical_match_wrap" >  </LinearLayout>  <TextView    android:id="@+id/tvCommentContainerViewMore"    style="@style/text_small_blue"    android:layout_width="match_parent"    android:background="@drawable/bg_item_to_alpha"    android:gravity="left|center_vertical"    android:paddingBottom="4dp"    android:paddingTop="4dp"    android:text="查看全部" /></LinearLayout>

MomentView复用

MomentView.java

setOnPictureClickListener    : 设置点击图片监听createView           : 创建ViewbindView            : 绑定数据并显示ViewsetPraise            : 设置点赞setShowComment         : 设置是否显示评论getShowComment         : 获取是否显示评论的设置setComment           : 设置评论setPicture           : 设置九宫格图片toComment            : 跳转到所有评论界面getData             : 获取动态绑定的数据isLoggedIn           : 判断是否已登录,未登录则跳到登录界面praise             : (取消)点赞onDialogButtonClick       : 处理对话框返回结果,比如删除动态onHttpResponse         : 处理Http请求的返回结果,比如点赞onClick             : 处理点击事件,比如点击内容跳到动态详情界面onItemClick           : 处理点击图片的事件,默认是查看大图,可setOnPictureClickListener接管处理

package apijson.demo.client.view;

import android.annotation.SuppressLint;import android.app.Activity;import android.content.res.Resources;import android.view.LayoutInflater;import android.view.View;import android.view.View.OnClickListener;import android.view.ViewGroup;import android.widget.AdapterView;import android.widget.AdapterView.OnItemClickListener;import android.widget.GridView;import android.widget.ImageView;import android.widget.LinearLayout.LayoutParams;import android.widget.TextView;import java.util.ArrayList;import java.util.List;import apijson.demo.client.R;import apijson.demo.client.activity_fragment.LoginActivity;import apijson.demo.client.activity_fragment.MomentActivity;import apijson.demo.client.activity_fragment.UserActivity;import apijson.demo.client.activity_fragment.UserListActivity;import apijson.demo.client.application.APIJSONApplication;import apijson.demo.client.model.CommentItem;import apijson.demo.client.model.Moment;import apijson.demo.client.model.MomentItem;import apijson.demo.client.model.User;import apijson.demo.client.util.HttpRequest;import apijson.demo.client.view.CommentView.OnCommentClickListener;import zuo.biao.apijson.JSONResponse;import zuo.biao.library.base.BaseView;import zuo.biao.library.manager.CacheManager;import zuo.biao.library.manager.HttpManager.OnHttpResponseListener;import zuo.biao.library.model.Entry;import zuo.biao.library.ui.AlertDialog;import zuo.biao.library.ui.AlertDialog.OnDialogButtonClickListener;import zuo.biao.library.ui.GridAdapter;import zuo.biao.library.ui.WebViewActivity;import zuo.biao.library.util.ImageLoaderUtil;import zuo.biao.library.util.Log;import zuo.biao.library.util.ScreenUtil;import zuo.biao.library.util.StringUtil;import zuo.biao.library.util.TimeUtil;/**动态 * @author Lemon * @useMomentView momentView = new MomentView(context, inflater);adapter中使用convertView = momentView.getView();//[具体见.DemoAdapter] 或 其它类中使用containerView.addView(momentView.getConvertView());momentView.bindView(data);momentView.setOnPictureClickListener(onPictureClickListener);//非必需momentView.setOnDataChangedListener(onDataChangedListener);data = momentView.getData();//非必需momentView.setOnClickListener(onClickListener);//非必需... */public class MomentView extends BaseView<MomentItem> implements OnClickListener, OnHttpResponseListener, OnDialogButtonClickListener, OnItemClickListener {  private static final String TAG = "MomentView";  public interface OnPictureClickListener {    void onClickPicture(int momentPosition, MomentView momentView, int pictureIndex);  }  private OnPictureClickListener onPictureClickListener;  /**设置点击图片监听   * @param onPictureClickListener   */  public void setOnPictureClickListener(OnPictureClickListener onPictureClickListener) {    this.onPictureClickListener = onPictureClickListener;  }  public MomentView(Activity context, Resources resources) {    super(context, resources);  }  //UI显示区(操作UI,但不存在数据获取或处理代码,也不存在事件监听代码)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<  private LayoutInflater inflater;  public View llMomentViewContainer;  public ImageView ivMomentViewHead;  public TextView tvMomentViewName;  public TextView tvMomentViewStatus;  public TextView tvMomentViewContent;  public GridView gvMomentView;  public TextView tvMomentViewDate;  public ImageView ivMomentViewPraise;  public ImageView ivMomentViewComment;  public ViewGroup llMomentViewPraise;  public PraiseTextView tvMomentViewPraise;  public View vMomentViewDivider;  public ViewGroup llMomentViewCommentContainer;  @SuppressLint("InflateParams")  @Override  public View createView(LayoutInflater inflater) {    this.inflater = inflater;    convertView = inflater.inflate(R.layout.moment_view, null);    llMomentViewContainer = findViewById(R.id.llMomentViewContainer);    ivMomentViewHead = findViewById(R.id.ivMomentViewHead, this);    tvMomentViewName = findViewById(R.id.tvMomentViewName, this);    tvMomentViewStatus = findViewById(R.id.tvMomentViewStatus, this);    tvMomentViewContent = findViewById(R.id.tvMomentViewContent, this);    gvMomentView = findViewById(R.id.gvMomentView);    tvMomentViewDate = findViewById(R.id.tvMomentViewDate);    ivMomentViewPraise = findViewById(R.id.ivMomentViewPraise, this);    ivMomentViewComment = findViewById(R.id.ivMomentViewComment, this);    llMomentViewPraise = findViewById(R.id.llMomentViewPraise, this);    tvMomentViewPraise = findViewById(R.id.tvMomentViewPraise, this);    vMomentViewDivider = findViewById(R.id.vMomentViewDivider);    llMomentViewCommentContainer = findViewById(R.id.llMomentViewCommentContainer);    return convertView;  }  private User user;  private Moment moment;  private long momentId;  private long userId;  private boolean isCurrentUser;  private int status;  public int getStatus() {    return status;  }  @Override  public void bindView(MomentItem data_){    this.data = data_;    llMomentViewContainer.setVisibility(data == null ? View.GONE : View.VISIBLE);    if (data == null) {      Log.w(TAG, "bindView data == null >> return;");      return;    }    this.user = data.getUser();    this.moment = data.getMoment();    this.momentId = moment.getId();    this.userId = moment.getUserId();    this.isCurrentUser = APIJSONApplication.getInstance().isCurrentUser(moment.getUserId());    this.status = data.getMyStatus();    ImageLoaderUtil.loadImage(ivMomentViewHead, user.getHead());    tvMomentViewName.setText(StringUtil.getTrimedString(user.getName()));    tvMomentViewStatus.setText(StringUtil.getTrimedString(data.getStatusString()));    tvMomentViewStatus.setVisibility(isCurrentUser ? View.VISIBLE : View.GONE);    tvMomentViewContent.setVisibility(StringUtil.isNotEmpty(moment.getContent(), true) ? View.VISIBLE : View.GONE);    tvMomentViewContent.setText(StringUtil.getTrimedString(moment.getContent()));    tvMomentViewDate.setText(TimeUtil.getSmartDate(moment.getDate()));    // 图片    setPicture(moment.getPictureList());    // 点赞    setPraise(data.getIsPraised(), data.getUserList());    // 评论    setComment(data.getCommentItemList());    vMomentViewDivider.setVisibility(llMomentViewPraise.getVisibility() == View.VISIBLE        && llMomentViewCommentContainer.getVisibility() == View.VISIBLE ? View.VISIBLE : View.GONE);  }  /**设置点赞   * @param joined   * @param list   */  private void setPraise(boolean joined, List<User> list) {    ivMomentViewPraise.setImageResource(joined ? R.drawable.praised : R.drawable.praise);    llMomentViewPraise.setVisibility(list == null || list.isEmpty() ? View.GONE : View.VISIBLE);    if (llMomentViewPraise.getVisibility() == View.VISIBLE) {      tvMomentViewPraise.setView(list);    }  }  private boolean showComment = true;  public void setShowComment(boolean showComment) {    this.showComment = showComment;  }  public boolean getShowComment() {    return showComment;  }  public CommentContainerView commentContainerView;  /**设置评论   * @param list   */  public void setComment(List<CommentItem> list) {    llMomentViewCommentContainer.setVisibility(showComment == false || list == null || list.isEmpty()        ? View.GONE : View.VISIBLE);    if (llMomentViewCommentContainer.getVisibility() != View.VISIBLE) {      Log.i(TAG, "setComment llMomentViewCommentContainer.getVisibility() != View.VISIBLE >> return;");      return;    }    if (commentContainerView == null) {      commentContainerView = new CommentContainerView(context, resources);      llMomentViewCommentContainer.removeAllViews();      llMomentViewCommentContainer.addView(commentContainerView.createView(inflater));      commentContainerView.setOnCommentClickListener(new OnCommentClickListener() {        @Override        public void onCommentClick(CommentItem item, int position, int index, boolean isLong) {          toComment(item, true);        }      });      commentContainerView.tvCommentContainerViewMore.setOnClickListener(this);      commentContainerView.setMaxShowCount(5);    }    commentContainerView.bindView(list);  }  private GridAdapter adapter;  /**设置图片   * @param pictureList   */  private void setPicture(List<String> pictureList) {    List<Entry<String, String>> keyValueList = new ArrayList<Entry<String, String>>();    if (pictureList != null) {      for (String picture : pictureList) {        keyValueList.add(new Entry<String, String>(picture, null));      }    }    int pictureNum = keyValueList.size();    gvMomentView.setVisibility(pictureNum <= 0 ? View.GONE : View.VISIBLE);    if (pictureNum <= 0) {      Log.i(TAG, "setList pictureNum <= 0 >> lvModel.setAdapter(null); return;");      adapter = null;      gvMomentView.setAdapter(null);      return;    }    gvMomentView.setNumColumns(pictureNum <= 1 ? 1 : 3);    if (adapter == null) {      adapter = new GridAdapter(context).setHasName(false);      gvMomentView.setAdapter(adapter);    }    adapter.refresh(keyValueList);    gvMomentView.setOnItemClickListener(this);    final int gridViewHeight = (int) (ScreenUtil.getScreenSize(context)[0]        - convertView.getPaddingLeft() - convertView.getPaddingRight()        - getDimension(R.dimen.moment_view_head_width));    try {      if (pictureNum >= 7) {        gvMomentView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, gridViewHeight));      } else if (pictureNum >= 4) {        gvMomentView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, (gridViewHeight*2)/3));      } else if (pictureNum >= 2) {        gvMomentView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, gridViewHeight / 3));      } else {        gvMomentView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));      }    } catch (Exception e) {      Log.e(TAG, " setPictureGrid try int gridViewHeight;...>> catch" + e.getMessage());    }  }  /**跳转到所有评论界面   * @param isToComment   */  private void toComment(boolean isToComment) {    toComment(null, isToComment);  }  /**跳转到所有评论界面   * @param commentItem   * @param isToComment comment有效时为true   */  private void toComment(CommentItem commentItem, boolean isToComment) {    if (commentItem == null) {      commentItem = new CommentItem();    }    toActivity(MomentActivity.createIntent(context, momentId, isToComment        , commentItem.getId(), commentItem.getUser().getId(), commentItem.getUser().getName()));  }  //UI显示区(操作UI,但不存在数据获取或处理代码,也不存在事件监听代码)>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

  //Data数据区(存在数据获取或处理代码,但不存在事件监听代码)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<  @Override  public MomentItem getData() {//bindView(null)不会使data == null    return llMomentViewContainer.getVisibility() == View.VISIBLE ? data : null;  }  /**判断是否已登录,如果未登录则弹出登录界面   * @return   */  private boolean isLoggedIn() {    boolean isLoggedIn = APIJSONApplication.getInstance().isLoggedIn();    if (isLoggedIn == false) {      context.startActivity(LoginActivity.createIntent(context));      context.overridePendingTransition(R.anim.bottom_push_in, R.anim.hold);    }    return isLoggedIn;  }  /**点赞   * @param toPraise   */  public void praise(boolean toPraise) {    if (data == null || toPraise == data.getIsPraised()) {      Log.e(TAG, "praiseWork toPraise == moment.getIsPraise() >> return;");      return;    }    //    setPraise(toPraise, data.getPraiseCount() + (toPraise ? 1 : -1));    HttpRequest.praiseMoment(momentId, toPraise, toPraise ? HTTP_PRAISE : HTTP_CANCEL_PRAISE, this);  }  //Data数据区(存在数据获取或处理代码,但不存在事件监听代码)>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

  //Event事件监听区(只要存在事件监听代码就是)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<  @Override  public void onDialogButtonClick(int requestCode, boolean isPositive) {    if (isPositive && data != null) {      data.setMyStatus(MomentItem.STATUS_DELETING);      bindView(data);      HttpRequest.deleteMoment(moment.getId(), HTTP_DELETE, this);    }  }  public static final int HTTP_PRAISE = 1;  public static final int HTTP_CANCEL_PRAISE = 2;  public static final int HTTP_DELETE = 3;  @Override  public void onHttpResponse(int requestCode, String result, Exception e) {    if (data == null) {      Log.e(TAG, "onHttpResponse data == null >> return;");      return;    }    JSONResponse response = new JSONResponse(result);    JSONResponse response2 = response.getJSONResponse(Moment.class.getSimpleName());    boolean isSucceed = JSONResponse.isSucceed(response2);    switch (requestCode) {    case HTTP_PRAISE:    case HTTP_CANCEL_PRAISE:      if (isSucceed) {        data.setIsPraised(requestCode == HTTP_PRAISE);        bindView(data);      } else {        showShortToast((requestCode == HTTP_PRAISE ? "点赞" : "取消点赞") + "失败,请检查网络后重试");      }      break;    case HTTP_DELETE:      showShortToast(isSucceed ? R.string.delete_succeed : R.string.delete_failed);      //只对adapter.getCount()有影响。目前是隐藏的,不需要通知,也不需要刷新adapter,用户手动刷新后自然就更新了。      if (isSucceed) {        bindView(null);        status = MomentItem.STATUS_DELETED;        if (onDataChangedListener != null) {          onDataChangedListener.onDataChanged();        }        CacheManager.getInstance().remove(MomentItem.class, "" + momentId);      } else {        data.setMyStatus(MomentItem.STATUS_NORMAL);        bindView(data);      }      break;    }  }  @Override  public void onClick(View v) {    if (data == null) {      return;    }    if (status == MomentItem.STATUS_PUBLISHING) {      showShortToast(R.string.publishing);      return;    }    switch (v.getId()) {    case R.id.ivMomentViewHead:    case R.id.tvMomentViewName:      toActivity(UserActivity.createIntent(context, userId));      break;    case R.id.tvMomentViewStatus:      if (status == MomentItem.STATUS_NORMAL) {        new AlertDialog(context, "", "删除动态", true, 0, this).show();      }      break;    case R.id.tvMomentViewContent:    case R.id.tvCommentContainerViewMore:      toComment(false);      break;    case R.id.tvMomentViewPraise:    case R.id.llMomentViewPraise:      toActivity(UserListActivity.createIntent(context, data.getPraiseUserIdList())          .putExtra(UserListActivity.INTENT_TITLE, "点赞的人"));      break;    default:      if (isLoggedIn() == false) {        return;      }      switch (v.getId()) {      case R.id.ivMomentViewPraise:        praise(! data.getIsPraised());        break;      case R.id.ivMomentViewComment:        toComment(true);        break;      default:        break;      }      break;    }  }  @Override  public void onItemClick(AdapterView<?> parent, View view, int position, long id) {    if (status == MomentItem.STATUS_PUBLISHING) {      showShortToast(R.string.publishing);      return;    }    if (onPictureClickListener != null) {      onPictureClickListener.onClickPicture(this.position, this, position);    } else {      toActivity(WebViewActivity.createIntent(context, null          , adapter == null ? null : adapter.getItem(position).getKey()));    }  }  //Event事件监听区(只要存在事件监听代码就是)>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>}

moment_view.xml

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  style="@style/match_wrap"  android:descendantFocusability="blocksDescendants" >  <LinearLayout    android:id="@+id/llMomentViewContainer"    style="@style/ll_horizontal_match_wrap"    android:background="@color/white"    android:gravity="top"    android:padding="10dp" >    <RelativeLayout      android:id="@+id/rlMomentViewItemHead"      android:layout_width="@dimen/moment_view_head_width"      android:layout_height="@dimen/moment_view_head_height"      android:paddingRight="@dimen/moment_view_head_padding_right" >      <ImageView        android:background="@color/alpha_3"        android:id="@+id/ivMomentViewHead"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:scaleType="centerCrop" />    </RelativeLayout>    <LinearLayout      style="@style/ll_vertical_match_wrap"      android:layout_below="@+id/rlMomentViewItemHead"      android:layout_toRightOf="@+id/rlMomentViewItemHead"      android:gravity="left" >      <LinearLayout        style="@style/ll_horizontal_match_wrap"        android:layout_height="match_parent" >        <TextView          android:id="@+id/tvMomentViewName"          style="@style/text_small_blue"          android:layout_width="match_parent"          android:layout_weight="1"          android:background="@drawable/bg_item_to_alpha"          android:gravity="left"          android:text="Name" />        <TextView          android:id="@+id/tvMomentViewStatus"          style="@style/text_small_blue"          android:background="@drawable/bg_item_to_alpha"          android:text="发布中" />      </LinearLayout>      <TextView        android:id="@+id/tvMomentViewContent"        style="@style/text_small_black"        android:layout_width="match_parent"        android:layout_marginTop="5dp"        android:background="@drawable/bg_item_to_alpha"        android:gravity="left|top"        android:maxLines="8"        android:paddingBottom="5dp"        android:text="This is a content..." />      <apijson.demo.client.view.EmptyEventGridView        android:id="@+id/gvMomentView"        style="@style/wrap_wrap"        android:focusable="false"        android:horizontalSpacing="4dp"        android:listSelector="@drawable/bg_item_to_alpha"        android:numColumns="3"        android:paddingTop="4dp"        android:scrollbars="none"        android:stretchMode="columnWidth"        android:verticalSpacing="4dp" />      <LinearLayout        style="@style/ll_horizontal_match_wrap"        android:layout_height="wrap_content"        android:layout_marginTop="5dp" >        <TextView          android:id="@+id/tvMomentViewDate"          style="@style/text_small_black"          android:layout_width="match_parent"          android:layout_weight="1"          android:gravity="left"          android:text="2015年12月" />        <ImageView          android:id="@+id/ivMomentViewPraise"          style="@style/img_btn"          android:layout_marginRight="18dp"          android:background="@drawable/bg_item_to_alpha"          android:src="@drawable/praise" />        <ImageView          android:id="@+id/ivMomentViewComment"          style="@style/img_btn"          android:background="@drawable/bg_item_to_alpha"          android:src="@drawable/comment" />      </LinearLayout>      <LinearLayout        style="@style/ll_vertical_match_wrap"        android:layout_marginTop="5dp"        android:background="@color/alpha_1"        android:paddingLeft="8dp"        android:paddingRight="8dp" >        <LinearLayout          android:id="@+id/llMomentViewPraise"          style="@style/ll_horizontal_match_wrap"          android:layout_height="wrap_content"          android:layout_marginBottom="4dp"          android:layout_marginTop="4dp"          android:background="@drawable/bg_item_to_alpha"          android:gravity="top" >          <ImageView            android:layout_width="20dp"            android:layout_height="20dp"            android:scaleType="fitXY"            android:src="@drawable/praise" />          <apijson.demo.client.view.PraiseTextView            android:id="@+id/tvMomentViewPraise"            style="@style/text_small_blue"            android:background="@drawable/bg_item_to_alpha"            android:gravity="left|top"            android:lineSpacingExtra="4dp"            android:text="等觉得很赞" />        </LinearLayout>        <View          android:id="@+id/vMomentViewDivider"          style="@style/divider_horizontal_1px" />        <LinearLayout          android:id="@+id/llMomentViewCommentContainer"          style="@style/ll_vertical_match_wrap"          android:paddingBottom="4dp"          android:paddingTop="4dp" >        </LinearLayout>      </LinearLayout>    </LinearLayout>  </LinearLayout></RelativeLayout>

由于这个项目使用了ZBLibrary快速开发框架,所以实现仿QQ空间和微信朋友圈的这种复杂界面只用了极少的代码,并且高解耦、高复用、高灵活。

服务端是用APIJSON(Server)工程快速搭建的,客户端App和服务端通过APIJSON-JSON传输结构协议通信,非常方便灵活,省去了大量的接口和文档!

今年RxJava特别火,在北京市场几乎是必备技能,所以我还把这个项目做了个RxJava版本,欢迎交流和指教。

实现UI的Java类:

MomentListFragment       395行       动态列表的获取和显示MomentActivity         616行       动态和评论列表的获取、显示和交互(评论和删除评论等)MomentAdapter          67行        动态列表的显示CommentAdapter         82行        评论列表的显示MomentView           495行       动态的显示和交互(各种跳转、点赞、删除等)EmptyEventGridView       56行        动态里图片的显示和交互(触摸空白处传递触摸事件到内层View)PraiseTextView         129行       动态里点赞用户的显示和交互(点击姓名跳到个人详情,点击整体跳到点赞的用户列表界面)CommentView           153行       一级评论(头像、姓名、内容)的显示和交互(回复、删除等),添加二级评论列表CommentContainerView      172行       二级评论列表的显示和交互(查看全部等)CommentTextView         122行       二级评论(姓名、内容)的显示和交互(回复、删除等)

实现UI的XML布局:

moment_activity         47行        动态和评论列表的显示moment_view           148行       动态的显示comment_view          87行        一级评论(头像、姓名、内容)的显示comment_container_view     20行        二级评论列表的显示comment_item          10行        二级评论(姓名、内容)的显示

为什么没有实现MomentListFragment对应的XML布局?

因为MomentListFragment继承BaseHttpListFragment,内部用XListView作为缺省列表View,所以可以不用自己实现了。

实现数据获取、提交和处理的Java类:

HttpRequest           +175行       数据的获取和提交(getMoment,...,deleteComment)CommentUtil           140行       单层评论和和二级评论的处理Comment             56行        评论数据CommentItem           99行        评论的显示和交互数据Moment             43行        动态数据MomentItem           272行       动态的显示和交互数据User              103行       用户数据

(注:未列出的代码文件要么和动态无关,要么APIJSON或ZBLibrary已提供。server.model里的类由服务端提供)

 仿QQ空间和微信朋友圈,高解耦高复用高灵活

下载试用(测试服务器地址:139.196.140.118:8080)

APIJSONClientApp.apk

源码及文档(记得给个Star哦)

https://github.com/TommyLemon/APIJSON

以上所述是小编给大家介绍的Android仿QQ空间动态界面分享功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对武林网网站的支持!

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表