登录 立即注册
安币:

安卓巴士 - 安卓开发 - Android开发 - 安卓 - 移动互联网门户

仿微信朋友圈

[复制链接]
来自: MrlLee 分类: Android精品源码 上传时间: 2016-4-18 20:57:17
Tag:一起来 撸个 朋友圈吧

项目介绍:

按照惯例,首先上图(图片大小:7M,为了大小问题,色彩调的比较低,所以看起来略渣):






本篇实现的原理跟上篇是一致的,不过也许上一篇写的有点乱,比较难理解,所以本篇将会一边概括上篇的内容一边讲述如何实现本篇的内容。

Step 1:概括
在上一篇中,写了那么多东东,其实核心思想只有一个:计算偏移量。
listview.smoothscrolltopositionfromtop这个方法执行起来其实是分两部的:

  • 到达指定item,使item的顶部对齐listview的顶部
  • 到达后,smoothScroll一定距离,也就是第二个参数

而我们的目标是为了让item的底部对齐输入框的顶部,而smoothscrolltopositionfromtop第一步已经帮我们定位好,使item的顶部对齐listview的顶部,所以我们着手的问题只是如何计算出偏移量。

又因为输入法弹出后,实际上我们看见的内容区域是变小的,所以我们需要计算的是item的底部与输入框顶部的差值,而这个差值就是偏移量了。
同时因为getBottom得到的是相对于父类而言的参数,所以我们只好通过item的height来动态计算(因为smoothscrolltopositionfromtop第一步会使item顶部对齐listview顶部,所以item的底部就相当于它的高度)
以上就是上一篇的概括。

总结起来就是:

  • listview定位到指定的item
  • 得到listview的height,此时的height相当于bottom
  • 得到height与可见部分的差值,这个差值就是偏移量
  • listview偏移上述步骤得到的偏移量

Step 2:评论控件对齐输入框顶部的实现原理
通过上面的概括,其实不难得出,我们只要得到当前点击的评论的底部再计算与可见区域底部的差值就可以了。
实际上也正是如此,但是在实现的时候我们则需要稍微处理一下。
首先看看我们的动态的底部布局:


底部布局


可以看到,我们的底部布局是RelativeLayout嵌套着LinearLayout,这第一个LinearLayout是存放点赞和评论的。然后这个LinearLayout里面又嵌套着一个LinearLayout,这个LinearLayout则是村发那个评论的。
看起来层次嵌套挺多,过度绘制妥妥的了。
不过打开微信看了看,咱就安心了。



左:微信朋友圈;右:本项目

毕竟那啥,看起来过度绘制都差不多哈哈。
上面说过,我们最终目的都是得到当前点击的评论的底部距离可视区域的底部,同时由于我们当初的设计是将commentWidget抛了出来,所以理论上来说,我们拿到commentWidget.getBottom()就行了。
但其实不然,getTop/Bottom/Left/Right这几个方法得到的是相对于其父布局的参数,而非在屏幕上的,所以我们需要处理一下:





比如上图,我们需要拿到四楼相对于整个item的位置,普通的getBottom是不可行的,所以我们需要计算一下。
在布局分析那里,我们可以看到我们嵌套了好几层,在图中我也用不同的颜色标出来了范围。
回到问题,我们要拿到该评论控件相对于item的位置,则需要通过其父布局的top,而父布局又因为嵌套在其他父布局里面,所以我们需要得到最外层的布局的top。在图中表现为蓝色框框的顶部。
所以我们取得当前点击评论控件相对于item的位置方法如下:
  • 取得评论控件父布局(记为parent1)的top(图中绿色布局),记为top1
  • 取得包含着点赞和评论布局(记为parent2)的top(即parent1.getParent(),图中红色布局),记为top2
  • 取得整个bottom相对于item的top,即(parent2.getParent()),记为top3
  • 取得被点击的commentWidget的bottom(该bottom是相对于parent1的bottom)
  • 最后commentWidget的bottom相对于item来说,其y方向的值等于top1+top2+top3+bottom.

