開源app之MyHearts
###前言 這個月,說實話,有忙有閒,經歷了一次病痛的洗禮,才認識到了只有好好的生活,認真的對待自己的身體,才能更好的去工作,沒有了身體的支撐,什麼工作都只能是紙老虎,不攻自破。在這裡也祝願大家,在生活中好好對待自己,身體第一,工作第二。 ###為什麼要寫這個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下) https://github.com/wuyinlei/MyHearts