前言

这个月,说实话,有忙有闲,经历了一次病痛的洗礼,才认识到了只有好好的生活,认真的对待自己的身体,才能更好的去工作,没有了身体的支撑,什么工作都只能是纸老虎,不攻自破。在这里也祝愿大家,在生活中好好对待自己,身体第一,工作第二。

为什么要写这个app

群里的一个哥们前几天晚上给我看了一下一个app,我粗略看了下界面(还没运行下载,他给我发的),我看了一下,感觉挺不错的,当时心里一热,哈哈,这不是挺简单的么,几天就搞完了,但是当我去下载的时候,看到了30-40MB的大小,我惊呆了,要知道一个淘宝才那么大。哈哈,不过还是被这个界面吸引了,而且里面的内容也挺不错的,大多关于心理方面的。那就自己模仿一下吧,顺带的自己去学习一下,因为这个app涉及到的知识点挺多(即时通讯、直播、视屏播放、第三方登录),想着自己就慢慢的写,然后去学习一下会用到的知识,伴随着这样的想法,就有了这个MyHearts项目。

几个小知识点

一、进入到主界面,可以看到下方的几个Tab键,原本想着是用FragmentTabhost实现,但是看到中间的那个Tab键和其他的按键是不同等高度的,而且这个还是有动画效果的,后面想着,如果用framelayout覆盖在上面应该是可以实现的,但是动画呢,这个时候想到之前用到的帧动画,想必这个帧动画也是可以实现的,然后自己就去试了试,结果还真给实现了,对于程序这东西来说,当别人问这个能不能实现,我在这个地方加一个字段、加个方法,可以实现么,我想说的就是,既然已经想到了,那就试一下呗,行了就证明方法可以,不行证明需要找其他的方法,最重要的是动手写程序,程序不是问出来的,而是一句一句代码积累出来的。

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<item
android:drawable="@mipmap/main_layout_center_image_1"
android:duration="100"/>
<item
android:drawable="@mipmap/main_layout_center_image_2"
android:duration="100"/>
<item
android:drawable="@mipmap/main_layout_center_image_3"
android:duration="100"/>
<item
android:drawable="@mipmap/main_layout_center_image_4"
android:duration="100"/>
<item
android:drawable="@mipmap/main_layout_center_image_5"
android:duration="100"/>
<item
android:drawable="@mipmap/main_layout_center_image_6"
android:duration="100"/>
<item
android:drawable="@mipmap/main_layout_center_image_7"
android:duration="100"/>
<item
android:drawable="@mipmap/main_layout_center_image_8"
android:duration="100"/>
<item
android:drawable="@mipmap/main_layout_center_image_9"
android:duration="100"/>
//这里并没有写完,可以直接去代码里面查看,最后会附上git地址 </animation-list>

在代码中这样就可以执行动画了


// 获取ImageView上的动画背景
AnimationDrawable spinnerImg = (AnimationDrawable) mIvImg.getBackground();
// 开始动画
spinnerImg.start();

这样就可以实现直播和life动画的切换了。