然后通过这个值减去可见区域的底部就得到了偏移值了


Step 3:代码实现
代码上十分简单,本次改动仅仅只有计算偏移值的地方:
首先补充上一篇的calculateListViewOffset方法

[Java] 查看源文件 复制代码
private int calculateListViewOffset(int currentDynamicPos, CommentWidget commentWidget, int keyBoardHeight) {
        int result;
        if (screenHeight == 0) screenHeight = UIHelper.getScreenPixHeight(this);
        if (statusBarHeight == 0) statusBarHeight = UIHelper.getStatusHeight(this);

        if (commentWidget == null) {
            // 评论控件为空,证明回复的是整个动态
            result = getOffsetOfDynamic(currentDynamicPos, keyBoardHeight);
        }
        else {
            // 评论控件不空,证明回复的是评论
            result = getOffsetOfComment(currentDynamicPos, commentWidget, keyBoardHeight);
        }
        return result;
    }

然后完善我们的getOffsetOfComment方法:
[Java] 查看源文件 复制代码
 // 得到评论的偏移量
    private int getOffsetOfComment(int currentDynamicPos, CommentWidget commentWidget, int keyBoardHeight) {
        int result=0;
        int contentHeight;
        contentHeight = screenHeight - keyBoardHeight - mInputLayout.getHeight();
        try {
            //得到评论控件所在父控件(即评论的父控件)
            final LinearLayout parent = (LinearLayout) commentWidget.getParent();
            //得到评论和点赞的父控件
            final LinearLayout praiseAndCommentParent = (LinearLayout) parent.getParent();
            //得到评论和点赞的父控件的父控件
            final RelativeLayout originParent = (RelativeLayout) praiseAndCommentParent.getParent();
            //得到评论和点赞的父控件的父控件的top
            final int originParentTop = originParent.getTop();
            //得到评论和点赞的父控件的top
            final int praiseAndCommentParentTop = praiseAndCommentParent.getTop();
            //得到评论所在父控件的top
            final int parentTop = parent.getTop();
            //得到当前评论控件的底部(相对于LinearLayout)
            final int currentCommentBottom = commentWidget.getBottom();
            //则当前评论控件相对于item来说,其底部=父类LinearLayout.top+当前控件的底部
            final int currentCommentOffset = originParentTop + praiseAndCommentParentTop + parentTop + currentCommentBottom;

            //则偏移量等于offset-contentheight
            result = currentCommentOffset - contentHeight;
        } catch (Exception e) {
            e.printStackTrace();
            Log.e("FriendCircleDemoAct","也许是空指针也许是cast错误哦");
        }
        return -result;
    }

相关代码都写了注释了,因为忽然发现,本项目的注释稍微少了点。







相关源码推荐:

我来说两句
所有评论(554)
安卓新手上路 2016-4-18 22:15:13
虽不明,但觉厉!
回复
liuguang 2016-4-18 22:45:36
不错哟
回复
liuguang 2016-4-18 22:49:20
楼主用心了,内容非常精彩。
回复
嘟嘟小马2014 2016-4-19 09:10:47
楼主威武啊,安卓巴士有你更给力!
回复
善良的老农 2016-4-19 09:32:18
123
回复
权爸爸啊! 2016-4-19 09:53:05
感谢分享,安卓巴士有你更精彩:)
回复
niebiao 2016-4-19 10:07:20
感谢分享,安卓巴士有你更精彩:)
回复
提取码:  下载次数:192 状态:已购或VIP 售价:10(原价:10)金钱 下载权限:限制会员 
7620 3 192
代码贡献英雄榜
用户名 下载数
联系我们
首页/微信公众账号投稿

帖子代码编辑/版权问题

QQ:435399051,769657487

如何获得代码达人称号

如何成为签约作者

联系我们
关闭
合作电话:
13802416937
Email:
435399051@qq.com
商务市场合作/投稿
问题反馈及帮助
联系我们

广告投放| 申请友链|手机版|站点统计|安卓巴士 ( 粤ICP备15117877号 )

快速回复 返回顶部 返回列表