二、心事界面的图片展示,之前在用postman(用于接口调试的,值得推荐)请求数据接口的时候,看到里面有个photos字段,并不是所有的item都有这个字段,而且里面个数不一,但都是一个图片地址,想着应该是类似于qq空间发表说说的附带的图片。自己想着用RecyclerView实现,因为这个是很好实现的,但是我在看到okgo(本项目的网络请求框架,支持Rx,挺不错的)项目中,他的项目也有这个类似的功能,用到的就是NineGridView(https://github.com/jeasonlzy/NineGridView),okgo这个项目也是这位大神写的。这个也是很简单使用的,他是在ViewGroup的基础上自定义的。用法也是很简单,如下

 //也就是用户发朋友圈的那种,添加图片
List<String> images = bean.getPhotos();
if (images != null) {
for (String image : images) {
//ImageInfo 是他的实体类,用于image的地址
ImageInfo info = new ImageInfo();
info.setThumbnailUrl(image);
info.setBigImageUrl(image);
imageInfo.add(info);
}
}
holder.mPhotoRecycler.setAdapter(new NineGridViewClickAdapter(mContext, imageInfo)); if (images != null && images.size() == 1) {
//如果用户只发了一张图片的话,就设置图片的宽和高
holder.mPhotoRecycler.setSingleImageSize(300);
holder.mPhotoRecycler.setSingleImageRatio(1);
//holder.mPhotoRecycler.setSingleImageRatio(images.get(0).width * 1.0f / images.get(0).height);
}

实现的结果如下:

三、二级评论列表,这个我一直想不到好的解决办法(在我脑海里一直以为有更好的方法),这里我就是用的item里面嵌套一个RecyclerView,得到的comment list,然后在进行item分配。如果有好的,请告知。谢谢啦。
这里就看下代码,也没什么可写的,无非就是RecyclerView嵌套RecyclerView

  List<CommentsBean> comments = bean.getComments();
if (comments != null && comments.size() > 0) {
CommentAdapter adapter = new CommentAdapter(comments);
holder.mCommentRe.setVisibility(View.VISIBLE);
holder.mCommentRecycler.setLayoutManager(new LinearLayoutManager(mContext));
// holder.mCommentRecycler.addItemDecoration(new DividerItemDecoration(mContext
//,DividerItemDecoration.VERTICAL_LIST));
holder.mCommentRecycler.setItemAnimator(new DefaultItemAnimator());
holder.mCommentRecycler.setAdapter(adapter);
}

对于评论里面的回复和被回复者,为了便于区分,我这里使用到了SpanableString。类似于下面:

CommentsBean bean = mCommentsBeen.get(position);
//评论用户
String profileName = bean.getName();
//被回复者 如果为空 默认回复发帖者
String replayName = bean.getReplyToUserName(); StringBuffer sb = new StringBuffer(); sb.append(profileName);
sb.append(" ");
String replay = mContext.getResources().getString(R.string.replay_comment);
if (!replayName.equals("")) { //判断是否有被回复的,没有就是默认发帖者
sb.append(replay);
sb.append(replayName);
} String commentContent = bean.getContent();
sb.append(commentContent); // String result = ; SpannableString msp = new SpannableString(sb.toString()); //对评论者进行颜色配置
msp.setSpan(new ForegroundColorSpan(Color.BLUE), 0,
profileName.length(),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //如果有被回复的对象,那么被回复的对象也要进行颜色配置
if (!replayName.equals("")) {
int start = profileName.length() + 3;
int end = start + replayName.length();
msp.setSpan(new ForegroundColorSpan(Color.BLUE), start, end,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
} //这个地方要直接设置成msp 不能用msp.toString() 要不然没有样式
holder.mTvCommentContent.setText(msp);

效果图,大家可以git代码去运行一下。
四、之前用到左滑出菜单栏,第一个是Draglayout,但是这个存在冲突,滑动不是很流畅,自己后面换到了git上的一个仿QQ5.2的,但是和自己app里面的轮播(从左向右滑动的时候,会带出左侧边栏,还有就是心事界面的Tablayout也是存在同样的方式,后面自己想到了应该是用到的ViewPager滑动事件的问题,就想着之前用到的,就重写了ViewPager,然后处理了一些逻辑,基本解决了冲突),代码如下:

/**
* 事件分发,请求父控件是否拦截
* <p/>
* 1、右滑,而且是第一个页面,需要父控件拦截
* <p/>
* 2、左滑,而且当前的页面是最后一个页面,需要父控件拦截
* <p/>
* 3、上下滑动,需要父控件拦截
*
* @param ev
* @return
*/ @Override
public boolean dispatchTouchEvent(MotionEvent ev) {
/**
* 用getParent()去请求,请求父控件是否不要拦截滑动事件
*/ switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
//先去让父控件不要拦截,这样才可能走到ACTION_MOVE方法调用
getParent().requestDisallowInterceptTouchEvent(true);
/**
* 拿到刚开始按下的时候的坐标
*/
startX = (int) ev.getRawX();
startY = (int) ev.getRawY();
break;
case MotionEvent.ACTION_MOVE: /**
* 获取到移动之后的坐标
*/
int endX = (int) ev.getRawX();
int endY = (int) ev.getRawY(); //左右滑动
if (Math.abs(endX - startX) > Math.abs(endY - startY)) {
if (endX > startX) {
//右滑
//获取到第一个 需要父控件拦截
if (getCurrentItem() == 0) {
getParent().requestDisallowInterceptTouchEvent(false);
}
} else if (endX <= startX) {
//左滑
//获取到最后一个
// 需要父控件拦截
if (getCurrentItem() == getAdapter().getCount() - 1) {
getParent().requestDisallowInterceptTouchEvent(false);
}
}
} else {
//上下滑动
getParent().requestDisallowInterceptTouchEvent(false);
} break;
default:
break;
} return super.dispatchTouchEvent(ev);
}

哈哈,最后还是换成了DrawerLayout,不存在了滑动的冲突BUG了,Drawerlayout默认划出是覆盖在主界面上的,这里为了模仿的比较像,就重写了一些逻辑(hongyang大神的博客中有介绍)

 mDrawerLayout.setDrawerListener(new DrawerLayout.DrawerListener() {
@Override
public void onDrawerSlide(View drawerView, float slideOffset) {
View mContent = mDrawerLayout.getChildAt(0);
View mMenu = drawerView;
float scale = 1 - slideOffset;
float rightScale = 0.8f + scale * 0.2f; if (drawerView.getTag().equals("LEFT"))
{ float leftScale = 1 - 0.3f * scale; ViewHelper.setScaleX(mMenu, leftScale);
ViewHelper.setScaleY(mMenu, leftScale);
ViewHelper.setAlpha(mMenu, 0.6f + 0.4f * (1 - scale));
ViewHelper.setTranslationX(mContent,
mMenu.getMeasuredWidth() * (1 - scale));
ViewHelper.setPivotX(mContent, 0);
ViewHelper.setPivotY(mContent,
mContent.getMeasuredHeight() / 2);
mContent.invalidate();
ViewHelper.setScaleX(mContent, rightScale);
ViewHelper.setScaleY(mContent, rightScale);
} else
{
ViewHelper.setTranslationX(mContent,
-mMenu.getMeasuredWidth() * slideOffset);
ViewHelper.setPivotX(mContent, mContent.getMeasuredWidth());
ViewHelper.setPivotY(mContent,
mContent.getMeasuredHeight() / 2);
mContent.invalidate();
ViewHelper.setScaleX(mContent, rightScale);
ViewHelper.setScaleY(mContent, rightScale);
}
} @Override
public void onDrawerOpened(View drawerView) { } @Override
public void onDrawerClosed(View drawerView) {
mDrawerLayout.setDrawerLockMode(
DrawerLayout.LOCK_MODE_LOCKED_CLOSED, Gravity.RIGHT);
} @Override
public void onDrawerStateChanged(int newState) { }
});

到这里,基本上就没什么知识点了(因为自己也写的不是很好,加上自己的水平有限),后面增加新功能了在做补充。
最后上传几张效果图:



代码传送门(如果感觉还不错,欢迎star下)

开源app之MyHearts的更多相关文章

  1. 开源App之MyHearts(二)

    前言 小弟技术有限,有的地方也是自己摸索出来的,可能和大神们写的好的代码没法比,但是我会努力的.要对自己说下,加油!! 此次更新 1.集成QQ登录完成 集成QQ登录网上写的介绍已经很多了,这里就不详细 ...

  2. React Native指南汇集了各类react-native学习资源、开源App和组件

    来自:https://github.com/ele828/react-native-guide React Native指南汇集了各类react-native学习资源.开源App和组件 React-N ...

  3. 开源APP 源码

    作者:wjh2005链接:http://www.zhihu.com/question/28518265/answer/88750562来源:知乎著作权归作者所有,转载请联系作者获得授权. 1. Cod ...

  4. 开源APP

    仿微信 https://github.com/zhengwenming/WeChat 电台韵律 https://github.com/DaMingShen 运动App https://github.c ...

  5. 越折腾越好用的 3 款开源 APP

    高中的时候我特别喜欢捣鼓手机,然后我一个哥们儿在我的强烈推荐下买了个 HTC Dream(G1) 手机. G1 作为谷歌的第一个亲儿子,它出厂搭载的是 Android 1.5 系统,但当时已经出到了 ...

  6. [译]百里挑一:21个优质Swift开源App

    Mybridge AI根据代码质量和start排名从900多个开源项目中选出21个开源项目. 1:Firefox iOS [Official] Firefox iOS app built in Swi ...

  7. 9个完整android开源app项目

    一.photoup 介绍: photoup 是一款开源的相册类app,主要功能是将本地图片提交到facebook上去,虽然他的功能和facebook的远程服务相关,但是本身是可以被当作一款 相册应用的 ...

  8. 关于"干货集中营"的一个开源App

    中秋佳节,玩了一天,撸了两天代码,搞出这么个东东,共享出来,小伙伴们如果有兴趣,欢迎添砖加瓦. 数据接口为干货集中营的数据,接口地址:http://gank.io/api 使用到的技术清单如下: 1. ...

  9. 四个很好的开源app项目

    Open Source and the iOS App Store Today, we are open-sourcing 4 iOS apps: ThatInbox, an email client ...

随机推荐

  1. Mainstoryboard

    页面间进行跳转 [self performSegueWithIdentifier:@"signInSuccess" sender:self] signSuccess是miansto ...

  2. Chapter 4: Tomcat Default Connector

    一.概述 第三章介绍的connector是一个很好的学习工具,但是我们还可以做的更多.这一章介绍的是Tomcat4默认的connector. 一个Tomcat的connector是一个独立的模块,能够 ...

  3. 解决:Ubuntu12.04下使用ping命令返回ping:icmp open socket: Operation not permitted的解决

    ping命令在运行中采用了ICMP协议,需要发送ICMP报文.但是只有root用户才能建立ICMP报文.而正常情况下,ping命令的权限应为-rwsr-xr-x,即带有suid的文件,一旦该权限被修改 ...

  4. C++读入二进制数并转换为十进制输出

    题目描述 已知一个只包含0和1的二进制数,长度不大于10,将其转换为十进制并输出. 输入描述 输入一个二进制整数n,其长度不大于10 输出描述 输出转换后的十进制数,占一行 样例输入 样例输出 sol ...

  5. 【转】为什么我要用 Node.js? 案例逐一介绍

    原文转自:http://blog.jobbole.com/53736/ 介绍 JavaScript 高涨的人气带来了很多变化,以至于如今使用其进行网络开发的形式也变得截然不同了.就如同在浏览器中一样, ...

  6. Welcome to MacJournal!

    Welcome to MacJournal 6 To get started, create a new entry by clicking on "New Entry" in t ...

  7. Js的引用赋值与传值赋值

    要说js的赋值方式时首先要说明js的数值类型:基本类型和引用类型. 1.基本类型 基本的数据类型有:undefined,boolean,number,string,null. 基本类型存放在栈区,访问 ...

  8. cnblogs.com的用户体验

    用户体验: 作为博客园的用户,我们觉得博客园的用户体验还是很不错的.但是我们觉得主界面有些混乱,一登录进去太多东西,完全不明白怎么分的类. 评价cnblogs.com的用户体验 1.你是什么样的用户, ...

  9. Spring MVC+Maven+Freemarker+Mybatis开发环境搭建

    版权声明:本文为博主原创文章,未经博主允许不得转载.   目录(?)[-] 创建一个Spring MVC项目 集成Freemarker 集成Mybatis Mybatis自动生成工具   利用STS( ...

  10. JavaWeb学习记录(十九)——开发JSTL自定义标签

    一.防盗链标签 import javax.servlet.http.HttpServletResponse;import javax.servlet.jsp.JspException;import j ...