浏览代码

1.add newsfeed module
2.main page update

liukai 2 年之前
父节点
当前提交
94378939a2
共有 100 个文件被更改,包括 4154 次插入179 次删除
  1. 1 0
      app/build.gradle
  2. 1 0
      cpt_ewallet/src/main/java/com/hongyegroup/cpt_ewallet/bean/EWalletHistoryBean.java
  3. 24 64
      cpt_main/src/main/java/com/hongyegroup/cpt_main/ui/MainActivity.kt
  4. 二进制
      cpt_main/src/main/res/drawable-xxhdpi/main_active_blue.webp
  5. 二进制
      cpt_main/src/main/res/drawable-xxhdpi/main_active_gray.webp
  6. 二进制
      cpt_main/src/main/res/drawable-xxhdpi/main_newsfeed_blue.webp
  7. 二进制
      cpt_main/src/main/res/drawable-xxhdpi/main_newsfeed_gray.webp
  8. 二进制
      cpt_main/src/main/res/drawable-xxhdpi/main_part_jobs_blue.webp
  9. 二进制
      cpt_main/src/main/res/drawable-xxhdpi/main_part_jobs_gray.webp
  10. 0 11
      cpt_main/src/main/res/drawable/selector_main_tab_active.xml
  11. 11 0
      cpt_main/src/main/res/drawable/selector_main_tab_newsfeed.xml
  12. 0 11
      cpt_main/src/main/res/drawable/selector_main_tab_partjob.xml
  13. 20 69
      cpt_main/src/main/res/layout/activity_main.xml
  14. 2 3
      cpt_main/src/main/res/layout/fragment_home.xml
  15. 1 0
      cpt_newsfeed/.gitignore
  16. 6 0
      cpt_newsfeed/build.gradle
  17. 21 0
      cpt_newsfeed/proguard-rules.pro
  18. 26 0
      cpt_newsfeed/src/androidTest/java/com/hongyegroup/cpt_main/ExampleInstrumentedTest.java
  19. 17 0
      cpt_newsfeed/src/main/AndroidManifest.xml
  20. 30 0
      cpt_newsfeed/src/main/java/com/hongyegroup/cpt_newsfeed/adapter/NewsFeedListAdapter.kt
  21. 132 0
      cpt_newsfeed/src/main/java/com/hongyegroup/cpt_newsfeed/bean/NewsFeedAdatperBean.java
  22. 13 0
      cpt_newsfeed/src/main/java/com/hongyegroup/cpt_newsfeed/mvvm/NewsFeedDetailViewModel.kt
  23. 13 0
      cpt_newsfeed/src/main/java/com/hongyegroup/cpt_newsfeed/mvvm/NewsFeedFansViewModel.kt
  24. 13 0
      cpt_newsfeed/src/main/java/com/hongyegroup/cpt_newsfeed/mvvm/NewsFeedFollowViewModel.kt
  25. 98 0
      cpt_newsfeed/src/main/java/com/hongyegroup/cpt_newsfeed/mvvm/NewsFeedFollowingViewModel.kt
  26. 13 0
      cpt_newsfeed/src/main/java/com/hongyegroup/cpt_newsfeed/mvvm/NewsFeedFollowsViewModel.kt
  27. 16 0
      cpt_newsfeed/src/main/java/com/hongyegroup/cpt_newsfeed/mvvm/NewsFeedMainViewModel.kt
  28. 13 0
      cpt_newsfeed/src/main/java/com/hongyegroup/cpt_newsfeed/mvvm/NewsFeedMomentViewModel.kt
  29. 13 0
      cpt_newsfeed/src/main/java/com/hongyegroup/cpt_newsfeed/mvvm/NewsFeedPostViewModel.kt
  30. 13 0
      cpt_newsfeed/src/main/java/com/hongyegroup/cpt_newsfeed/mvvm/NewsFeedProfileViewModel.kt
  31. 24 0
      cpt_newsfeed/src/main/java/com/hongyegroup/cpt_newsfeed/router/NewsFeedComponentServiceImpl.kt
  32. 53 0
      cpt_newsfeed/src/main/java/com/hongyegroup/cpt_newsfeed/ui/NewsFeedDetailActivity.kt
  33. 44 0
      cpt_newsfeed/src/main/java/com/hongyegroup/cpt_newsfeed/ui/NewsFeedFansFragment.kt
  34. 42 0
      cpt_newsfeed/src/main/java/com/hongyegroup/cpt_newsfeed/ui/NewsFeedFollowFragment.kt
  35. 53 0
      cpt_newsfeed/src/main/java/com/hongyegroup/cpt_newsfeed/ui/NewsFeedFollowsActivity.kt
  36. 106 0
      cpt_newsfeed/src/main/java/com/hongyegroup/cpt_newsfeed/ui/NewsFeedListFragment.kt
  37. 154 0
      cpt_newsfeed/src/main/java/com/hongyegroup/cpt_newsfeed/ui/NewsFeedMainFragment.kt
  38. 59 0
      cpt_newsfeed/src/main/java/com/hongyegroup/cpt_newsfeed/ui/NewsFeedPostActivity.kt
  39. 50 0
      cpt_newsfeed/src/main/java/com/hongyegroup/cpt_newsfeed/ui/NewsFeedProfileActivity.kt
  40. 50 0
      cpt_newsfeed/src/main/java/com/hongyegroup/cpt_newsfeed/ui/NewsFeedProfileFragment.kt
  41. 39 0
      cpt_newsfeed/src/main/java/com/hongyegroup/cpt_newsfeed/widget/expand/ButtonSpan.java
  42. 279 0
      cpt_newsfeed/src/main/java/com/hongyegroup/cpt_newsfeed/widget/expand/ExpandTextView.java
  43. 25 0
      cpt_newsfeed/src/main/java/com/hongyegroup/cpt_newsfeed/widget/expand/InterceptUrlSpan.kt
  44. 43 0
      cpt_newsfeed/src/main/java/com/hongyegroup/cpt_newsfeed/widget/expand/MyTypefaceSpan.java
  45. 二进制
      cpt_newsfeed/src/main/res/drawable-xxhdpi/news_feed_camera.webp
  46. 二进制
      cpt_newsfeed/src/main/res/drawable-xxhdpi/news_feed_comments_un.webp
  47. 二进制
      cpt_newsfeed/src/main/res/drawable-xxhdpi/news_feed_likes_un.webp
  48. 二进制
      cpt_newsfeed/src/main/res/drawable-xxhdpi/news_feed_share_un.webp
  49. 二进制
      cpt_newsfeed/src/main/res/drawable-xxhdpi/newsfeed_profile_news_addfollow_red.webp
  50. 二进制
      cpt_newsfeed/src/main/res/drawable-xxhdpi/newsfeed_profile_news_followed.webp
  51. 5 0
      cpt_newsfeed/src/main/res/drawable/shape_news_feed_follow_red_round_18.xml
  52. 36 0
      cpt_newsfeed/src/main/res/layout/activity_newsfeed_detail.xml
  53. 36 0
      cpt_newsfeed/src/main/res/layout/activity_newsfeed_follows.xml
  54. 37 0
      cpt_newsfeed/src/main/res/layout/activity_newsfeed_post.xml
  55. 9 0
      cpt_newsfeed/src/main/res/layout/activity_newsfeed_profile.xml
  56. 34 0
      cpt_newsfeed/src/main/res/layout/fragment_newsfeed_fans.xml
  57. 34 0
      cpt_newsfeed/src/main/res/layout/fragment_newsfeed_follow.xml
  58. 37 0
      cpt_newsfeed/src/main/res/layout/fragment_newsfeed_following.xml
  59. 185 0
      cpt_newsfeed/src/main/res/layout/fragment_newsfeed_main.xml
  60. 34 0
      cpt_newsfeed/src/main/res/layout/fragment_newsfeed_profile.xml
  61. 239 0
      cpt_newsfeed/src/main/res/layout/item_news_feed_news.xml
  62. 347 0
      cpt_newsfeed/src/main/res/layout/layout_placeholder_newsfeed_hot.xml
  63. 17 0
      cpt_newsfeed/src/test/java/com/hongyegroup/cpt_main/ExampleUnitTest.java
  64. 2 2
      cpt_parttime/src/main/AndroidManifest.xml
  65. 2 2
      cpt_parttime/src/main/java/com/hongyegroup/cpt_parttime/router/PartTimeComponentServiceImpl.kt
  66. 1 1
      cpt_parttime/src/main/java/com/hongyegroup/cpt_parttime/ui/PartJobAlbumActivity.kt
  67. 2 1
      cpt_parttime/src/main/java/com/hongyegroup/cpt_parttime/ui/PartTimeJobDetailActivity.kt
  68. 1 1
      cpt_parttime/src/main/java/com/hongyegroup/cpt_parttime/ui/PartJobDetailFaqFragment.kt
  69. 2 1
      cpt_parttime/src/main/java/com/hongyegroup/cpt_parttime/ui/PartJobDetailFragment.kt
  70. 1 1
      cpt_parttime/src/main/java/com/hongyegroup/cpt_parttime/ui/PartJobDetailGroomingFragment.kt
  71. 1 1
      cpt_parttime/src/main/java/com/hongyegroup/cpt_parttime/ui/PartJobDetailPaymentFragment.kt
  72. 1 1
      cpt_parttime/src/main/java/com/hongyegroup/cpt_parttime/ui/PartJobDetailProcessFragment.kt
  73. 1 1
      cpt_parttime/src/main/java/com/hongyegroup/cpt_parttime/ui/PartJobDetailSlotsFragment.kt
  74. 1 1
      cpt_parttime/src/main/java/com/hongyegroup/cpt_parttime/ui/JobActivesFragment.kt
  75. 2 1
      cpt_parttime/src/main/java/com/hongyegroup/cpt_parttime/ui/PartTimeMainFragment.kt
  76. 1 1
      cpt_parttime/src/main/res/layout/activity_parttime_job_detail.xml
  77. 1 1
      cpt_parttime/src/main/res/layout/fragment_job_actives.xml
  78. 1 1
      cpt_parttime/src/main/res/layout/fragment_parttime_job_detail.xml
  79. 1 1
      cpt_parttime/src/main/res/layout/fragment_parttime_main.xml
  80. 1 1
      cpt_parttime/src/main/res/layout/include_parttime_job_detail_header_date_address.xml
  81. 24 2
      cs_baselib/src/main/java/com/guadou/lib_baselib/ext/ViewPagerExt.kt
  82. 二进制
      cs_cptServices/src/main/res/drawable-xxhdpi/im_default_head.webp
  83. 1 0
      cs_ninegrid/.gitignore
  84. 7 0
      cs_ninegrid/build.gradle
  85. 17 0
      cs_ninegrid/proguard-rules.pro
  86. 9 0
      cs_ninegrid/src/main/AndroidManifest.xml
  87. 76 0
      cs_ninegrid/src/main/java/com/guadou/ninegrid/ImageInfo.java
  88. 17 0
      cs_ninegrid/src/main/java/com/guadou/ninegrid/ImageLoader.java
  89. 34 0
      cs_ninegrid/src/main/java/com/guadou/ninegrid/NineGlideLoader.kt
  90. 687 0
      cs_ninegrid/src/main/java/com/guadou/ninegrid/flownine/FlowLayout.java
  91. 77 0
      cs_ninegrid/src/main/java/com/guadou/ninegrid/flownine/LayoutConfiguration.java
  92. 76 0
      cs_ninegrid/src/main/java/com/guadou/ninegrid/flownine/LineDefinition.java
  93. 240 0
      cs_ninegrid/src/main/java/com/guadou/ninegrid/nine_grid_layout/AbstractNineGridLayout.java
  94. 28 0
      cs_ninegrid/src/main/java/com/guadou/ninegrid/nine_grid_layout/NineGridLayout.java
  95. 77 0
      cs_ninegrid/src/main/java/com/guadou/ninegrid/nine_grid_layout/SimpleImageViewNineGrid.kt
  96. 10 0
      cs_ninegrid/src/main/java/com/guadou/ninegrid/nine_grid_layout/ViewGetter.java
  97. 82 0
      cs_ninegrid/src/main/java/com/guadou/ninegrid/roundimg/CustomRoundImageView.java
  98. 92 0
      cs_ninegrid/src/main/java/com/guadou/ninegrid/roundimg/ForceClickImageView.java
  99. 10 0
      cs_ninegrid/src/main/java/com/guadou/ninegrid/roundimg/NiceUtils.java
  100. 0 0
      cs_ninegrid/src/main/java/com/guadou/ninegrid/roundimg/NineGridViewWrapper.java

+ 1 - 0
app/build.gradle

@@ -18,4 +18,5 @@ dependencies {
     implementation project(':cpt_parttime')
     implementation project(':cpt_ewallet')
     implementation project(':cpt_rewards')
+    implementation project(':cpt_newsfeed')
 }

+ 1 - 0
cpt_ewallet/src/main/java/com/hongyegroup/cpt_ewallet/bean/EWalletHistoryBean.java

@@ -10,4 +10,5 @@ public class EWalletHistoryBean {
 
     public String groupDate;
     public boolean isShowDivider;
+
 }

+ 24 - 64
cpt_main/src/main/java/com/hongyegroup/cpt_main/ui/MainActivity.kt

@@ -21,7 +21,7 @@ import com.hongyegroup.cpt_main.mvvm.MainViewModel
 import dagger.hilt.android.AndroidEntryPoint
 
 /**
- * 首页Tab+Fragment
+ * 首页Tab + Fragment
  */
 @Route(path = ARouterPath.PATH_MAIN_PAGE_MAIN)
 @AndroidEntryPoint
@@ -29,9 +29,8 @@ class MainActivity : YYBaseVDBActivity<MainViewModel, ActivityMainBinding>() {
 
     //首页的5个TabFragment
     private var mHomeFragment: Fragment? = null
-    private var mPartTimeFragment: Fragment? = null
-    private var mActivesFragment: Fragment? = null
     private var mEWalletFragment: Fragment? = null
+    private var mNewsFeedFragment: Fragment? = null
     private var mProfileFragment: Fragment? = null
     private var mCurPosition = 0  //当前Fragment选中的索引
     private var mClickPage = 0  //当前Fragment选中的索引
@@ -80,21 +79,16 @@ class MainActivity : YYBaseVDBActivity<MainViewModel, ActivityMainBinding>() {
                     }
                 }
                 1 -> {
-                    mPartTimeFragment?.let {
+                    mEWalletFragment?.let {
                         if (it is IFragmentRefresh) (it as IFragmentRefresh).scrollTopRefresh()
                     }
                 }
                 2 -> {
-                    mActivesFragment?.let {
+                    mNewsFeedFragment?.let {
                         if (it is IFragmentRefresh) (it as IFragmentRefresh).scrollTopRefresh()
                     }
                 }
                 3 -> {
-                    mEWalletFragment?.let {
-                        if (it is IFragmentRefresh) (it as IFragmentRefresh).scrollTopRefresh()
-                    }
-                }
-                4 -> {
                     mProfileFragment?.let {
                         if (it is IFragmentRefresh) (it as IFragmentRefresh).scrollTopRefresh()
                     }
@@ -115,15 +109,12 @@ class MainActivity : YYBaseVDBActivity<MainViewModel, ActivityMainBinding>() {
                 targetFragment = mHomeFragment
             }
             1 -> {
-                targetFragment = mPartTimeFragment
+                targetFragment = mEWalletFragment
             }
             2 -> {
-                targetFragment = mActivesFragment
+                targetFragment = mNewsFeedFragment
             }
             3 -> {
-                targetFragment = mEWalletFragment
-            }
-            4 -> {
                 targetFragment = mProfileFragment
             }
             else -> {
@@ -158,7 +149,7 @@ class MainActivity : YYBaseVDBActivity<MainViewModel, ActivityMainBinding>() {
     private fun setupStatusBarColor() {
         //只有Profile页面变白色
         when (mCurPosition) {
-            2, 3, 4 -> setStatusBarWhiteText()
+            1, 3 -> setStatusBarWhiteText()
             else -> setStatusBarBlackText()
         }
     }
@@ -168,13 +159,10 @@ class MainActivity : YYBaseVDBActivity<MainViewModel, ActivityMainBinding>() {
         mHomeFragment?.let {
             transaction.hide(it)
         }
-        mPartTimeFragment?.let {
-            transaction.hide(it)
-        }
-        mActivesFragment?.let {
+        mEWalletFragment?.let {
             transaction.hide(it)
         }
-        mEWalletFragment?.let {
+        mNewsFeedFragment?.let {
             transaction.hide(it)
         }
         mProfileFragment?.let {
@@ -184,43 +172,31 @@ class MainActivity : YYBaseVDBActivity<MainViewModel, ActivityMainBinding>() {
 
     //底部Tab的选中效果
     private fun setBottomSelected(position: Int) {
-        mBinding.groupTabParttime.isSelected = false
 
         //传递进来的Position设置为选中:
         when (position) {
             0 -> {
                 mBinding.groupTabHome.isSelected = true
-                mBinding.groupTabParttime.isSelected = false
-                mBinding.groupTabActives.isSelected = false
                 mBinding.groupTabWallet.isSelected = false
+                mBinding.groupTabNewsfeed.isSelected = false
                 mBinding.groupTabMe.isSelected = false
             }
             1 -> {
                 mBinding.groupTabHome.isSelected = false
-                mBinding.groupTabParttime.isSelected = true
-                mBinding.groupTabActives.isSelected = false
-                mBinding.groupTabWallet.isSelected = false
+                mBinding.groupTabWallet.isSelected = true
+                mBinding.groupTabNewsfeed.isSelected = false
                 mBinding.groupTabMe.isSelected = false
             }
             2 -> {
                 mBinding.groupTabHome.isSelected = false
-                mBinding.groupTabParttime.isSelected = false
-                mBinding.groupTabActives.isSelected = true
                 mBinding.groupTabWallet.isSelected = false
+                mBinding.groupTabNewsfeed.isSelected = true
                 mBinding.groupTabMe.isSelected = false
             }
             3 -> {
                 mBinding.groupTabHome.isSelected = false
-                mBinding.groupTabParttime.isSelected = false
-                mBinding.groupTabActives.isSelected = false
-                mBinding.groupTabWallet.isSelected = true
-                mBinding.groupTabMe.isSelected = false
-            }
-            else -> {
-                mBinding.groupTabHome.isSelected = false
-                mBinding.groupTabParttime.isSelected = false
-                mBinding.groupTabActives.isSelected = false
                 mBinding.groupTabWallet.isSelected = false
+                mBinding.groupTabNewsfeed.isSelected = false
                 mBinding.groupTabMe.isSelected = true
             }
         }
@@ -232,9 +208,8 @@ class MainActivity : YYBaseVDBActivity<MainViewModel, ActivityMainBinding>() {
     private fun initFragment() {
         // 正常情况下初始化
         mHomeFragment = HomeFragment()
-        mPartTimeFragment = YYRouterService.parttimeComponentServer?.obtainPartTimeMainFragment()
-        mActivesFragment = YYRouterService.parttimeComponentServer?.obtainPartTimeActivesFragment()
         mEWalletFragment = YYRouterService.eWalletComponentServer?.obtainEWalletMainFragment()
+        mNewsFeedFragment = YYRouterService.newsfeedComponentServer?.obtainNewsFeedMainFragment()
         mProfileFragment = YYRouterService.parttimeComponentServer?.obtainPartTimeProfileFragment()
     }
 
@@ -254,14 +229,12 @@ class MainActivity : YYBaseVDBActivity<MainViewModel, ActivityMainBinding>() {
             val f1 = manager.findFragmentByTag("1")
             val f2 = manager.findFragmentByTag("2")
             val f3 = manager.findFragmentByTag("3")
-            val f4 = manager.findFragmentByTag("4")
 
             // 复用
             mHomeFragment = f0 ?: HomeFragment()
-            mPartTimeFragment = f1 ?: YYRouterService.parttimeComponentServer?.obtainPartTimeMainFragment()
-            mActivesFragment = f2 ?: YYRouterService.parttimeComponentServer?.obtainPartTimeActivesFragment()
-            mEWalletFragment = f3 ?: YYRouterService.eWalletComponentServer?.obtainEWalletMainFragment()
-            mProfileFragment = f4 ?: YYRouterService.parttimeComponentServer?.obtainPartTimeProfileFragment()
+            mEWalletFragment = f1 ?: YYRouterService.eWalletComponentServer?.obtainEWalletMainFragment()
+            mNewsFeedFragment = f2 ?: YYRouterService.newsfeedComponentServer?.obtainNewsFeedMainFragment()
+            mProfileFragment = f3 ?: YYRouterService.parttimeComponentServer?.obtainPartTimeProfileFragment()
         }
     }
 
@@ -291,11 +264,11 @@ class MainActivity : YYBaseVDBActivity<MainViewModel, ActivityMainBinding>() {
             }
         }
 
-        fun switchPartTime() {
+        fun switchEWallet() {
             mClickPage = 1
             if (mClickPage == mCurPosition) {
                 //重复点击
-                mPartTimeFragment?.let {
+                mEWalletFragment?.let {
                     if (it is IFragmentRefresh) (it as IFragmentRefresh).scrollTopRefresh()
                 }
             } else {
@@ -303,11 +276,11 @@ class MainActivity : YYBaseVDBActivity<MainViewModel, ActivityMainBinding>() {
             }
         }
 
-        fun switchActives() {
+        fun switchNewsFeed() {
             mClickPage = 2
             if (mClickPage == mCurPosition) {
                 //重复点击
-                mActivesFragment?.let {
+                mNewsFeedFragment?.let {
                     if (it is IFragmentRefresh) (it as IFragmentRefresh).scrollTopRefresh()
                 }
             } else {
@@ -315,29 +288,16 @@ class MainActivity : YYBaseVDBActivity<MainViewModel, ActivityMainBinding>() {
             }
         }
 
-        //切换消息页面Tab
-        fun switchEWallet() {
-            mClickPage = 3
-            if (mClickPage == mCurPosition) {
-                //重复点击
-                mEWalletFragment?.let {
-                    if (it is IFragmentRefresh) (it as IFragmentRefresh).scrollTopRefresh()
-                }
-            } else {
-                switchFragment(3)
-            }
-        }
-
         //切换Me页面Tab
         fun switchProfile() {
-            mClickPage = 4
+            mClickPage = 3
             if (mClickPage == mCurPosition) {
                 //重复点击
                 mProfileFragment?.let {
                     if (it is IFragmentRefresh) (it as IFragmentRefresh).scrollTopRefresh()
                 }
             } else {
-                switchFragment(4)
+                switchFragment(3)
             }
         }
 

二进制
cpt_main/src/main/res/drawable-xxhdpi/main_active_blue.webp


二进制
cpt_main/src/main/res/drawable-xxhdpi/main_active_gray.webp


二进制
cpt_main/src/main/res/drawable-xxhdpi/main_newsfeed_blue.webp


二进制
cpt_main/src/main/res/drawable-xxhdpi/main_newsfeed_gray.webp


二进制
cpt_main/src/main/res/drawable-xxhdpi/main_part_jobs_blue.webp


二进制
cpt_main/src/main/res/drawable-xxhdpi/main_part_jobs_gray.webp


+ 0 - 11
cpt_main/src/main/res/drawable/selector_main_tab_active.xml

@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <item android:drawable="@drawable/main_active_blue" android:state_pressed="true" />
-    <item android:drawable="@drawable/main_active_blue" android:state_selected="true" />
-    <item android:drawable="@drawable/main_active_blue" android:state_active="true" />
-    <item android:drawable="@drawable/main_active_gray" android:state_selected="false" />
-    <item android:drawable="@drawable/main_active_gray" android:state_active="false" />
-    <item android:drawable="@drawable/main_active_gray" android:state_pressed="false" />
-
-</selector>

+ 11 - 0
cpt_main/src/main/res/drawable/selector_main_tab_newsfeed.xml

@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item android:drawable="@drawable/main_newsfeed_blue" android:state_pressed="true" />
+    <item android:drawable="@drawable/main_newsfeed_blue" android:state_selected="true" />
+    <item android:drawable="@drawable/main_newsfeed_blue" android:state_active="true" />
+    <item android:drawable="@drawable/main_newsfeed_gray" android:state_selected="false" />
+    <item android:drawable="@drawable/main_newsfeed_gray" android:state_active="false" />
+    <item android:drawable="@drawable/main_newsfeed_gray" android:state_pressed="false" />
+
+</selector>

+ 0 - 11
cpt_main/src/main/res/drawable/selector_main_tab_partjob.xml

@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <item android:drawable="@drawable/main_part_jobs_blue" android:state_pressed="true" />
-    <item android:drawable="@drawable/main_part_jobs_blue" android:state_selected="true" />
-    <item android:drawable="@drawable/main_part_jobs_blue" android:state_active="true" />
-    <item android:drawable="@drawable/main_part_jobs_gray" android:state_selected="false" />
-    <item android:drawable="@drawable/main_part_jobs_gray" android:state_active="false" />
-    <item android:drawable="@drawable/main_part_jobs_gray" android:state_pressed="false" />
-
-</selector>

+ 20 - 69
cpt_main/src/main/res/layout/activity_main.xml

@@ -94,89 +94,65 @@
 
             </androidx.constraintlayout.widget.ConstraintLayout>
 
-            <!-- 兼职 -->
-            <androidx.constraintlayout.widget.ConstraintLayout
-                android:id="@+id/group_tab_parttime"
+            <!--钱包-->
+            <LinearLayout
+                android:id="@+id/group_tab_wallet"
                 style="@style/SelectableItemBackgroundLess"
                 android:layout_width="0dp"
                 android:layout_height="wrap_content"
                 android:layout_weight="1"
-                android:onClick="@{() -> click.switchPartTime()}">
+                android:gravity="center"
+                android:onClick="@{() -> click.switchEWallet()}"
+                android:orientation="vertical">
 
                 <ImageView
-                    android:id="@+id/iv_parttime_text"
                     android:layout_width="@dimen/d_30dp"
                     android:layout_height="@dimen/d_30dp"
-                    android:src="@drawable/selector_main_tab_partjob"
-                    app:layout_constraintBottom_toTopOf="@+id/tv_parttime_text"
-                    app:layout_constraintLeft_toLeftOf="parent"
-                    app:layout_constraintRight_toRightOf="parent"
-                    app:layout_constraintTop_toTopOf="parent"
-                    app:layout_constraintVertical_chainStyle="packed" />
+                    android:src="@drawable/selector_main_tab_wallet" />
 
                 <com.guadou.lib_baselib.font_text_view.TextViewMedium
-                    android:id="@+id/tv_parttime_text"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:text="兼职"
+                    android:text="钱包"
                     android:textColor="@color/selector_tab_main_text"
-                    android:textSize="@dimen/d_12sp"
-                    app:layout_constraintBottom_toBottomOf="parent"
-                    app:layout_constraintLeft_toLeftOf="parent"
-                    app:layout_constraintRight_toRightOf="parent"
-                    app:layout_constraintTop_toBottomOf="@+id/iv_parttime_text" />
-
-                <com.guadou.lib_baselib.font_text_view.TextViewRegular
-                    android:id="@+id/tv_parttime_unread_num"
-                    android:layout_width="@dimen/d_15dp"
-                    android:layout_height="@dimen/d_15dp"
-                    android:layout_marginLeft="@dimen/d_30dp"
-                    android:background="@drawable/shape_circle_red"
-                    android:gravity="center"
-                    android:text="2"
-                    android:textColor="@color/white"
-                    android:textSize="@dimen/d_8sp"
-                    android:visibility="gone"
-                    app:layout_constraintLeft_toLeftOf="parent"
-                    app:layout_constraintRight_toRightOf="parent"
-                    app:layout_constraintTop_toTopOf="parent" />
+                    android:textSize="@dimen/d_12sp" />
 
-            </androidx.constraintlayout.widget.ConstraintLayout>
+            </LinearLayout>
 
-            <!-- 工作状态 -->
+            <!-- 朋友圈 -->
             <androidx.constraintlayout.widget.ConstraintLayout
-                android:id="@+id/group_tab_actives"
+                android:id="@+id/group_tab_newsfeed"
                 style="@style/SelectableItemBackgroundLess"
                 android:layout_width="0dp"
                 android:layout_height="wrap_content"
                 android:layout_weight="1"
-                android:onClick="@{() -> click.switchActives()}">
+                android:onClick="@{() -> click.switchNewsFeed()}">
 
                 <ImageView
-                    android:id="@+id/iv_actives_text"
+                    android:id="@+id/iv_newsfeed_text"
                     android:layout_width="@dimen/d_30dp"
                     android:layout_height="@dimen/d_30dp"
-                    android:src="@drawable/selector_main_tab_active"
-                    app:layout_constraintBottom_toTopOf="@+id/tv_actives_text"
+                    android:src="@drawable/selector_main_tab_newsfeed"
+                    app:layout_constraintBottom_toTopOf="@+id/tv_newsfeed_text"
                     app:layout_constraintLeft_toLeftOf="parent"
                     app:layout_constraintRight_toRightOf="parent"
                     app:layout_constraintTop_toTopOf="parent"
                     app:layout_constraintVertical_chainStyle="packed" />
 
                 <com.guadou.lib_baselib.font_text_view.TextViewMedium
-                    android:id="@+id/tv_actives_text"
+                    android:id="@+id/tv_newsfeed_text"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:text="工作状态"
+                    android:text="朋友圈"
                     android:textColor="@color/selector_tab_main_text"
                     android:textSize="@dimen/d_12sp"
                     app:layout_constraintBottom_toBottomOf="parent"
                     app:layout_constraintLeft_toLeftOf="parent"
                     app:layout_constraintRight_toRightOf="parent"
-                    app:layout_constraintTop_toBottomOf="@+id/iv_actives_text" />
+                    app:layout_constraintTop_toBottomOf="@+id/iv_newsfeed_text" />
 
                 <com.guadou.lib_baselib.font_text_view.TextViewRegular
-                    android:id="@+id/tv_actives_unread_num"
+                    android:id="@+id/tv_newsfeed_unread_num"
                     android:layout_width="@dimen/d_8dp"
                     android:layout_height="@dimen/d_8dp"
                     android:layout_marginLeft="@dimen/d_30dp"
@@ -190,31 +166,6 @@
 
             </androidx.constraintlayout.widget.ConstraintLayout>
 
-            <!--钱包-->
-            <LinearLayout
-                android:id="@+id/group_tab_wallet"
-                style="@style/SelectableItemBackgroundLess"
-                android:layout_width="0dp"
-                android:layout_height="wrap_content"
-                android:layout_weight="1"
-                android:gravity="center"
-                android:onClick="@{() -> click.switchEWallet()}"
-                android:orientation="vertical">
-
-                <ImageView
-                    android:layout_width="@dimen/d_30dp"
-                    android:layout_height="@dimen/d_30dp"
-                    android:src="@drawable/selector_main_tab_wallet" />
-
-                <com.guadou.lib_baselib.font_text_view.TextViewMedium
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:text="钱包"
-                    android:textColor="@color/selector_tab_main_text"
-                    android:textSize="@dimen/d_12sp" />
-
-            </LinearLayout>
-
             <!-- 我的  -->
             <androidx.constraintlayout.widget.ConstraintLayout
                 android:id="@+id/group_tab_me"

+ 2 - 3
cpt_main/src/main/res/layout/fragment_home.xml

@@ -51,12 +51,12 @@
                 android:layout_gravity="center"
                 android:layout_marginRight="@dimen/d_15dp"
                 android:contentDescription="通知列表"
-                binding:clicks="@{click.gotoNotificationPage}"
                 android:src="@drawable/main_title_notification_icon"
                 android:visibility="visible"
                 app:layout_constraintBottom_toBottomOf="parent"
                 app:layout_constraintRight_toRightOf="parent"
-                app:layout_constraintTop_toTopOf="parent" />
+                app:layout_constraintTop_toTopOf="parent"
+                binding:clicks="@{click.gotoNotificationPage}" />
 
             <TextView
                 android:id="@+id/tv_badge_num"
@@ -99,7 +99,6 @@
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content" />
 
-
             <androidx.core.widget.NestedScrollView
                 android:id="@+id/scrollView"
                 android:layout_width="match_parent"

+ 1 - 0
cpt_newsfeed/.gitignore

@@ -0,0 +1 @@
+/build

+ 6 - 0
cpt_newsfeed/build.gradle

@@ -0,0 +1,6 @@
+apply from: "../module_default_config.gradle"
+
+dependencies {
+    //九宫格控件
+    implementation project(':cs_ninegrid')
+}

+ 21 - 0
cpt_newsfeed/proguard-rules.pro

@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile

+ 26 - 0
cpt_newsfeed/src/androidTest/java/com/hongyegroup/cpt_main/ExampleInstrumentedTest.java

@@ -0,0 +1,26 @@
+package com.hongyegroup.cpt_main;
+
+import android.content.Context;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+    @Test
+    public void useAppContext() {
+        // Context of the app under test.
+        Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        assertEquals("com.hongyegroup.cpt_parttime", appContext.getPackageName());
+    }
+}

+ 17 - 0
cpt_newsfeed/src/main/AndroidManifest.xml

@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.hongyegroup.cpt_newsfeed">
+
+    <application android:allowBackup="true">
+
+        <activity android:name=".ui.NewsFeedDetailActivity" />
+
+        <activity android:name=".ui.NewsFeedPostActivity" />
+
+        <activity android:name=".ui.NewsFeedFollowsActivity" />
+
+        <activity android:name=".ui.NewsFeedProfileActivity" />
+
+    </application>
+
+</manifest>

+ 30 - 0
cpt_newsfeed/src/main/java/com/hongyegroup/cpt_newsfeed/adapter/NewsFeedListAdapter.kt

@@ -0,0 +1,30 @@
+package com.hongyegroup.cpt_newsfeed.adapter
+
+import com.chad.library.adapter.base.BaseMultiItemQuickAdapter
+import com.chad.library.adapter.base.module.LoadMoreModule
+import com.chad.library.adapter.base.viewholder.BaseViewHolder
+import com.guadou.cs_cptservices.YYConstants
+import com.hongyegroup.cpt_newsfeed.R
+import com.hongyegroup.cpt_newsfeed.bean.NewsFeedAdatperBean
+
+/**
+ * 列表适配器
+ */
+class NewsFeedListAdapter(list: MutableList<NewsFeedAdatperBean>)
+    : BaseMultiItemQuickAdapter<NewsFeedAdatperBean, BaseViewHolder>(list), LoadMoreModule {
+
+    private var mTvWidth: Int = 0
+
+    init {
+        addItemType(YYConstants.NEWS_FEED_TYPE_NEWS, R.layout.item_news_feed_news)
+//        addItemType(YYConstants.NEWS_FEED_TYPE_BALLOT, R.layout.item_news_feed_ballot)
+//        addItemType(YYConstants.NEWS_FEED_TYPE_VIDEO, R.layout.item_news_feed_video)
+
+//        mTvWidth = ScreenUtils.getScreenWidth(context) - CommUtils.dip2px(45)
+    }
+
+    override fun convert(holder: BaseViewHolder, item: NewsFeedAdatperBean) {
+
+    }
+
+}

+ 132 - 0
cpt_newsfeed/src/main/java/com/hongyegroup/cpt_newsfeed/bean/NewsFeedAdatperBean.java

@@ -0,0 +1,132 @@
+package com.hongyegroup.cpt_newsfeed.bean;
+
+import com.chad.library.adapter.base.entity.MultiItemEntity;
+import com.google.gson.annotations.SerializedName;
+import com.guadou.cs_cptservices.YYConstants;
+import com.guadou.ninegrid.ImageInfo;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 朋友圈展示每一个动态的bean对象
+ * 分为两种 一种为动态 一种为投票
+ */
+public class NewsFeedAdatperBean implements Serializable, MultiItemEntity {
+
+    /* 动态 */
+    @SerializedName("id")
+    public String id;               //当前newsFeed的服务器id
+
+    @SerializedName("type")
+    public String type;                //当前newsFeed的类型 content是动态  poll是投票  video是视频模式
+
+    @SerializedName("group_id")
+    public String group_id;            //是否是圈子内的消息-圈子Id
+
+    @SerializedName("group_name")
+    public String group_name;       //圈子的名字
+
+    @SerializedName("topics")
+    public List<TopicBean> topics;           //相关的话题集合
+
+    @SerializedName("avatar")
+    public String avatar;           //当前newsFeed的发布者头像
+
+    @SerializedName("publish_member_id")
+    public String member_id;         //发布者的Id
+
+    @SerializedName("publish_by")
+    public String username;         //当前newsFeed的发布者姓名  如果为空展示YY Part Time Jobs
+
+    @SerializedName("likes_count")
+    public int likeNum;                    //当前newsFeed的点赞数量
+
+    @SerializedName("likes")
+    public List<LikeBean> likes;       //用于判断是否点赞
+
+    @SerializedName("comments_count")
+    public int commentNum;                 //当前newsFeed的评论数量
+
+    @SerializedName("share_count")
+    public int share_count;                 //当前newsFeed的分享数量
+
+    public String follow;          //判断是否关注
+
+    public int publish_fans_count;   //这个News的发布者的粉丝数量
+
+    /* 投票 */
+    @SerializedName("description")
+    public String contentDesc = "";          //动态和投票的内容
+
+    @SerializedName("question")
+    public String ballotQuestion;        //投票的问题
+
+    @SerializedName("poll_type")
+    public String ballotOptionType;      //投票文本的类型是图片还是文本 Image
+
+    @SerializedName("resources")
+    public List<OptionBean> resources;  //动态的两种type的资源都在这里
+
+    public int resource_type;   //resource的类型,1是默认的 2是视频
+
+
+    // ================== 自定义属性 begin ↓ ======================
+
+    public boolean myIsContentExpand;        //记录动态类型->当前newsFeed的内容是否展开了,默认为false(非服务器数据->列表是否展开了?)
+    public boolean myIsMyOptionSelected;     //记录投票类型->是否已经选择了 。需要判断 如果votes的length全部为0 就没有选择
+    public int myPollSelectedIndex = -1;    //已经选择的索引,默认没选择为-1
+    public List<ImageInfo> myNewsResources;  //动态的资源
+    public List<ImageInfo> myPollImages;      //投票的图片资源
+
+
+    //    public List<String> myPoolTexts;       //投票的文字资源
+//    public boolean isNewFollow = false;           //自定义的属性->是否是刚刚新关注的
+
+    // ================== 自定义属性 end ↑ ======================
+
+    //多类型布局
+    @Override
+    public int getItemType() {
+        if (type.equals("Video")) {
+            return YYConstants.NEWS_FEED_TYPE_VIDEO;
+        } else if (type.equals("poll")) {
+            return YYConstants.NEWS_FEED_TYPE_BALLOT;
+        } else {
+            return YYConstants.NEWS_FEED_TYPE_NEWS;
+        }
+    }
+
+
+    //每一个投票选项的数据
+    public static class OptionBean implements Serializable {
+        @SerializedName("id")
+        public String optionId;
+        @SerializedName("text")
+        public String textContent;
+        @SerializedName("image")
+        public String imgurl;
+        @SerializedName("votes")
+        public List<Object> votes;   //判断当前用户是否投票了
+        @SerializedName("votes_count")
+        public int votes_count;   //当前投票的总数量
+    }
+
+    @SerializedName("created_at")
+    public String publishDate;   //不同type共有的发布时间
+
+    public String micro_at;     //时间戳
+
+
+    public static class LikeBean implements Serializable {
+        public String likeable_type;
+        public int emoticon_id = 1;
+
+    }
+
+    public static class TopicBean implements Serializable {
+        public String topic_id;
+        public String topic_name;
+    }
+
+}

+ 13 - 0
cpt_newsfeed/src/main/java/com/hongyegroup/cpt_newsfeed/mvvm/NewsFeedDetailViewModel.kt

@@ -0,0 +1,13 @@
+package com.hongyegroup.cpt_newsfeed.mvvm
+
+import androidx.lifecycle.SavedStateHandle
+import com.guadou.lib_baselib.base.vm.BaseViewModel
+import dagger.hilt.android.lifecycle.HiltViewModel
+import javax.inject.Inject
+
+@HiltViewModel
+class NewsFeedDetailViewModel @Inject constructor(
+    private val savedStateHandle: SavedStateHandle
+) : BaseViewModel() {
+
+}

+ 13 - 0
cpt_newsfeed/src/main/java/com/hongyegroup/cpt_newsfeed/mvvm/NewsFeedFansViewModel.kt

@@ -0,0 +1,13 @@
+package com.hongyegroup.cpt_newsfeed.mvvm
+
+import androidx.lifecycle.SavedStateHandle
+import com.guadou.lib_baselib.base.vm.BaseViewModel
+import dagger.hilt.android.lifecycle.HiltViewModel
+import javax.inject.Inject
+
+@HiltViewModel
+class NewsFeedFansViewModel @Inject constructor(
+    private val savedStateHandle: SavedStateHandle
+) : BaseViewModel() {
+
+}

+ 13 - 0
cpt_newsfeed/src/main/java/com/hongyegroup/cpt_newsfeed/mvvm/NewsFeedFollowViewModel.kt

@@ -0,0 +1,13 @@
+package com.hongyegroup.cpt_newsfeed.mvvm
+
+import androidx.lifecycle.SavedStateHandle
+import com.guadou.lib_baselib.base.vm.BaseViewModel
+import dagger.hilt.android.lifecycle.HiltViewModel
+import javax.inject.Inject
+
+@HiltViewModel
+class NewsFeedFollowViewModel @Inject constructor(
+    private val savedStateHandle: SavedStateHandle
+) : BaseViewModel() {
+
+}

+ 98 - 0
cpt_newsfeed/src/main/java/com/hongyegroup/cpt_newsfeed/mvvm/NewsFeedFollowingViewModel.kt

@@ -0,0 +1,98 @@
+package com.hongyegroup.cpt_newsfeed.mvvm
+
+import android.annotation.SuppressLint
+import android.view.View
+import android.widget.TextView
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.SavedStateHandle
+import com.guadou.lib_baselib.base.vm.BaseViewModel
+import com.guadou.lib_baselib.ext.checkEmpty
+import com.guadou.lib_baselib.utils.CommUtils
+import com.hongyegroup.cpt_newsfeed.R
+import com.hongyegroup.cpt_newsfeed.adapter.NewsFeedListAdapter
+import com.hongyegroup.cpt_newsfeed.bean.NewsFeedAdatperBean
+import dagger.hilt.android.lifecycle.HiltViewModel
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.withContext
+import javax.inject.Inject
+
+@HiltViewModel
+class NewsFeedFollowingViewModel @Inject constructor(
+    private val savedStateHandle: SavedStateHandle
+) : BaseViewModel() {
+
+    var mCurPage = 1
+    var isNeedPlaceHolder = true
+    var isNeedCleanAllData = true
+
+    var mDatas = mutableListOf<NewsFeedAdatperBean>()
+    val mAdapter by lazy { NewsFeedListAdapter(mDatas) }
+
+    /**
+     * 获取动态的数据
+     */
+    fun getNewsFeedList() : LiveData<Boolean> {
+        val liveData = MutableLiveData<Boolean>()
+
+        launchOnUI {
+            //开始Loading
+            if (isNeedPlaceHolder) loadStartLoading()
+            val result = withContext(Dispatchers.IO) {
+                delay(1000)
+
+                val list = mutableListOf<NewsFeedAdatperBean>()
+                for (i in 1..10) {
+                    list.add(NewsFeedAdatperBean().apply {
+                        type = "news"
+                    })
+                }
+                return@withContext list
+            }
+
+            loadSuccess()
+            handleData(result)
+            liveData.postValue(true)
+
+        }
+
+        return liveData
+    }
+
+    //处理数据-添加或刷新
+    @SuppressLint("NotifyDataSetChanged")
+    private fun handleData(list: List<NewsFeedAdatperBean>?) {
+        if (!list.checkEmpty()) {
+            //有数据,判断是刷新还是加载更多的数据
+            if (isNeedCleanAllData) {
+                //刷新的方式
+                mDatas.clear()
+                mDatas.addAll(list!!)
+                mAdapter.notifyDataSetChanged()
+            } else {
+                //加载更多
+                mDatas.addAll(list!!)
+                mAdapter.notifyItemRangeInserted(mDatas.size - list.size, list.size)
+                mAdapter.loadMoreModule.loadMoreComplete()
+            }
+        } else {
+            //展示无数据
+            if (isNeedCleanAllData && mCurPage == 1) {
+                mDatas.clear()
+                mAdapter.notifyDataSetChanged()
+                //展示无数据的布局
+                val emptyView: View = CommUtils.inflate(R.layout.item_empty_layout)
+                emptyView.findViewById<TextView>(R.id.tv_empty_msg).text = "暂无任何动态"
+                mAdapter.setEmptyView(emptyView)
+            } else {
+                //如果是加载更多,展示加载完成,没有更多数据了
+                mAdapter.loadMoreModule.loadMoreEnd()
+            }
+        }
+        isNeedPlaceHolder = false
+        isNeedCleanAllData = false
+    }
+
+
+}

+ 13 - 0
cpt_newsfeed/src/main/java/com/hongyegroup/cpt_newsfeed/mvvm/NewsFeedFollowsViewModel.kt

@@ -0,0 +1,13 @@
+package com.hongyegroup.cpt_newsfeed.mvvm
+
+import androidx.lifecycle.SavedStateHandle
+import com.guadou.lib_baselib.base.vm.BaseViewModel
+import dagger.hilt.android.lifecycle.HiltViewModel
+import javax.inject.Inject
+
+@HiltViewModel
+class NewsFeedFollowsViewModel @Inject constructor(
+    private val savedStateHandle: SavedStateHandle
+) : BaseViewModel() {
+
+}

+ 16 - 0
cpt_newsfeed/src/main/java/com/hongyegroup/cpt_newsfeed/mvvm/NewsFeedMainViewModel.kt

@@ -0,0 +1,16 @@
+package com.hongyegroup.cpt_newsfeed.mvvm
+
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.SavedStateHandle
+import com.guadou.lib_baselib.base.vm.BaseViewModel
+import dagger.hilt.android.lifecycle.HiltViewModel
+import javax.inject.Inject
+
+@HiltViewModel
+class NewsFeedMainViewModel @Inject constructor(
+    private val savedStateHandle: SavedStateHandle
+) : BaseViewModel() {
+
+    val mFragments = mutableListOf<Fragment>()
+
+}

+ 13 - 0
cpt_newsfeed/src/main/java/com/hongyegroup/cpt_newsfeed/mvvm/NewsFeedMomentViewModel.kt

@@ -0,0 +1,13 @@
+package com.hongyegroup.cpt_newsfeed.mvvm
+
+import androidx.lifecycle.SavedStateHandle
+import com.guadou.lib_baselib.base.vm.BaseViewModel
+import dagger.hilt.android.lifecycle.HiltViewModel
+import javax.inject.Inject
+
+@HiltViewModel
+class NewsFeedMomentViewModel @Inject constructor(
+    private val savedStateHandle: SavedStateHandle
+) : BaseViewModel() {
+
+}

+ 13 - 0
cpt_newsfeed/src/main/java/com/hongyegroup/cpt_newsfeed/mvvm/NewsFeedPostViewModel.kt

@@ -0,0 +1,13 @@
+package com.hongyegroup.cpt_newsfeed.mvvm
+
+import androidx.lifecycle.SavedStateHandle
+import com.guadou.lib_baselib.base.vm.BaseViewModel
+import dagger.hilt.android.lifecycle.HiltViewModel
+import javax.inject.Inject
+
+@HiltViewModel
+class NewsFeedPostViewModel @Inject constructor(
+    private val savedStateHandle: SavedStateHandle
+) : BaseViewModel() {
+
+}

+ 13 - 0
cpt_newsfeed/src/main/java/com/hongyegroup/cpt_newsfeed/mvvm/NewsFeedProfileViewModel.kt

@@ -0,0 +1,13 @@
+package com.hongyegroup.cpt_newsfeed.mvvm
+
+import androidx.lifecycle.SavedStateHandle
+import com.guadou.lib_baselib.base.vm.BaseViewModel
+import dagger.hilt.android.lifecycle.HiltViewModel
+import javax.inject.Inject
+
+@HiltViewModel
+class NewsFeedProfileViewModel @Inject constructor(
+    private val savedStateHandle: SavedStateHandle
+) : BaseViewModel() {
+
+}

+ 24 - 0
cpt_newsfeed/src/main/java/com/hongyegroup/cpt_newsfeed/router/NewsFeedComponentServiceImpl.kt

@@ -0,0 +1,24 @@
+package com.hongyegroup.cpt_newsfeed.router
+
+import android.content.Context
+import androidx.fragment.app.Fragment
+import com.alibaba.android.arouter.facade.annotation.Route
+import com.guadou.cs_router.ARouterPath
+import com.guadou.cs_router.newsfeed.INewsFeedComponentServer
+import com.hongyegroup.cpt_newsfeed.ui.NewsFeedMainFragment
+
+@Route(path = ARouterPath.PATH_SERVICE_NEWSFEED, name = "NewsFeed模块路由服务")
+class NewsFeedComponentServiceImpl : INewsFeedComponentServer {
+
+    override fun startNewsFeedPostPage() {
+    }
+
+    override fun obtainNewsFeedMainFragment(): Fragment {
+        return NewsFeedMainFragment()
+    }
+
+    override fun init(context: Context?) {
+    }
+
+
+}

+ 53 - 0
cpt_newsfeed/src/main/java/com/hongyegroup/cpt_newsfeed/ui/NewsFeedDetailActivity.kt

@@ -0,0 +1,53 @@
+package com.hongyegroup.cpt_newsfeed.ui
+
+import android.content.Intent
+import android.os.Bundle
+import com.guadou.cs_cptservices.base.activity.YYBaseVDBActivity
+import com.guadou.lib_baselib.bean.DataBindingConfig
+import com.guadou.lib_baselib.utils.CommUtils
+import com.guadou.lib_baselib.utils.KeyboardUtils
+import com.hongyegroup.cpt_newsfeed.BR
+import com.hongyegroup.cpt_newsfeed.R
+import com.hongyegroup.cpt_newsfeed.databinding.ActivityNewsfeedDetailBinding
+import com.hongyegroup.cpt_newsfeed.mvvm.NewsFeedDetailViewModel
+import dagger.hilt.android.AndroidEntryPoint
+
+/**
+ * 动态详情页面
+ */
+@AndroidEntryPoint
+class NewsFeedDetailActivity : YYBaseVDBActivity<NewsFeedDetailViewModel, ActivityNewsfeedDetailBinding>() {
+
+    companion object {
+        fun startInstance() {
+            val context = CommUtils.getContext()
+            val intent = Intent(context, NewsFeedDetailActivity::class.java)
+            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+            context.startActivity(intent)
+        }
+    }
+
+    override fun getDataBindingConfig(): DataBindingConfig {
+        return DataBindingConfig(R.layout.activity_newsfeed_detail, BR.viewModel, mViewModel)
+            .addBindingParams(BR.click, ClickProxy())
+    }
+
+    override fun init(savedInstanceState: Bundle?) {
+        setStatusBarBlackText()
+    }
+
+    override fun startObserve() {
+
+    }
+
+    /**
+     * DataBinding事件处理
+     */
+    inner class ClickProxy {
+
+        fun selectCountryCode() {
+            KeyboardUtils.hideSoftInput(mActivity)
+        }
+
+    }
+}

+ 44 - 0
cpt_newsfeed/src/main/java/com/hongyegroup/cpt_newsfeed/ui/NewsFeedFansFragment.kt

@@ -0,0 +1,44 @@
+package com.hongyegroup.cpt_newsfeed.ui
+
+import android.os.Bundle
+import com.guadou.cs_cptservices.base.fragment.YYBaseVDBLazyLoadingFragment
+import com.guadou.lib_baselib.bean.DataBindingConfig
+import com.guadou.lib_baselib.utils.KeyboardUtils
+import com.hongyegroup.cpt_newsfeed.BR
+import com.hongyegroup.cpt_newsfeed.R
+import com.hongyegroup.cpt_newsfeed.databinding.FragmentNewsfeedFansBinding
+import com.hongyegroup.cpt_newsfeed.mvvm.NewsFeedFansViewModel
+
+/**
+ * 关注我的人员列表 粉丝列表
+ */
+class NewsFeedFansFragment : YYBaseVDBLazyLoadingFragment<NewsFeedFansViewModel, FragmentNewsfeedFansBinding>() {
+
+    override fun getDataBindingConfig(): DataBindingConfig {
+        return DataBindingConfig(R.layout.fragment_newsfeed_fans, BR.viewModel, mViewModel)
+            .addBindingParams(BR.click, ClickProxy())
+    }
+
+    override fun init(savedInstanceState: Bundle?) {
+    }
+
+    override fun onLazyInitData() {
+
+    }
+
+    override fun startObserve() {
+
+    }
+
+    /**
+     * DataBinding事件处理
+     */
+    inner class ClickProxy {
+
+        fun selectCountryCode() {
+            KeyboardUtils.hideSoftInput(mActivity)
+        }
+
+    }
+
+}

+ 42 - 0
cpt_newsfeed/src/main/java/com/hongyegroup/cpt_newsfeed/ui/NewsFeedFollowFragment.kt

@@ -0,0 +1,42 @@
+package com.hongyegroup.cpt_newsfeed.ui
+
+import android.os.Bundle
+import com.guadou.cs_cptservices.base.fragment.YYBaseVDBLazyLoadingFragment
+import com.guadou.lib_baselib.bean.DataBindingConfig
+import com.guadou.lib_baselib.utils.KeyboardUtils
+import com.hongyegroup.cpt_newsfeed.BR
+import com.hongyegroup.cpt_newsfeed.R
+import com.hongyegroup.cpt_newsfeed.databinding.FragmentNewsfeedFollowBinding
+import com.hongyegroup.cpt_newsfeed.mvvm.NewsFeedFollowViewModel
+
+/**
+ * 我关注的人员列表
+ */
+class NewsFeedFollowFragment : YYBaseVDBLazyLoadingFragment<NewsFeedFollowViewModel, FragmentNewsfeedFollowBinding>() {
+
+    override fun getDataBindingConfig(): DataBindingConfig {
+        return DataBindingConfig(R.layout.fragment_newsfeed_follow, BR.viewModel, mViewModel)
+            .addBindingParams(BR.click, ClickProxy())
+    }
+
+    override fun init(savedInstanceState: Bundle?) {
+    }
+
+    override fun onLazyInitData() {
+    }
+
+    override fun startObserve() {
+    }
+
+    /**
+     * DataBinding事件处理
+     */
+    inner class ClickProxy {
+
+        fun selectCountryCode() {
+            KeyboardUtils.hideSoftInput(mActivity)
+        }
+
+    }
+
+}

+ 53 - 0
cpt_newsfeed/src/main/java/com/hongyegroup/cpt_newsfeed/ui/NewsFeedFollowsActivity.kt

@@ -0,0 +1,53 @@
+package com.hongyegroup.cpt_newsfeed.ui
+
+import android.content.Intent
+import android.os.Bundle
+import com.guadou.cs_cptservices.base.activity.YYBaseVDBActivity
+import com.guadou.lib_baselib.bean.DataBindingConfig
+import com.guadou.lib_baselib.utils.CommUtils
+import com.guadou.lib_baselib.utils.KeyboardUtils
+import com.hongyegroup.cpt_newsfeed.BR
+import com.hongyegroup.cpt_newsfeed.R
+import com.hongyegroup.cpt_newsfeed.databinding.ActivityNewsfeedFollowsBinding
+import com.hongyegroup.cpt_newsfeed.mvvm.NewsFeedFollowsViewModel
+import dagger.hilt.android.AndroidEntryPoint
+
+/**
+ * 动态中关注与被关注的ViewPager
+ */
+@AndroidEntryPoint
+class NewsFeedFollowsActivity : YYBaseVDBActivity<NewsFeedFollowsViewModel, ActivityNewsfeedFollowsBinding>() {
+
+    companion object {
+        fun startInstance() {
+            val context = CommUtils.getContext()
+            val intent = Intent(context, NewsFeedFollowsActivity::class.java)
+            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+            context.startActivity(intent)
+        }
+    }
+
+    override fun getDataBindingConfig(): DataBindingConfig {
+        return DataBindingConfig(R.layout.activity_newsfeed_follows, BR.viewModel, mViewModel)
+            .addBindingParams(BR.click, ClickProxy())
+    }
+
+    override fun init(savedInstanceState: Bundle?) {
+        setStatusBarBlackText()
+    }
+
+    override fun startObserve() {
+
+    }
+
+    /**
+     * DataBinding事件处理
+     */
+    inner class ClickProxy {
+
+        fun selectCountryCode() {
+            KeyboardUtils.hideSoftInput(mActivity)
+        }
+
+    }
+}

+ 106 - 0
cpt_newsfeed/src/main/java/com/hongyegroup/cpt_newsfeed/ui/NewsFeedListFragment.kt

@@ -0,0 +1,106 @@
+package com.hongyegroup.cpt_newsfeed.ui
+
+import android.os.Bundle
+import android.view.View
+import com.chad.library.adapter.base.listener.OnLoadMoreListener
+import com.guadou.cs_cptservices.base.fragment.YYBaseVDBLazyLoadingFragment
+import com.guadou.cs_cptservices.interfaces.IFragmentRefresh
+import com.guadou.lib_baselib.bean.DataBindingConfig
+import com.guadou.lib_baselib.engine.toast
+import com.guadou.lib_baselib.ext.vertical
+import com.guadou.lib_baselib.utils.log.YYLogUtils
+import com.guadou.lib_baselib.view.gloading.Gloading
+import com.guadou.lib_baselib.view.gloading.GloadingPlaceHolderlAdapter
+import com.hongyegroup.cpt_newsfeed.R
+import com.hongyegroup.cpt_newsfeed.databinding.FragmentNewsfeedFollowingBinding
+import com.hongyegroup.cpt_newsfeed.mvvm.NewsFeedFollowingViewModel
+import com.scwang.smart.refresh.layout.api.RefreshLayout
+import com.scwang.smart.refresh.layout.listener.OnRefreshListener
+
+/**
+ * 多类型的动态列表页面
+ */
+class NewsFeedListFragment(private val type: Int) : YYBaseVDBLazyLoadingFragment<NewsFeedFollowingViewModel, FragmentNewsfeedFollowingBinding>(),
+    IFragmentRefresh, OnRefreshListener, OnLoadMoreListener {
+
+    override fun getDataBindingConfig(): DataBindingConfig {
+        return DataBindingConfig(R.layout.fragment_newsfeed_following)
+    }
+
+    //重新生成GLoading对象
+    override fun generateGLoading(view: View): Gloading.Holder {
+        return Gloading.from(GloadingPlaceHolderlAdapter(R.layout.layout_placeholder_newsfeed_hot)).wrap(view)
+            .withRetry { onLazyInitData() }
+    }
+
+    override fun init(savedInstanceState: Bundle?) {
+        initRV()
+        initListener()
+    }
+
+    override fun onLazyInitData() {
+        YYLogUtils.w("onLazyInitData-1")
+        initData()
+    }
+
+    private fun initData() {
+        mViewModel.getNewsFeedList().observe(this) {
+            mBinding.refreshLayout.finishRefresh()
+            mViewModel.mAdapter.loadMoreModule.isEnableLoadMore = true
+        }
+    }
+
+    private fun initListener() {
+        //Adapter的滑动监听,监听加载更多
+        mViewModel.mAdapter.loadMoreModule.isEnableLoadMore = false
+        mViewModel.mAdapter.loadMoreModule.preLoadNumber = 4
+        mViewModel.mAdapter.loadMoreModule.setOnLoadMoreListener(this)
+
+        //刷新控件初始化
+        mBinding.refreshLayout.setEnableNestedScroll(true)
+        mBinding.refreshLayout.setEnableLoadMore(false)
+        mBinding.refreshLayout.setEnableRefresh(true)
+        mBinding.refreshLayout.setOnRefreshListener(this)
+
+        //Item点击
+        mViewModel.mAdapter.addChildClickViewIds(R.id.ll_news_feed_root)
+        mViewModel.mAdapter.setOnItemChildClickListener { _, _, position ->
+            val item = mViewModel.mDatas[position]
+            toast("点击Item")
+        }
+    }
+
+    override fun onRefresh(refreshLayout: RefreshLayout) {
+        mViewModel.isNeedCleanAllData = true
+        mViewModel.mAdapter.loadMoreModule.loadMoreComplete()
+        mViewModel.mAdapter.loadMoreModule.isEnableLoadMore = false
+        //直接调用,参数从成员变量中获取
+        mViewModel.mCurPage = 1
+        initData()
+    }
+
+    override fun onLoadMore() {
+        mViewModel.isNeedCleanAllData = false
+        mViewModel.mCurPage++
+        initData()
+    }
+
+    private fun initRV() {
+        mBinding.recyclerView.vertical().apply {
+            adapter = mViewModel.mAdapter
+        }
+    }
+
+    override fun scrollTopRefresh() {
+        if (mViewModel.mDatas.size > 1) {
+            mBinding.recyclerView.scrollToPosition(0)
+        }
+        mBinding.refreshLayout.autoRefresh()
+    }
+
+
+    override fun startObserve() {
+
+    }
+
+}

+ 154 - 0
cpt_newsfeed/src/main/java/com/hongyegroup/cpt_newsfeed/ui/NewsFeedMainFragment.kt

@@ -0,0 +1,154 @@
+package com.hongyegroup.cpt_newsfeed.ui
+
+import android.content.Intent
+import android.os.Bundle
+import android.view.View
+import androidx.viewpager.widget.ViewPager
+import com.guadou.cs_cptservices.base.fragment.YYBaseVDBFragment
+import com.guadou.cs_cptservices.interfaces.IFragmentRefresh
+import com.guadou.lib_baselib.base.Ghost
+import com.guadou.lib_baselib.bean.DataBindingConfig
+import com.guadou.lib_baselib.engine.toast
+import com.guadou.lib_baselib.ext.bindFragment
+import com.guadou.lib_baselib.utils.CommUtils
+import com.hongyegroup.cpt_newsfeed.BR
+import com.hongyegroup.cpt_newsfeed.R
+import com.hongyegroup.cpt_newsfeed.databinding.FragmentNewsfeedMainBinding
+import com.hongyegroup.cpt_newsfeed.mvvm.NewsFeedMainViewModel
+
+/**
+ * 首页动态广场的页面
+ * Tab + ViewPager
+ */
+class NewsFeedMainFragment : YYBaseVDBFragment<NewsFeedMainViewModel, FragmentNewsfeedMainBinding>(), IFragmentRefresh {
+
+    private var mCurPage = 1
+    private lateinit var mNewsFeedMonentsFragment: NewsFeedListFragment
+    private lateinit var mNewsFeedFollowingFragment: NewsFeedListFragment
+    private lateinit var mNewsFeedProfileFragment: NewsFeedProfileFragment
+
+    override fun getDataBindingConfig(): DataBindingConfig {
+        return DataBindingConfig(R.layout.fragment_newsfeed_main, BR.viewModel, mViewModel)
+            .addBindingParams(BR.click, ClickProxy())
+    }
+
+    override fun startObserve() {
+    }
+
+    override fun init(savedInstanceState: Bundle?) {
+        setStatusBarBlackText()
+
+        initAdapter()
+    }
+
+    private fun initAdapter() {
+        mNewsFeedMonentsFragment = NewsFeedListFragment(0)
+        mNewsFeedFollowingFragment = NewsFeedListFragment(1)
+        mNewsFeedProfileFragment = NewsFeedProfileFragment("8558", true)
+
+        mViewModel.mFragments.add(mNewsFeedMonentsFragment)
+        mViewModel.mFragments.add(mNewsFeedFollowingFragment)
+        mViewModel.mFragments.add(mNewsFeedProfileFragment)
+
+        mBinding.viewPager.bindFragment(childFragmentManager, mViewModel.mFragments)
+
+        mBinding.viewPager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
+            override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {}
+            override fun onPageScrollStateChanged(state: Int) {}
+            override fun onPageSelected(position: Int) {
+                mCurPage = position
+                setIndicator(position)
+            }
+        })
+
+        mBinding.viewPager.currentItem = 1
+    }
+
+    //点击顶部选择切换ViewPager的效果
+    private fun setCurrentPage(index: Int) {
+        mBinding.viewPager.currentItem = index
+        setIndicator(index)
+    }
+
+    //滑动ViewPager切换顶部选择的效果
+    private fun setIndicator(position: Int) {
+        mCurPage = position
+        when (position) {
+            0 -> {
+                mBinding.textMoments.setTextColor(CommUtils.getColor(R.color.app_blue))
+                mBinding.viewFollowLine.visibility = View.VISIBLE
+                mBinding.textFollowing.setTextColor(CommUtils.getColor(R.color.gray_88))
+                mBinding.viewForYouLine.visibility = View.GONE
+                mBinding.textPulished.setTextColor(CommUtils.getColor(R.color.gray_88))
+                mBinding.viewPublished.visibility = View.GONE
+            }
+            1 -> {
+                mBinding.textMoments.setTextColor(CommUtils.getColor(R.color.gray_88))
+                mBinding.viewFollowLine.visibility = View.GONE
+                mBinding.textFollowing.setTextColor(CommUtils.getColor(R.color.app_blue))
+                mBinding.viewForYouLine.visibility = View.VISIBLE
+                mBinding.textPulished.setTextColor(CommUtils.getColor(R.color.gray_88))
+                mBinding.viewPublished.visibility = View.GONE
+            }
+            else -> {
+                mBinding.textMoments.setTextColor(CommUtils.getColor(R.color.gray_88))
+                mBinding.viewFollowLine.visibility = View.GONE
+                mBinding.textFollowing.setTextColor(CommUtils.getColor(R.color.gray_88))
+                mBinding.viewForYouLine.visibility = View.GONE
+                mBinding.textPulished.setTextColor(CommUtils.getColor(R.color.app_blue))
+                mBinding.viewPublished.visibility = View.VISIBLE
+            }
+        }
+    }
+
+    override fun scrollTopRefresh() {
+        when (mCurPage) {
+            0 -> mNewsFeedMonentsFragment.scrollTopRefresh()
+            1 -> mNewsFeedFollowingFragment.scrollTopRefresh()
+            else -> mNewsFeedProfileFragment.scrollTopRefresh()
+        }
+    }
+
+    /**
+     * DataBinding事件处理
+     */
+    inner class ClickProxy {
+
+        //切换到朋友圈
+        fun switchMoments() {
+            if (mCurPage == 0) {
+                mNewsFeedMonentsFragment.scrollTopRefresh()
+            } else {
+                setCurrentPage(0)
+            }
+        }
+
+        //切换已关注的
+        fun switchFollowing() {
+            if (mCurPage == 1) {
+                mNewsFeedFollowingFragment.scrollTopRefresh()
+            } else {
+                setCurrentPage(1)
+            }
+        }
+
+        //切换我的发布
+        fun switchPulished() {
+            if (mCurPage == 2) {
+                mNewsFeedProfileFragment.scrollTopRefresh()
+            } else {
+                setCurrentPage(2)
+            }
+        }
+
+        //去发布页面
+        fun gotoPostPage() {
+            Ghost.launchActivityForResult(mActivity, Intent(mActivity, NewsFeedPostActivity::class.java)) {
+                val name = it?.getStringExtra("name")
+                toast("获取回调 name:" + name)
+            }
+        }
+
+    }
+
+}

+ 59 - 0
cpt_newsfeed/src/main/java/com/hongyegroup/cpt_newsfeed/ui/NewsFeedPostActivity.kt

@@ -0,0 +1,59 @@
+package com.hongyegroup.cpt_newsfeed.ui
+
+import android.content.Intent
+import android.os.Bundle
+import com.guadou.cs_cptservices.base.activity.YYBaseVDBActivity
+import com.guadou.lib_baselib.bean.DataBindingConfig
+import com.guadou.lib_baselib.utils.CommUtils
+import com.guadou.lib_baselib.utils.KeyboardUtils
+import com.hongyegroup.cpt_newsfeed.BR
+import com.hongyegroup.cpt_newsfeed.R
+import com.hongyegroup.cpt_newsfeed.databinding.ActivityNewsfeedPostBinding
+import com.hongyegroup.cpt_newsfeed.mvvm.NewsFeedPostViewModel
+import dagger.hilt.android.AndroidEntryPoint
+
+/**
+ * 动态发布页面
+ */
+@AndroidEntryPoint
+class NewsFeedPostActivity : YYBaseVDBActivity<NewsFeedPostViewModel, ActivityNewsfeedPostBinding>() {
+
+    companion object {
+        fun startInstance() {
+            val context = CommUtils.getContext()
+            val intent = Intent(context, NewsFeedPostActivity::class.java)
+            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+            context.startActivity(intent)
+        }
+    }
+
+    override fun getDataBindingConfig(): DataBindingConfig {
+        return DataBindingConfig(R.layout.activity_newsfeed_post, BR.viewModel, mViewModel)
+            .addBindingParams(BR.click, ClickProxy())
+    }
+
+    override fun init(savedInstanceState: Bundle?) {
+        setStatusBarBlackText()
+    }
+
+    override fun startObserve() {
+
+    }
+
+    /**
+     * DataBinding事件处理
+     */
+    inner class ClickProxy {
+
+        fun selectCountryCode() {
+            KeyboardUtils.hideSoftInput(mActivity)
+
+            setResult(-1, Intent().apply {
+                putExtra("name", "zhangsan")
+            })
+
+            finish()
+        }
+
+    }
+}

+ 50 - 0
cpt_newsfeed/src/main/java/com/hongyegroup/cpt_newsfeed/ui/NewsFeedProfileActivity.kt

@@ -0,0 +1,50 @@
+package com.hongyegroup.cpt_newsfeed.ui
+
+import android.content.Intent
+import android.os.Bundle
+import com.guadou.lib_baselib.base.activity.BaseVMActivity
+import com.guadou.lib_baselib.base.vm.EmptyViewModel
+import com.guadou.lib_baselib.utils.CommUtils
+import com.hongyegroup.cpt_newsfeed.R
+
+/**
+ * 个人的主页 实际上为空容器
+ * 内部加载Fragment实现
+ */
+class NewsFeedProfileActivity : BaseVMActivity<EmptyViewModel>() {
+
+    private var mMemberId: String? = null
+    private var isSelf: Boolean = false
+    private lateinit var mNewsFeedProfileFragment: NewsFeedProfileFragment
+
+    companion object {
+        fun startInstance(memberId: String, isSelf: Boolean = false) {
+            val context = CommUtils.getContext()
+            val intent = Intent(context, NewsFeedProfileActivity::class.java)
+            intent.putExtra("memberId", memberId)
+            intent.putExtra("isSelf", isSelf)
+            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+            context.startActivity(intent)
+        }
+    }
+
+    override fun getDataFromIntent(intent: Intent) {
+        mMemberId = intent.getStringExtra("memberId")
+        isSelf = intent.getBooleanExtra("isSelf", false)
+    }
+
+    override fun getLayoutIdRes(): Int = R.layout.activity_newsfeed_profile
+
+    override fun init(savedInstanceState: Bundle?) {
+        mNewsFeedProfileFragment = NewsFeedProfileFragment(mMemberId,isSelf)
+
+        supportFragmentManager.beginTransaction()
+            .add(R.id.fragment_container, mNewsFeedProfileFragment)
+            .commitAllowingStateLoss()
+    }
+
+    override fun startObserve() {
+
+    }
+
+}

+ 50 - 0
cpt_newsfeed/src/main/java/com/hongyegroup/cpt_newsfeed/ui/NewsFeedProfileFragment.kt

@@ -0,0 +1,50 @@
+package com.hongyegroup.cpt_newsfeed.ui
+
+import android.os.Bundle
+import com.guadou.cs_cptservices.base.fragment.YYBaseVDBLazyLoadingFragment
+import com.guadou.lib_baselib.bean.DataBindingConfig
+import com.guadou.lib_baselib.utils.KeyboardUtils
+import com.hongyegroup.cpt_newsfeed.BR
+import com.hongyegroup.cpt_newsfeed.R
+import com.hongyegroup.cpt_newsfeed.databinding.FragmentNewsfeedProfileBinding
+import com.hongyegroup.cpt_newsfeed.mvvm.NewsFeedProfileViewModel
+
+/**
+ * 我的发布 个人主页 同一个页面
+ */
+class NewsFeedProfileFragment(
+    private val mMemberId: String?, private val isSelf: Boolean
+) : YYBaseVDBLazyLoadingFragment<NewsFeedProfileViewModel, FragmentNewsfeedProfileBinding>() {
+
+    override fun getDataBindingConfig(): DataBindingConfig {
+        return DataBindingConfig(R.layout.fragment_newsfeed_profile, BR.viewModel, mViewModel)
+            .addBindingParams(BR.click, ClickProxy())
+    }
+
+    override fun init(savedInstanceState: Bundle?) {
+    }
+
+    override fun onLazyInitData() {
+
+    }
+
+    override fun startObserve() {
+
+    }
+
+    fun scrollTopRefresh() {
+
+    }
+
+    /**
+     * DataBinding事件处理
+     */
+    inner class ClickProxy {
+
+        fun selectCountryCode() {
+            KeyboardUtils.hideSoftInput(mActivity)
+        }
+
+    }
+
+}

+ 39 - 0
cpt_newsfeed/src/main/java/com/hongyegroup/cpt_newsfeed/widget/expand/ButtonSpan.java

@@ -0,0 +1,39 @@
+package com.hongyegroup.cpt_newsfeed.widget.expand;
+
+import android.content.Context;
+import android.text.TextPaint;
+import android.text.style.ClickableSpan;
+import android.view.View;
+
+import com.hongyegroup.cpt_newsfeed.R;
+
+
+public class ButtonSpan extends ClickableSpan {
+
+    View.OnClickListener onClickListener;
+    private Context context;
+    private int colorId;
+
+    public ButtonSpan(Context context, View.OnClickListener onClickListener) {
+        this(context, onClickListener, R.color.app_blue);
+    }
+
+    public ButtonSpan(Context context, View.OnClickListener onClickListener, int colorId) {
+        this.onClickListener = onClickListener;
+        this.context = context;
+        this.colorId = colorId;
+    }
+
+    @Override
+    public void updateDrawState(TextPaint ds) {
+        ds.setColor(context.getResources().getColor(colorId));
+        ds.setUnderlineText(false);
+    }
+
+    @Override
+    public void onClick(View widget) {
+        if (onClickListener != null) {
+            onClickListener.onClick(widget);
+        }
+    }
+}

+ 279 - 0
cpt_newsfeed/src/main/java/com/hongyegroup/cpt_newsfeed/widget/expand/ExpandTextView.java

@@ -0,0 +1,279 @@
+package com.hongyegroup.cpt_newsfeed.widget.expand;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.text.Layout;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.SpannableStringBuilder;
+import android.text.Spanned;
+import android.text.StaticLayout;
+import android.text.method.LinkMovementMethod;
+import android.text.style.URLSpan;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+
+import androidx.appcompat.widget.AppCompatTextView;
+
+import com.guadou.lib_baselib.font_text_view.TypefaceUtil;
+import com.guadou.lib_baselib.utils.CommUtils;
+import com.hongyegroup.cpt_newsfeed.R;
+
+
+/**
+ * 折叠展开的TextView
+ */
+public class ExpandTextView extends AppCompatTextView {
+
+    private CharSequence originText;// 原始内容文本
+    private int initWidth = 0;// TextView可展示宽度
+    private int mMaxLines = 3;// TextView最大行数
+    private SpannableString SPAN_CLOSE = null;// 收起的文案(颜色处理)
+    private SpannableString SPAN_EXPAND = null;// 展开的文案(颜色处理)
+    private String TEXT_EXPAND = "  [更多]";
+    private String TEXT_CLOSE = "  [收起]";
+    private boolean isLongClick = false;
+
+    public ExpandTextView(Context context) {
+        super(context);
+        initCloseEnd();
+    }
+
+    public ExpandTextView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        initCloseEnd();
+    }
+
+    public ExpandTextView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        initCloseEnd();
+    }
+
+    /**
+     * 设置TextView可显示的最大行数
+     *
+     * @param maxLines 最大行数
+     */
+    @Override
+    public void setMaxLines(int maxLines) {
+        this.mMaxLines = maxLines;
+        super.setMaxLines(maxLines);
+    }
+
+    /**
+     * 初始化TextView的可展示宽度
+     *
+     * @param width
+     */
+    public void initWidth(int width) {
+        initWidth = width;
+    }
+
+    /**
+     * 收起的文案(颜色处理)初始化
+     */
+    private void initCloseEnd() {
+        //设置展开的文本
+        SPAN_CLOSE = new SpannableString(TEXT_EXPAND);
+
+        ButtonSpan span = new ButtonSpan(getContext(), new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                ExpandTextView.super.setMaxLines(Integer.MAX_VALUE);
+                setExpandText(originText);
+                if (mCallback != null) mCallback.isExpand(1);
+            }
+        }, R.color.app_blue);
+
+        SPAN_CLOSE.setSpan(span, 0, TEXT_EXPAND.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
+        SPAN_CLOSE.setSpan(new MyTypefaceSpan(TypefaceUtil.getMedium()), 0, TEXT_EXPAND.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
+    }
+
+    /**
+     * 展开的文案(颜色处理)初始化
+     */
+    private void initExpandEnd() {
+        //设置关闭的文本
+        SPAN_EXPAND = new SpannableString(TEXT_CLOSE);
+        ButtonSpan span = new ButtonSpan(getContext(), new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                ExpandTextView.super.setMaxLines(mMaxLines);
+                setCloseText(originText);
+                if (mCallback != null) mCallback.isExpand(0);
+            }
+        }, R.color.app_blue);
+
+        SPAN_EXPAND.setSpan(span, 0, TEXT_CLOSE.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
+        SPAN_EXPAND.setSpan(new MyTypefaceSpan(TypefaceUtil.getMedium()), 0, TEXT_CLOSE.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
+    }
+
+    /**
+     * 默认设置文本方法
+     */
+    public void setCloseText(CharSequence text) {
+
+        if (SPAN_CLOSE == null) {
+            initCloseEnd();
+        }
+        boolean appendShowAll = false;// true 不需要展开收起功能, false 需要展开收起功能
+        originText = text;
+
+        // SDK >= 16 可以直接从xml属性获取最大行数
+        int maxLines = 0;
+        maxLines = getMaxLines();
+//        StringBuilder workingTextBuilder = new StringBuilder(originText);
+        CharSequence workingText = originText;
+        if (maxLines != -1) {
+            Layout layout = createWorkingLayout(workingText);
+            if (layout.getLineCount() > maxLines) {
+                //获取一行显示字符个数,然后截取字符串数
+                workingText = originText.subSequence(0, layout.getLineEnd(maxLines - 1));// 收起状态原始文本截取展示的部分
+
+                String showText = originText.subSequence(0, layout.getLineEnd(maxLines - 1)) + "..." + SPAN_CLOSE;
+                Layout layout2 = createWorkingLayout(showText);
+
+                // 对workingText进行-1截取,直到展示行数==最大行数,并且添加 SPAN_CLOSE 后刚好占满最后一行
+                while (layout2.getLineCount() > maxLines) {
+                    int lastSpace = workingText.length() - 1;
+                    if (lastSpace == -1) {
+                        break;
+                    }
+                    workingText = workingText.subSequence(0, lastSpace);
+                    layout2 = createWorkingLayout(workingText + "..." + SPAN_CLOSE);
+                }
+
+                appendShowAll = true;
+
+            }
+        }
+
+        setText(workingText);
+
+        if (appendShowAll) {
+            // 必须使用append,不能在上面使用+连接,否则spannable会无效
+            append("...");
+            append(SPAN_CLOSE);
+        }
+
+        setMovementMethod(LinkMovementMethod.getInstance());
+
+        replaceUrlSpan();
+    }
+
+    /**
+     * 展开
+     */
+    private void setExpandText(CharSequence text) {
+        if (SPAN_EXPAND == null) {
+            initExpandEnd();
+        }
+        Layout layout1 = createWorkingLayout(text);
+        Layout layout2 = createWorkingLayout(text + TEXT_CLOSE);
+        // 展示全部原始内容时 如果 TEXT_CLOSE 需要换行才能显示完整,则直接将TEXT_CLOSE展示在下一行
+        if (layout2.getLineCount() > layout1.getLineCount()) {
+            setText(originText + "\n");
+        } else {
+            setText(originText);
+        }
+        append(SPAN_EXPAND);
+
+        setMovementMethod(LinkMovementMethod.getInstance());
+
+        replaceUrlSpan();
+    }
+
+    /**
+     * 填充文本之后尝试替换URLSpan
+     */
+    private void replaceUrlSpan() {
+        CharSequence text = getText();
+        if (text instanceof Spannable) {
+            int end = text.length();
+            Spannable sp = (Spannable) text;
+
+            URLSpan[] urls = sp.getSpans(0, end, URLSpan.class);
+            SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(text);
+
+            if (urls.length > 0) {
+                for (URLSpan urlSpan : urls) {
+                    //拦截点击,替换Span
+                    InterceptUrlSpan interceptUrlSpan = new InterceptUrlSpan(urlSpan.getURL());
+                    spannableStringBuilder.setSpan(interceptUrlSpan, sp.getSpanStart(urlSpan), sp.getSpanEnd(urlSpan), Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
+                }
+
+                //替换之后重新设置进去
+                setText(spannableStringBuilder);
+            }
+
+        }
+    }
+
+    /**
+     * 展示全部的文本
+     */
+    public void showAllText() {
+        ExpandTextView.super.setMaxLines(Integer.MAX_VALUE);
+        setExpandText(originText);
+    }
+
+    /**
+     * 展示收缩文本
+     */
+    public void showExpandText() {
+        ExpandTextView.super.setMaxLines(mMaxLines);
+        setCloseText(originText);
+    }
+
+    //返回textview的显示区域的layout,该textview的layout并不会显示出来,只是用其宽度来比较要显示的文字是否过长
+    private Layout createWorkingLayout(CharSequence workingText) {
+        return new StaticLayout(workingText, getPaint(), initWidth - getPaddingLeft() - getPaddingRight(),
+                Layout.Alignment.ALIGN_NORMAL, getLineSpacingMultiplier(), getLineSpacingExtra(), false);
+    }
+
+
+    private OnExpandCallback mCallback;
+
+    public void setOnExpandCallback(OnExpandCallback callback) {
+        mCallback = callback;
+    }
+
+    /**
+     * 回调,展开和收缩的状态回调
+     */
+    public interface OnExpandCallback {
+        void isExpand(int status); //0为收缩  1是展开
+    }
+
+
+    @SuppressLint("ClickableViewAccessibility")
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+
+        if (isLongClick) {
+            setBackgroundColor(CommUtils.getColor(R.color.gray));
+        } else {
+            setBackgroundColor(CommUtils.getColor(R.color.white));
+        }
+
+        if (event.getAction() == MotionEvent.ACTION_DOWN) {
+
+        } else if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) {
+
+            if (isLongClick) {
+                setBackgroundColor(CommUtils.getColor(R.color.gray));
+            } else {
+                setBackgroundColor(CommUtils.getColor(R.color.white));
+            }
+            isLongClick = false;
+        }
+
+        return super.onTouchEvent(event);
+    }
+
+
+    public void setLongClick(boolean longClick) {
+        isLongClick = longClick;
+    }
+}

+ 25 - 0
cpt_newsfeed/src/main/java/com/hongyegroup/cpt_newsfeed/widget/expand/InterceptUrlSpan.kt

@@ -0,0 +1,25 @@
+package com.hongyegroup.cpt_newsfeed.widget.expand
+
+import android.text.style.ClickableSpan
+import android.view.View
+import com.guadou.cs_cptservices.ui.GlobalWebActivity
+import com.guadou.lib_baselib.utils.log.YYLogUtils
+
+
+class InterceptUrlSpan(private val url: String) : ClickableSpan() {
+
+    var _viewClickFlag = false
+    val _clickRunnable = Runnable { _viewClickFlag = false }
+
+    override fun onClick(widget: View) {
+
+        if (!_viewClickFlag) {
+            _viewClickFlag = true
+            YYLogUtils.w("自定义的点击$url")
+            GlobalWebActivity.startInstance("", url)
+        }
+        widget.removeCallbacks(_clickRunnable)
+        widget.postDelayed(_clickRunnable, 350)
+
+    }
+}

+ 43 - 0
cpt_newsfeed/src/main/java/com/hongyegroup/cpt_newsfeed/widget/expand/MyTypefaceSpan.java

@@ -0,0 +1,43 @@
+package com.hongyegroup.cpt_newsfeed.widget.expand;
+
+import android.graphics.Paint;
+import android.graphics.Typeface;
+import android.text.TextPaint;
+import android.text.style.MetricAffectingSpan;
+
+/**
+ * 系统原生的TypefaceSpan只能使用原生的默认字体
+ * 如果使用自定义的字体,通过这个来实现
+ */
+public class MyTypefaceSpan extends MetricAffectingSpan {
+
+    private final Typeface typeface;
+
+    public MyTypefaceSpan(final Typeface typeface) {
+        this.typeface = typeface;
+    }
+
+    @Override
+    public void updateDrawState(final TextPaint drawState) {
+        apply(drawState);
+    }
+
+    @Override
+    public void updateMeasureState(final TextPaint paint) {
+        apply(paint);
+    }
+
+    private void apply(final Paint paint) {
+        final Typeface oldTypeface = paint.getTypeface();
+        final int oldStyle = oldTypeface != null ? oldTypeface.getStyle() : 0;
+        int fakeStyle = oldStyle & ~typeface.getStyle();
+        if ((fakeStyle & Typeface.BOLD) != 0) {
+            paint.setFakeBoldText(true);
+        }
+        if ((fakeStyle & Typeface.ITALIC) != 0) {
+            paint.setTextSkewX(-0.25f);
+        }
+        paint.setTypeface(typeface);
+    }
+
+}

二进制
cpt_newsfeed/src/main/res/drawable-xxhdpi/news_feed_camera.webp


二进制
cpt_newsfeed/src/main/res/drawable-xxhdpi/news_feed_comments_un.webp


二进制
cpt_newsfeed/src/main/res/drawable-xxhdpi/news_feed_likes_un.webp


二进制
cpt_newsfeed/src/main/res/drawable-xxhdpi/news_feed_share_un.webp


二进制
cpt_newsfeed/src/main/res/drawable-xxhdpi/newsfeed_profile_news_addfollow_red.webp


二进制
cpt_newsfeed/src/main/res/drawable-xxhdpi/newsfeed_profile_news_followed.webp


+ 5 - 0
cpt_newsfeed/src/main/res/drawable/shape_news_feed_follow_red_round_18.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="@color/profile_red" />
+    <corners android:radius="@dimen/d_18dp" />
+</shape>

+ 36 - 0
cpt_newsfeed/src/main/res/layout/activity_newsfeed_detail.xml

@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:binding="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    tools:ignore="RtlHardcoded">
+
+    <data>
+
+        <variable
+            name="viewModel"
+            type="com.hongyegroup.cpt_newsfeed.mvvm.NewsFeedDetailViewModel" />
+
+        <variable
+            name="click"
+            type="com.hongyegroup.cpt_newsfeed.ui.NewsFeedDetailActivity.ClickProxy" />
+
+    </data>
+
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="@color/white"
+        android:orientation="vertical">
+
+
+        <TextView
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:gravity="center"
+            android:text="NewsFeed" />
+
+    </LinearLayout>
+
+</layout>

+ 36 - 0
cpt_newsfeed/src/main/res/layout/activity_newsfeed_follows.xml

@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:binding="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    tools:ignore="RtlHardcoded">
+
+    <data>
+
+        <variable
+            name="viewModel"
+            type="com.hongyegroup.cpt_newsfeed.mvvm.NewsFeedFollowsViewModel" />
+
+        <variable
+            name="click"
+            type="com.hongyegroup.cpt_newsfeed.ui.NewsFeedFollowsActivity.ClickProxy" />
+
+    </data>
+
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="@color/white"
+        android:orientation="vertical">
+
+
+        <TextView
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:gravity="center"
+            android:text="NewsFeed" />
+
+    </LinearLayout>
+
+</layout>

+ 37 - 0
cpt_newsfeed/src/main/res/layout/activity_newsfeed_post.xml

@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:binding="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    tools:ignore="RtlHardcoded">
+
+    <data>
+
+        <variable
+            name="viewModel"
+            type="com.hongyegroup.cpt_newsfeed.mvvm.NewsFeedPostViewModel" />
+
+        <variable
+            name="click"
+            type="com.hongyegroup.cpt_newsfeed.ui.NewsFeedPostActivity.ClickProxy" />
+
+    </data>
+
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="@color/white"
+        android:orientation="vertical">
+
+
+        <TextView
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:gravity="center"
+            android:text="NewsFeed"
+            binding:clicks="@{click.selectCountryCode}" />
+
+    </LinearLayout>
+
+</layout>

+ 9 - 0
cpt_newsfeed/src/main/res/layout/activity_newsfeed_profile.xml

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    tools:viewBindingIgnore="true"
+    android:id="@+id/fragment_container"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+</FrameLayout>

+ 34 - 0
cpt_newsfeed/src/main/res/layout/fragment_newsfeed_fans.xml

@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:binding="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    tools:ignore="RtlHardcoded">
+
+    <data>
+
+        <variable
+            name="viewModel"
+            type="com.hongyegroup.cpt_newsfeed.mvvm.NewsFeedFansViewModel" />
+
+        <variable
+            name="click"
+            type="com.hongyegroup.cpt_newsfeed.ui.NewsFeedFansFragment.ClickProxy" />
+
+        <import type="android.text.TextUtils" />
+
+    </data>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="#3684F9"
+        android:orientation="vertical">
+
+        <com.guadou.lib_baselib.view.titlebar.StatusbarGrayView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" />
+
+    </LinearLayout>
+
+</layout>

+ 34 - 0
cpt_newsfeed/src/main/res/layout/fragment_newsfeed_follow.xml

@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:binding="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    tools:ignore="RtlHardcoded">
+
+    <data>
+
+        <variable
+            name="viewModel"
+            type="com.hongyegroup.cpt_newsfeed.mvvm.NewsFeedFollowViewModel" />
+
+        <variable
+            name="click"
+            type="com.hongyegroup.cpt_newsfeed.ui.NewsFeedFollowFragment.ClickProxy" />
+
+        <import type="android.text.TextUtils" />
+
+    </data>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="#3684F9"
+        android:orientation="vertical">
+
+        <com.guadou.lib_baselib.view.titlebar.StatusbarGrayView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" />
+
+    </LinearLayout>
+
+</layout>

+ 37 - 0
cpt_newsfeed/src/main/res/layout/fragment_newsfeed_following.xml

@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:binding="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    tools:ignore="RtlHardcoded">
+
+    <data>
+
+    </data>
+
+    <com.scwang.smart.refresh.layout.SmartRefreshLayout
+        android:id="@+id/refresh_layout"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:focusable="true"
+        android:focusableInTouchMode="true"
+        app:srlEnablePreviewInEditMode="false"
+        app:srlPrimaryColor="@color/white">
+
+        <com.scwang.smart.refresh.header.ClassicsHeader
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" />
+
+        <androidx.recyclerview.widget.RecyclerView
+            android:id="@+id/recycler_view"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:overScrollMode="never"
+            android:scrollbars="none">
+
+        </androidx.recyclerview.widget.RecyclerView>
+
+
+    </com.scwang.smart.refresh.layout.SmartRefreshLayout>
+
+</layout>

+ 185 - 0
cpt_newsfeed/src/main/res/layout/fragment_newsfeed_main.xml

@@ -0,0 +1,185 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:binding="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    tools:ignore="RtlHardcoded">
+
+    <data>
+
+        <variable
+            name="viewModel"
+            type="com.hongyegroup.cpt_newsfeed.mvvm.NewsFeedMainViewModel" />
+
+        <variable
+            name="click"
+            type="com.hongyegroup.cpt_newsfeed.ui.NewsFeedMainFragment.ClickProxy" />
+
+    </data>
+
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="@color/white"
+        android:orientation="vertical">
+
+        <com.guadou.lib_baselib.view.titlebar.StatusbarGrayView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" />
+
+        <androidx.constraintlayout.widget.ConstraintLayout
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/d_46dp"
+            android:paddingLeft="@dimen/d_40dp"
+            android:paddingRight="@dimen/d_40dp">
+
+            <com.guadou.lib_baselib.font_text_view.TextViewBold
+                android:id="@+id/text_moments"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:onClick="@{()->click.switchMoments()}"
+                android:text="朋友圈"
+                android:textColor="@color/gray_88"
+                android:textSize="@dimen/d_16sp"
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintLeft_toLeftOf="parent"
+                app:layout_constraintRight_toLeftOf="@id/text_following"
+                app:layout_constraintTop_toTopOf="parent" />
+
+            <View
+                android:id="@+id/view_follow_line"
+                android:layout_width="0dp"
+                android:layout_height="2.5dp"
+                android:background="@drawable/shape_blue_round3"
+                android:visibility="gone"
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintLeft_toLeftOf="@id/text_moments"
+                app:layout_constraintRight_toRightOf="@id/text_moments" />
+
+            <com.guadou.lib_baselib.font_text_view.TextViewBold
+                android:id="@+id/text_following"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:onClick="@{()->click.switchFollowing()}"
+                android:text="已关注"
+                android:textColor="@color/app_blue"
+                android:textSize="@dimen/d_16sp"
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintLeft_toRightOf="@id/text_moments"
+                app:layout_constraintRight_toLeftOf="@id/text_pulished"
+                app:layout_constraintTop_toTopOf="parent" />
+
+            <!--  已关注的数量    -->
+            <com.guadou.lib_baselib.font_text_view.TextViewBold
+                android:layout_width="18dp"
+                android:layout_height="11.5dp"
+                android:background="@drawable/unread_red_bg"
+                android:gravity="center"
+                android:text="9"
+                android:textColor="@color/white"
+                android:textSize="@dimen/d_9sp"
+                app:layout_constraintBottom_toTopOf="@id/text_following"
+                app:layout_constraintLeft_toRightOf="@id/text_following"
+                app:layout_constraintRight_toRightOf="@id/text_following"
+                app:layout_constraintTop_toTopOf="@id/text_following" />
+
+            <View
+                android:id="@+id/view_for_you_line"
+                android:layout_width="0dp"
+                android:layout_height="2.5dp"
+                android:background="@drawable/shape_blue_round3"
+                android:visibility="visible"
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintLeft_toLeftOf="@id/text_following"
+                app:layout_constraintRight_toRightOf="@id/text_following" />
+
+            <com.guadou.lib_baselib.font_text_view.TextViewBold
+                android:id="@+id/text_pulished"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:onClick="@{()->click.switchPulished()}"
+                android:text="我的发布"
+                android:textColor="@color/gray_88"
+                android:textSize="@dimen/d_16sp"
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintLeft_toRightOf="@id/text_following"
+                app:layout_constraintRight_toRightOf="parent"
+                app:layout_constraintTop_toTopOf="parent" />
+
+            <View
+                android:id="@+id/view_published"
+                android:layout_width="0dp"
+                android:layout_height="2.5dp"
+                android:background="@drawable/shape_blue_round3"
+                android:visibility="gone"
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintLeft_toLeftOf="@id/text_pulished"
+                app:layout_constraintRight_toRightOf="@id/text_pulished" />
+
+        </androidx.constraintlayout.widget.ConstraintLayout>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="0.7dp"
+            android:background="@color/divider_color" />
+
+        <androidx.coordinatorlayout.widget.CoordinatorLayout
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:background="@color/page_bg">
+
+            <com.google.android.material.appbar.AppBarLayout
+                android:id="@+id/app_bar_layout"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:background="@color/white"
+                app:elevation="0dp">
+
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="68dp"
+                    android:gravity="center_vertical"
+                    android:orientation="horizontal"
+                    app:layout_scrollFlags="scroll|snap|enterAlways"
+                    binding:clicks="@{click.gotoPostPage}">
+
+                    <com.guadou.lib_baselib.view.CircleImageView
+                        android:id="@+id/iv_feed_avatar"
+                        android:layout_width="@dimen/d_45dp"
+                        android:layout_height="@dimen/d_45dp"
+                        android:layout_marginLeft="@dimen/d_15dp"
+                        android:scaleType="centerCrop"
+                        android:src="@drawable/im_default_head" />
+
+                    <com.guadou.lib_baselib.font_text_view.TextViewBold
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_marginLeft="@dimen/d_19dp"
+                        android:layout_weight="1"
+                        android:text="在想什么有趣的呢?"
+                        android:textColor="@color/notify_dark_blue"
+                        android:textSize="@dimen/d_16sp" />
+
+                    <ImageView
+                        android:id="@+id/iv_feed_take_photo"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:layout_marginRight="@dimen/d_16dp"
+                        android:src="@drawable/news_feed_camera" />
+
+                </LinearLayout>
+
+            </com.google.android.material.appbar.AppBarLayout>
+
+            <androidx.viewpager.widget.ViewPager
+                android:id="@+id/view_pager"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                app:layout_behavior="@string/appbar_scrolling_view_behavior" />
+
+        </androidx.coordinatorlayout.widget.CoordinatorLayout>
+
+    </LinearLayout>
+
+</layout>

+ 34 - 0
cpt_newsfeed/src/main/res/layout/fragment_newsfeed_profile.xml

@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:binding="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    tools:ignore="RtlHardcoded">
+
+    <data>
+
+        <variable
+            name="viewModel"
+            type="com.hongyegroup.cpt_newsfeed.mvvm.NewsFeedProfileViewModel" />
+
+        <variable
+            name="click"
+            type="com.hongyegroup.cpt_newsfeed.ui.NewsFeedProfileFragment.ClickProxy" />
+
+        <import type="android.text.TextUtils" />
+
+    </data>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="#3684F9"
+        android:orientation="vertical">
+
+        <com.guadou.lib_baselib.view.titlebar.StatusbarGrayView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" />
+
+    </LinearLayout>
+
+</layout>

+ 239 - 0
cpt_newsfeed/src/main/res/layout/item_news_feed_news.xml

@@ -0,0 +1,239 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/ll_news_feed_root"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="@color/white"
+    android:orientation="vertical"
+    tools:viewBindingIgnore="true">
+
+    <View
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/d_9dp"
+        android:background="@color/page_bg" />
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:gravity="center_vertical"
+        android:orientation="horizontal"
+        android:layout_marginTop="@dimen/d_10dp"
+        android:paddingLeft="@dimen/d_15dp"
+        android:paddingTop="@dimen/d_15dp"
+        android:paddingRight="@dimen/d_15dp"
+        android:paddingBottom="@dimen/d_8dp">
+
+        <com.guadou.lib_baselib.view.CircleImageView
+            android:id="@+id/iv_feed_news_avatar"
+            android:layout_width="@dimen/d_45dp"
+            android:layout_height="@dimen/d_45dp"
+            android:background="@drawable/im_default_head"
+            app:layout_constraintLeft_toLeftOf="parent" />
+
+        <LinearLayout
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:orientation="vertical">
+
+            <com.guadou.lib_baselib.font_text_view.TextViewBold
+                android:id="@+id/tv_feed_news_name"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="@dimen/d_12dp"
+                android:ellipsize="end"
+                android:singleLine="true"
+                android:text="丽莎"
+                android:textColor="@color/notify_dark_blue"
+                android:textSize="18dp" />
+
+            <com.guadou.lib_baselib.font_text_view.TextViewMedium
+                android:id="@+id/tv_feed_news_time"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="@dimen/d_12dp"
+                android:text="2022.02.08 18:01"
+                android:textColor="@color/gray_76"
+                android:textSize="@dimen/d_14sp" />
+
+        </LinearLayout>
+
+        <LinearLayout
+            android:id="@+id/ll_follow_box"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical"
+            android:background="@drawable/shape_news_feed_follow_red_round_18"
+            android:gravity="center"
+            android:orientation="horizontal"
+            android:paddingLeft="@dimen/d_11dp"
+            android:paddingTop="@dimen/d_5dp"
+            android:paddingRight="@dimen/d_11dp"
+            android:paddingBottom="@dimen/d_5dp">
+
+            <ImageView
+                android:id="@+id/iv_follow_icon"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="@dimen/d_0.5dp"
+                android:src="@drawable/newsfeed_profile_news_addfollow_red" />
+
+            <com.guadou.lib_baselib.font_text_view.TextViewMedium
+                android:id="@+id/tv_follow_text"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="@dimen/d_3dp"
+                android:text="Follow"
+                android:textColor="@color/white"
+                android:textSize="@dimen/d_14sp" />
+
+        </LinearLayout>
+
+    </LinearLayout>
+
+    <com.guadou.lib_baselib.font_text_view.TextViewMedium
+        android:id="@+id/tv_post_by_group"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="@dimen/d_20dp"
+        android:layout_marginRight="@dimen/d_20dp"
+        android:layout_marginBottom="@dimen/d_12dp"
+        android:textColor="@color/black"
+        android:textSize="@dimen/d_14sp"
+        tools:text="Share on Group Let’s Party Together." />
+
+    <com.hongyegroup.cpt_newsfeed.widget.expand.ExpandTextView
+        android:id="@+id/tv_feed_news_content"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="@dimen/d_20dp"
+        android:layout_marginRight="@dimen/d_20dp"
+        android:autoLink="web"
+        android:text="i wonder if you have any ideas about app design,Do you like the latest design or tetro design?"
+        android:textColor="@color/black"
+        android:textColorLink="@color/notify_dark_blue"
+        android:textIsSelectable="true"
+        android:textSize="@dimen/d_14sp" />
+
+
+    <com.guadou.ninegrid.nine_grid_layout.SimpleImageViewNineGrid
+        android:id="@+id/nine_grid_view"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="@dimen/d_20dp"
+        android:layout_marginTop="@dimen/d_10dp"
+        android:layout_marginRight="@dimen/d_20dp"
+        app:spacing="@dimen/d_13dp" />
+
+
+    <View
+        android:id="@+id/view_news_feed_bottom_line1"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/d_0.5dp"
+        android:layout_marginTop="@dimen/d_10dp"
+        android:background="@color/divider_color_ee" />
+
+    <LinearLayout
+        android:id="@+id/ll_news_feed_bottom_options"
+        android:layout_width="match_parent"
+        android:layout_height="40dp"
+        android:orientation="horizontal">
+
+        <LinearLayout
+            android:id="@+id/ll_feed_news_like_root"
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:gravity="center">
+
+            <ImageView
+                android:id="@+id/iv_tv_feed_news_like_icon"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:src="@drawable/news_feed_likes_un" />
+
+            <com.guadou.lib_baselib.font_text_view.TextViewMedium
+                android:id="@+id/tv_feed_news_like_num"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="@dimen/d_10dp"
+                android:text="赞(1560)"
+                android:textColor="@color/gray_76"
+                android:textSize="@dimen/d_14sp" />
+
+        </LinearLayout>
+
+        <View
+            android:layout_width="@dimen/d_0.5dp"
+            android:layout_height="match_parent"
+            android:layout_marginTop="@dimen/d_8dp"
+            android:layout_marginBottom="@dimen/d_8dp"
+            android:background="@color/divider_color_ee" />
+
+        <LinearLayout
+            android:id="@+id/ll_feed_news_comment_root"
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:gravity="center">
+
+            <ImageView
+                android:id="@+id/iv_tv_feed_news_comment_icon"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="@dimen/d_2dp"
+                android:src="@drawable/news_feed_comments_un" />
+
+            <com.guadou.lib_baselib.font_text_view.TextViewMedium
+                android:id="@+id/tv_feed_news_comment_num"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="@dimen/d_10dp"
+                android:text="评论(160)"
+                android:textColor="@color/gray_76"
+                android:textSize="@dimen/d_14sp" />
+
+        </LinearLayout>
+
+        <View
+            android:layout_width="@dimen/d_0.5dp"
+            android:layout_height="match_parent"
+            android:layout_marginTop="@dimen/d_8dp"
+            android:layout_marginBottom="@dimen/d_8dp"
+            android:background="@color/divider_color_ee" />
+
+        <LinearLayout
+            android:id="@+id/ll_feed_news_share_root"
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:gravity="center">
+
+            <ImageView
+                android:id="@+id/iv_tv_feed_news_share_icon"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="@dimen/d_1dp"
+                android:src="@drawable/news_feed_share_un" />
+
+            <com.guadou.lib_baselib.font_text_view.TextViewMedium
+                android:id="@+id/tv_feed_news_share_num"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="@dimen/d_10dp"
+                android:text="分享"
+                android:textColor="@color/gray_76"
+                android:textSize="@dimen/d_14sp" />
+
+        </LinearLayout>
+
+    </LinearLayout>
+
+    <View
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/d_1dp"
+        android:background="@color/page_bg" />
+
+</LinearLayout>

+ 347 - 0
cpt_newsfeed/src/main/res/layout/layout_placeholder_newsfeed_hot.xml

@@ -0,0 +1,347 @@
+<?xml version="1.0" encoding="utf-8"?>
+<com.guadou.lib_baselib.view.shimmer.ShimmerLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/shimmer_layout"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:tag="shimmer_layout">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical">
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"
+            android:paddingLeft="@dimen/d_12dp"
+            android:paddingTop="@dimen/d_13dp"
+            android:paddingRight="@dimen/d_12dp">
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="horizontal">
+
+                <View
+                    android:layout_width="@dimen/d_45dp"
+                    android:layout_height="@dimen/d_45dp"
+                    android:background="@drawable/shimmer_circle_background" />
+
+                <LinearLayout
+                    android:layout_width="0dp"
+                    android:layout_height="wrap_content"
+                    android:layout_weight="1"
+                    android:orientation="vertical">
+
+                    <View
+                        android:layout_width="@dimen/d_100dp"
+                        android:layout_height="@dimen/d_25dp"
+                        android:layout_marginLeft="@dimen/d_10dp"
+                        android:background="@color/shimmer_background_color" />
+
+                    <View
+                        android:layout_width="@dimen/d_120dp"
+                        android:layout_height="@dimen/d_20dp"
+                        android:layout_marginLeft="@dimen/d_10dp"
+                        android:layout_marginTop="@dimen/d_5dp"
+                        android:background="@color/shimmer_background_color" />
+
+                </LinearLayout>
+
+            </LinearLayout>
+
+            <View
+                android:layout_width="match_parent"
+                android:layout_height="@dimen/d_60dp"
+                android:layout_marginTop="@dimen/d_10dp"
+                android:background="@color/shimmer_background_color" />
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="@dimen/d_10dp"
+                android:gravity="center"
+                android:orientation="horizontal">
+
+                <View
+                    android:layout_width="@dimen/d_80dp"
+                    android:layout_height="@dimen/d_80dp"
+                    android:layout_marginRight="@dimen/d_25dp"
+                    android:background="@drawable/shimmer_bg_rounded_corners5" />
+
+
+                <View
+                    android:layout_width="@dimen/d_80dp"
+                    android:layout_height="@dimen/d_80dp"
+                    android:layout_marginRight="@dimen/d_25dp"
+                    android:background="@drawable/shimmer_bg_rounded_corners5" />
+
+                <View
+                    android:layout_width="@dimen/d_80dp"
+                    android:layout_height="@dimen/d_80dp"
+                    android:layout_marginRight="@dimen/d_25dp"
+                    android:background="@drawable/shimmer_bg_rounded_corners5" />
+
+            </LinearLayout>
+
+        </LinearLayout>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/d_10dp"
+            android:layout_marginTop="@dimen/d_10dp"
+            android:background="@color/shimmer_background_color" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"
+            android:paddingLeft="@dimen/d_12dp"
+            android:paddingTop="@dimen/d_13dp"
+            android:paddingRight="@dimen/d_12dp">
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="horizontal">
+
+                <View
+                    android:layout_width="@dimen/d_45dp"
+                    android:layout_height="@dimen/d_45dp"
+                    android:background="@drawable/shimmer_circle_background" />
+
+                <LinearLayout
+                    android:layout_width="0dp"
+                    android:layout_height="wrap_content"
+                    android:layout_weight="1"
+                    android:orientation="vertical">
+
+                    <View
+                        android:layout_width="@dimen/d_100dp"
+                        android:layout_height="@dimen/d_25dp"
+                        android:layout_marginLeft="@dimen/d_10dp"
+                        android:background="@color/shimmer_background_color" />
+
+                    <View
+                        android:layout_width="@dimen/d_120dp"
+                        android:layout_height="@dimen/d_20dp"
+                        android:layout_marginLeft="@dimen/d_10dp"
+                        android:layout_marginTop="@dimen/d_5dp"
+                        android:background="@color/shimmer_background_color" />
+
+                </LinearLayout>
+
+            </LinearLayout>
+
+            <View
+                android:layout_width="match_parent"
+                android:layout_height="@dimen/d_60dp"
+                android:layout_marginTop="@dimen/d_10dp"
+                android:background="@color/shimmer_background_color" />
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="@dimen/d_10dp"
+                android:gravity="center"
+                android:orientation="horizontal">
+
+                <View
+                    android:layout_width="@dimen/d_80dp"
+                    android:layout_height="@dimen/d_80dp"
+                    android:layout_marginRight="@dimen/d_25dp"
+                    android:background="@drawable/shimmer_bg_rounded_corners5" />
+
+
+                <View
+                    android:layout_width="@dimen/d_80dp"
+                    android:layout_height="@dimen/d_80dp"
+                    android:layout_marginRight="@dimen/d_25dp"
+                    android:background="@drawable/shimmer_bg_rounded_corners5" />
+
+                <View
+                    android:layout_width="@dimen/d_80dp"
+                    android:layout_height="@dimen/d_80dp"
+                    android:layout_marginRight="@dimen/d_25dp"
+                    android:background="@drawable/shimmer_bg_rounded_corners5" />
+
+            </LinearLayout>
+
+        </LinearLayout>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/d_10dp"
+            android:layout_marginTop="@dimen/d_10dp"
+            android:background="@color/shimmer_background_color" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"
+            android:paddingLeft="@dimen/d_12dp"
+            android:paddingTop="@dimen/d_13dp"
+            android:paddingRight="@dimen/d_12dp">
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="horizontal">
+
+                <View
+                    android:layout_width="@dimen/d_45dp"
+                    android:layout_height="@dimen/d_45dp"
+                    android:background="@drawable/shimmer_circle_background" />
+
+                <LinearLayout
+                    android:layout_width="0dp"
+                    android:layout_height="wrap_content"
+                    android:layout_weight="1"
+                    android:orientation="vertical">
+
+                    <View
+                        android:layout_width="@dimen/d_100dp"
+                        android:layout_height="@dimen/d_25dp"
+                        android:layout_marginLeft="@dimen/d_10dp"
+                        android:background="@color/shimmer_background_color" />
+
+                    <View
+                        android:layout_width="@dimen/d_120dp"
+                        android:layout_height="@dimen/d_20dp"
+                        android:layout_marginLeft="@dimen/d_10dp"
+                        android:layout_marginTop="@dimen/d_5dp"
+                        android:background="@color/shimmer_background_color" />
+
+                </LinearLayout>
+
+            </LinearLayout>
+
+            <View
+                android:layout_width="match_parent"
+                android:layout_height="@dimen/d_60dp"
+                android:layout_marginTop="@dimen/d_10dp"
+                android:background="@color/shimmer_background_color" />
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="@dimen/d_10dp"
+                android:gravity="center"
+                android:orientation="horizontal">
+
+                <View
+                    android:layout_width="@dimen/d_80dp"
+                    android:layout_height="@dimen/d_80dp"
+                    android:layout_marginRight="@dimen/d_25dp"
+                    android:background="@drawable/shimmer_bg_rounded_corners5" />
+
+
+                <View
+                    android:layout_width="@dimen/d_80dp"
+                    android:layout_height="@dimen/d_80dp"
+                    android:layout_marginRight="@dimen/d_25dp"
+                    android:background="@drawable/shimmer_bg_rounded_corners5" />
+
+                <View
+                    android:layout_width="@dimen/d_80dp"
+                    android:layout_height="@dimen/d_80dp"
+                    android:layout_marginRight="@dimen/d_25dp"
+                    android:background="@drawable/shimmer_bg_rounded_corners5" />
+
+            </LinearLayout>
+
+        </LinearLayout>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/d_10dp"
+            android:layout_marginTop="@dimen/d_10dp"
+            android:background="@color/shimmer_background_color" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"
+            android:paddingLeft="@dimen/d_12dp"
+            android:paddingTop="@dimen/d_13dp"
+            android:paddingRight="@dimen/d_12dp">
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="horizontal">
+
+                <View
+                    android:layout_width="@dimen/d_45dp"
+                    android:layout_height="@dimen/d_45dp"
+                    android:background="@drawable/shimmer_circle_background" />
+
+                <LinearLayout
+                    android:layout_width="0dp"
+                    android:layout_height="wrap_content"
+                    android:layout_weight="1"
+                    android:orientation="vertical">
+
+                    <View
+                        android:layout_width="@dimen/d_100dp"
+                        android:layout_height="@dimen/d_25dp"
+                        android:layout_marginLeft="@dimen/d_10dp"
+                        android:background="@color/shimmer_background_color" />
+
+                    <View
+                        android:layout_width="@dimen/d_120dp"
+                        android:layout_height="@dimen/d_20dp"
+                        android:layout_marginLeft="@dimen/d_10dp"
+                        android:layout_marginTop="@dimen/d_5dp"
+                        android:background="@color/shimmer_background_color" />
+
+                </LinearLayout>
+
+            </LinearLayout>
+
+            <View
+                android:layout_width="match_parent"
+                android:layout_height="@dimen/d_60dp"
+                android:layout_marginTop="@dimen/d_10dp"
+                android:background="@color/shimmer_background_color" />
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="@dimen/d_10dp"
+                android:gravity="center"
+                android:orientation="horizontal">
+
+                <View
+                    android:layout_width="@dimen/d_80dp"
+                    android:layout_height="@dimen/d_80dp"
+                    android:layout_marginRight="@dimen/d_25dp"
+                    android:background="@drawable/shimmer_bg_rounded_corners5" />
+
+
+                <View
+                    android:layout_width="@dimen/d_80dp"
+                    android:layout_height="@dimen/d_80dp"
+                    android:layout_marginRight="@dimen/d_25dp"
+                    android:background="@drawable/shimmer_bg_rounded_corners5" />
+
+                <View
+                    android:layout_width="@dimen/d_80dp"
+                    android:layout_height="@dimen/d_80dp"
+                    android:layout_marginRight="@dimen/d_25dp"
+                    android:background="@drawable/shimmer_bg_rounded_corners5" />
+
+            </LinearLayout>
+
+        </LinearLayout>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/d_10dp"
+            android:layout_marginTop="@dimen/d_10dp"
+            android:background="@color/shimmer_background_color" />
+
+    </LinearLayout>
+
+</com.guadou.lib_baselib.view.shimmer.ShimmerLayout>

+ 17 - 0
cpt_newsfeed/src/test/java/com/hongyegroup/cpt_main/ExampleUnitTest.java

@@ -0,0 +1,17 @@
+package com.hongyegroup.cpt_main;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
+ */
+public class ExampleUnitTest {
+    @Test
+    public void addition_isCorrect() {
+        assertEquals(4, 2 + 2);
+    }
+}

+ 2 - 2
cpt_parttime/src/main/AndroidManifest.xml

@@ -4,11 +4,11 @@
 
     <application android:allowBackup="true">
 
-        <activity android:name=".ui.PartTimeJobDetailActivity" />
+        <activity android:name=".ui.activity.PartTimeJobDetailActivity" />
 
         <activity android:name=".ui.ChooseCityActivity" />
 
-        <activity android:name=".ui.PartJobAlbumActivity" />
+        <activity android:name=".ui.activity.PartJobAlbumActivity" />
 
     </application>
 

+ 2 - 2
cpt_parttime/src/main/java/com/hongyegroup/cpt_parttime/router/PartTimeComponentServiceImpl.kt

@@ -6,9 +6,9 @@ import com.alibaba.android.arouter.facade.annotation.Route
 import com.guadou.cs_router.ARouterPath
 import com.guadou.cs_router.parttime.IParttimeComponentServer
 import com.guadou.lib_baselib.utils.log.YYLogUtils
-import com.hongyegroup.cpt_parttime.ui.JobActivesFragment
+import com.hongyegroup.cpt_parttime.ui.main.JobActivesFragment
 import com.hongyegroup.cpt_parttime.ui.PartJobProfileFragment
-import com.hongyegroup.cpt_parttime.ui.PartTimeMainFragment
+import com.hongyegroup.cpt_parttime.ui.main.PartTimeMainFragment
 
 @Route(path = ARouterPath.PATH_SERVICE_PARTTIME, name = "PartTime模块路由服务")
 class PartTimeComponentServiceImpl : IParttimeComponentServer {

+ 1 - 1
cpt_parttime/src/main/java/com/hongyegroup/cpt_parttime/ui/PartJobAlbumActivity.kt

@@ -1,4 +1,4 @@
-package com.hongyegroup.cpt_parttime.ui
+package com.hongyegroup.cpt_parttime.ui.activity
 
 import android.content.Intent
 import android.os.Bundle

+ 2 - 1
cpt_parttime/src/main/java/com/hongyegroup/cpt_parttime/ui/PartTimeJobDetailActivity.kt

@@ -1,4 +1,4 @@
-package com.hongyegroup.cpt_parttime.ui
+package com.hongyegroup.cpt_parttime.ui.activity
 
 import android.content.Intent
 import android.os.Bundle
@@ -19,6 +19,7 @@ import com.hongyegroup.cpt_parttime.BR
 import com.hongyegroup.cpt_parttime.R
 import com.hongyegroup.cpt_parttime.databinding.ActivityParttimeJobDetailBinding
 import com.hongyegroup.cpt_parttime.mvvm.PartTimeJobDetailViewModel
+import com.hongyegroup.cpt_parttime.ui.fragment.*
 import dagger.hilt.android.AndroidEntryPoint
 
 @AndroidEntryPoint

+ 1 - 1
cpt_parttime/src/main/java/com/hongyegroup/cpt_parttime/ui/PartJobDetailFaqFragment.kt

@@ -1,4 +1,4 @@
-package com.hongyegroup.cpt_parttime.ui
+package com.hongyegroup.cpt_parttime.ui.fragment
 
 import android.os.Bundle
 import com.guadou.cs_cptservices.base.fragment.YYBaseVDBLazyLoadingFragment

+ 2 - 1
cpt_parttime/src/main/java/com/hongyegroup/cpt_parttime/ui/PartJobDetailFragment.kt

@@ -1,4 +1,4 @@
-package com.hongyegroup.cpt_parttime.ui
+package com.hongyegroup.cpt_parttime.ui.fragment
 
 import android.os.Bundle
 import com.guadou.cs_cptservices.base.fragment.YYBaseVDBFragment
@@ -10,6 +10,7 @@ import com.hongyegroup.cpt_parttime.BR
 import com.hongyegroup.cpt_parttime.R
 import com.hongyegroup.cpt_parttime.databinding.FragmentParttimeJobDetailBinding
 import com.hongyegroup.cpt_parttime.mvvm.PartJobDetailChildViewModel
+import com.hongyegroup.cpt_parttime.ui.activity.PartTimeJobDetailActivity
 
 /**
  * 工作详情 子页面 展示工作详细信息

+ 1 - 1
cpt_parttime/src/main/java/com/hongyegroup/cpt_parttime/ui/PartJobDetailGroomingFragment.kt

@@ -1,4 +1,4 @@
-package com.hongyegroup.cpt_parttime.ui
+package com.hongyegroup.cpt_parttime.ui.fragment
 
 import android.os.Bundle
 import com.guadou.cs_cptservices.base.fragment.YYBaseVDBLazyLoadingFragment

+ 1 - 1
cpt_parttime/src/main/java/com/hongyegroup/cpt_parttime/ui/PartJobDetailPaymentFragment.kt

@@ -1,4 +1,4 @@
-package com.hongyegroup.cpt_parttime.ui
+package com.hongyegroup.cpt_parttime.ui.fragment
 
 import android.os.Bundle
 import android.text.TextUtils

+ 1 - 1
cpt_parttime/src/main/java/com/hongyegroup/cpt_parttime/ui/PartJobDetailProcessFragment.kt

@@ -1,4 +1,4 @@
-package com.hongyegroup.cpt_parttime.ui
+package com.hongyegroup.cpt_parttime.ui.fragment
 
 import android.os.Bundle
 import com.guadou.cs_cptservices.base.fragment.YYBaseVDBLazyLoadingFragment

+ 1 - 1
cpt_parttime/src/main/java/com/hongyegroup/cpt_parttime/ui/PartJobDetailSlotsFragment.kt

@@ -1,4 +1,4 @@
-package com.hongyegroup.cpt_parttime.ui
+package com.hongyegroup.cpt_parttime.ui.fragment
 
 import android.os.Bundle
 import com.guadou.cs_cptservices.base.fragment.YYBaseVDBLazyLoadingFragment

+ 1 - 1
cpt_parttime/src/main/java/com/hongyegroup/cpt_parttime/ui/JobActivesFragment.kt

@@ -1,4 +1,4 @@
-package com.hongyegroup.cpt_parttime.ui
+package com.hongyegroup.cpt_parttime.ui.main
 
 import android.os.Bundle
 import android.view.View

+ 2 - 1
cpt_parttime/src/main/java/com/hongyegroup/cpt_parttime/ui/PartTimeMainFragment.kt

@@ -1,4 +1,4 @@
-package com.hongyegroup.cpt_parttime.ui
+package com.hongyegroup.cpt_parttime.ui.main
 
 import android.graphics.Color
 import android.os.Bundle
@@ -21,6 +21,7 @@ import com.hongyegroup.cpt_parttime.BR
 import com.hongyegroup.cpt_parttime.R
 import com.hongyegroup.cpt_parttime.databinding.FragmentParttimeMainBinding
 import com.hongyegroup.cpt_parttime.mvvm.PartTimeMainViewModel
+import com.hongyegroup.cpt_parttime.ui.activity.PartTimeJobDetailActivity
 import com.scwang.smart.refresh.layout.api.RefreshLayout
 import com.scwang.smart.refresh.layout.listener.OnRefreshListener
 import kotlinx.coroutines.flow.MutableStateFlow

+ 1 - 1
cpt_parttime/src/main/res/layout/activity_parttime_job_detail.xml

@@ -13,7 +13,7 @@
 
         <variable
             name="click"
-            type="com.hongyegroup.cpt_parttime.ui.PartTimeJobDetailActivity.ClickProxy" />
+            type="com.hongyegroup.cpt_parttime.ui.activity.PartTimeJobDetailActivity.ClickProxy" />
 
         <import type="android.text.TextUtils" />
 

+ 1 - 1
cpt_parttime/src/main/res/layout/fragment_job_actives.xml

@@ -13,7 +13,7 @@
 
         <variable
             name="click"
-            type="com.hongyegroup.cpt_parttime.ui.JobActivesFragment.ClickProxy" />
+            type="com.hongyegroup.cpt_parttime.ui.main.JobActivesFragment" />
 
     </data>
 

+ 1 - 1
cpt_parttime/src/main/res/layout/fragment_parttime_job_detail.xml

@@ -13,7 +13,7 @@
 
         <variable
             name="click"
-            type="com.hongyegroup.cpt_parttime.ui.PartJobDetailFragment.ClickProxy" />
+            type="com.hongyegroup.cpt_parttime.ui.fragment.PartJobDetailFragment.ClickProxy" />
 
         <import type="android.text.TextUtils" />
 

+ 1 - 1
cpt_parttime/src/main/res/layout/fragment_parttime_main.xml

@@ -13,7 +13,7 @@
 
         <variable
             name="click"
-            type="com.hongyegroup.cpt_parttime.ui.PartTimeMainFragment.ClickProxy" />
+            type="com.hongyegroup.cpt_parttime.ui.main.PartTimeMainFragment.ClickProxy" />
 
         <import type="android.text.TextUtils" />
 

+ 1 - 1
cpt_parttime/src/main/res/layout/include_parttime_job_detail_header_date_address.xml

@@ -13,7 +13,7 @@
 
         <variable
             name="click"
-            type="com.hongyegroup.cpt_parttime.ui.PartJobDetailFragment.ClickProxy" />
+            type="com.hongyegroup.cpt_parttime.ui.fragment.PartJobDetailFragment.ClickProxy" />
 
         <import type="android.text.TextUtils" />
 

+ 24 - 2
cs_baselib/src/main/java/com/guadou/lib_baselib/ext/ViewPagerExt.kt

@@ -6,8 +6,11 @@ import android.view.ViewGroup
 import androidx.fragment.app.Fragment
 import androidx.fragment.app.FragmentManager
 import androidx.fragment.app.FragmentStatePagerAdapter
+import androidx.lifecycle.Lifecycle
 import androidx.viewpager.widget.PagerAdapter
 import androidx.viewpager.widget.ViewPager
+import androidx.viewpager2.adapter.FragmentStateAdapter
+import androidx.viewpager2.widget.ViewPager2
 
 /**
 ViewPager相关
@@ -47,11 +50,12 @@ fun ViewPager.bind(count: Int, bindView: (container: ViewGroup, position: Int) -
 fun ViewPager.bindFragment(
     fm: FragmentManager,
     fragments: List<Fragment>,
-    pageTitles: List<String>? = null
+    pageTitles: List<String>? = null,
+    behavior: Int = 0
 ): ViewPager {
     offscreenPageLimit = fragments.size - 1
 
-    adapter = object : FragmentStatePagerAdapter(fm) {
+    adapter = object : FragmentStatePagerAdapter(fm, behavior) {
         override fun getItem(p: Int) = fragments[p]
         override fun getCount() = fragments.size
         override fun getPageTitle(p: Int) = if (pageTitles == null) null else pageTitles[p]
@@ -60,6 +64,24 @@ fun ViewPager.bindFragment(
 }
 
 /**
+ * 给ViewPager2绑定Fragment
+ */
+fun ViewPager2.bindFragment(
+    fm: FragmentManager,
+    lifecycle: Lifecycle,
+    fragments: List<Fragment>
+): ViewPager2 {
+    offscreenPageLimit = fragments.size - 1
+
+    adapter = object : FragmentStateAdapter(fm, lifecycle) {
+        override fun getItemCount(): Int = fragments.size
+        override fun createFragment(position: Int): Fragment = fragments[position]
+    }
+    return this
+}
+
+
+/**
  * 让ViewPager展示卡片效果
  * @param pageMargin 用来调节卡片之间的距离
  * @param padding 用来调节ViewPager的padding

二进制
cs_cptServices/src/main/res/drawable-xxhdpi/im_default_head.webp


+ 1 - 0
cs_ninegrid/.gitignore

@@ -0,0 +1 @@
+/build

+ 7 - 0
cs_ninegrid/build.gradle

@@ -0,0 +1,7 @@
+apply from: "../lib_default_config.gradle"
+apply plugin: 'dagger.hilt.android.plugin'
+
+dependencies {
+    //底层
+    implementation project(':cs_baselib')
+}

+ 17 - 0
cs_ninegrid/proguard-rules.pro

@@ -0,0 +1,17 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in E:\Android\SDK/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the proguardFiles
+# directive in build.gradle.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}

+ 9 - 0
cs_ninegrid/src/main/AndroidManifest.xml

@@ -0,0 +1,9 @@
+<manifest
+    package="com.guadou.ninegrid"
+    xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <application>
+
+    </application>
+
+</manifest>

+ 76 - 0
cs_ninegrid/src/main/java/com/guadou/ninegrid/ImageInfo.java

@@ -0,0 +1,76 @@
+package com.guadou.ninegrid;
+
+import java.io.Serializable;
+
+/**
+ * 九宫格的图片bean
+ */
+public class ImageInfo implements Serializable {
+
+    public String thumbnailUrl;
+    public String bigImageUrl;
+    public int imageViewHeight;
+    public int imageViewWidth;
+    public int imageViewX;
+    public int imageViewY;
+
+    public String getThumbnailUrl() {
+        return thumbnailUrl;
+    }
+
+    public void setThumbnailUrl(String thumbnailUrl) {
+        this.thumbnailUrl = thumbnailUrl;
+    }
+
+    public String getBigImageUrl() {
+        return bigImageUrl;
+    }
+
+    public void setBigImageUrl(String bigImageUrl) {
+        this.bigImageUrl = bigImageUrl;
+    }
+
+    public int getImageViewHeight() {
+        return imageViewHeight;
+    }
+
+    public void setImageViewHeight(int imageViewHeight) {
+        this.imageViewHeight = imageViewHeight;
+    }
+
+    public int getImageViewWidth() {
+        return imageViewWidth;
+    }
+
+    public void setImageViewWidth(int imageViewWidth) {
+        this.imageViewWidth = imageViewWidth;
+    }
+
+    public int getImageViewX() {
+        return imageViewX;
+    }
+
+    public void setImageViewX(int imageViewX) {
+        this.imageViewX = imageViewX;
+    }
+
+    public int getImageViewY() {
+        return imageViewY;
+    }
+
+    public void setImageViewY(int imageViewY) {
+        this.imageViewY = imageViewY;
+    }
+
+    @Override
+    public String toString() {
+        return "ImageInfo{" +
+                "imageViewY=" + imageViewY +
+                ", imageViewX=" + imageViewX +
+                ", imageViewWidth=" + imageViewWidth +
+                ", imageViewHeight=" + imageViewHeight +
+                ", bigImageUrl='" + bigImageUrl + '\'' +
+                ", thumbnailUrl='" + thumbnailUrl + '\'' +
+                '}';
+    }
+}

+ 17 - 0
cs_ninegrid/src/main/java/com/guadou/ninegrid/ImageLoader.java

@@ -0,0 +1,17 @@
+package com.guadou.ninegrid;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.widget.ImageView;
+
+public interface ImageLoader {
+    /**
+     * 需要子类实现该方法,以确定如何加载和显示图片
+     *
+     * @param context   上下文
+     * @param imageView 需要展示图片的ImageView
+     * @param url       图片地址
+     */
+    void onDisplayImage(Context context, ImageView imageView, String url);
+
+}

+ 34 - 0
cs_ninegrid/src/main/java/com/guadou/ninegrid/NineGlideLoader.kt

@@ -0,0 +1,34 @@
+package com.guadou.ninegrid
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.widget.ImageView
+import com.guadou.lib_baselib.engine.extLoad
+import com.guadou.lib_baselib.engine.extLoadGif
+import com.guadou.lib_baselib.ext.checkEmpty
+
+/**
+ * 九宫格加载器
+ */
+class NineGlideLoader : ImageLoader {
+    @SuppressLint("CheckResult")
+    override fun onDisplayImage(context: Context, imageView: ImageView, url: String) {
+        var urlStr = url
+        if (urlStr.checkEmpty()) return
+
+        if (urlStr.startsWith("https")) {
+            //https可能会阻塞glide线程,导致图片加载缓慢
+            urlStr = urlStr.replace("https", "http")
+        }
+
+        imageView.setImageResource(R.drawable.layer_main_placeholder)
+
+        if (urlStr.endsWith(".gif")) {
+
+            imageView.extLoadGif(urlStr, R.drawable.layer_main_placeholder)
+
+        } else {
+            imageView.extLoad(urlStr, R.drawable.layer_main_placeholder)
+        }
+    }
+}

+ 687 - 0
cs_ninegrid/src/main/java/com/guadou/ninegrid/flownine/FlowLayout.java

@@ -0,0 +1,687 @@
+package com.guadou.ninegrid.flownine;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewDebug;
+import android.view.ViewGroup;
+
+import com.guadou.ninegrid.R;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+
+public class FlowLayout extends ViewGroup {
+    public static final int HORIZONTAL = 0;
+    public static final int VERTICAL = 1;
+    public static final int LAYOUT_DIRECTION_LTR = 0;
+    public static final int LAYOUT_DIRECTION_RTL = 1;
+
+    //是否单行显示
+    private boolean isSingleLine = false;
+
+    public final LayoutConfiguration config;
+    public List<LineDefinition> lines = new ArrayList<>();
+
+    public FlowLayout(Context context) {
+        super(context);
+        this.config = new LayoutConfiguration(context, null);
+    }
+
+    public FlowLayout(Context context, AttributeSet attributeSet) {
+        super(context, attributeSet);
+        this.config = new LayoutConfiguration(context, attributeSet);
+    }
+
+    public FlowLayout(Context context, AttributeSet attributeSet, int defStyle) {
+        super(context, attributeSet, defStyle);
+        this.config = new LayoutConfiguration(context, attributeSet);
+    }
+
+    @SuppressLint("DrawAllocation")
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        final int sizeWidth = MeasureSpec.getSize(widthMeasureSpec) - this.getPaddingRight() - this.getPaddingLeft();
+        final int sizeHeight = MeasureSpec.getSize(heightMeasureSpec) - this.getPaddingTop() - this.getPaddingBottom();
+        final int modeWidth = MeasureSpec.getMode(widthMeasureSpec);
+        final int modeHeight = MeasureSpec.getMode(heightMeasureSpec);
+        final int controlMaxLength = this.config.getOrientation() == HORIZONTAL ? sizeWidth : sizeHeight;
+        final int controlMaxThickness = this.config.getOrientation() == HORIZONTAL ? sizeHeight : sizeWidth;
+        final int modeLength = this.config.getOrientation() == HORIZONTAL ? modeWidth : modeHeight;
+        final int modeThickness = this.config.getOrientation() == HORIZONTAL ? modeHeight : modeWidth;
+
+        lines.clear();
+        LineDefinition currentLine = new LineDefinition(controlMaxLength);
+        lines.add(currentLine);
+
+        final int count = this.getChildCount();
+        for (int i = 0; i < count; i++) {
+            final View child = this.getChildAt(i);
+            if (child.getVisibility() == GONE) {
+                continue;
+            }
+
+            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+
+            child.measure(
+                    getChildMeasureSpec(widthMeasureSpec, this.getPaddingLeft() + this.getPaddingRight(), lp.width),
+                    getChildMeasureSpec(heightMeasureSpec, this.getPaddingTop() + this.getPaddingBottom(), lp.height)
+            );
+
+            lp.orientation = this.config.getOrientation();
+            if (this.config.getOrientation() == FlowLayout.HORIZONTAL) {
+                lp.setLength(child.getMeasuredWidth());
+                lp.setThickness(child.getMeasuredHeight());
+            } else {
+                lp.setLength(child.getMeasuredHeight());
+                lp.setThickness(child.getMeasuredWidth());
+            }
+
+            //如果要折叠
+//            if (isExpanded) {
+//                break;
+//            }
+
+            boolean newLine = (lp.isNewLine() || (modeLength != MeasureSpec.UNSPECIFIED && !currentLine.canFit(child)))
+                    && !isSingleLine;
+
+            if (newLine) {
+                currentLine = new LineDefinition(controlMaxLength);
+
+                if (this.config.getOrientation() == VERTICAL && this.config.getLayoutDirection() == LAYOUT_DIRECTION_RTL) {
+                    lines.add(0, currentLine);
+                } else {
+                    lines.add(currentLine);
+                }
+
+            }
+
+            if (this.config.getOrientation() == HORIZONTAL && this.config.getLayoutDirection() == LAYOUT_DIRECTION_RTL) {
+                currentLine.addView(0, child);
+            } else {
+                currentLine.addView(child);
+            }
+        }
+
+        this.calculateLinesAndChildPosition(lines);
+
+        int contentLength = 0;
+        final int linesCount = lines.size();
+        for (int i = 0; i < linesCount; i++) {
+            LineDefinition l = lines.get(i);
+            contentLength = Math.max(contentLength, l.getLineLength());
+        }
+        int contentThickness = currentLine.getLineStartThickness() + currentLine.getLineThickness();
+
+        int realControlLength = this.findSize(modeLength, controlMaxLength, contentLength);
+        int realControlThickness = this.findSize(modeHeight, controlMaxThickness, contentThickness);
+
+        this.applyGravityToLines(lines, realControlLength, realControlThickness);
+
+        for (int i = 0; i < linesCount; i++) {
+            LineDefinition line = lines.get(i);
+            this.applyGravityToLine(line);
+            this.applyPositionsToViews(line);
+        }
+
+        /* need to take padding into account */
+        int totalControlWidth = this.getPaddingLeft() + this.getPaddingRight();
+        int totalControlHeight = this.getPaddingBottom() + this.getPaddingTop();
+        if (this.config.getOrientation() == HORIZONTAL) {
+            totalControlWidth += contentLength;
+            totalControlHeight += contentThickness;
+        } else {
+            totalControlWidth += contentThickness;
+            totalControlHeight += contentLength;
+        }
+
+        //最后确定整个布局的高度和宽度
+        int cachedTotalWith = resolveSize(totalControlWidth, widthMeasureSpec);
+        int cachedTotalHeight = resolveSize(totalControlHeight, heightMeasureSpec);
+
+        this.setMeasuredDimension(cachedTotalWith, cachedTotalHeight);
+    }
+
+    public int findSize(int modeSize, int controlMaxSize, int contentSize) {
+        int realControlLength;
+        switch (modeSize) {
+            case MeasureSpec.UNSPECIFIED:
+                realControlLength = contentSize;
+                break;
+            case MeasureSpec.AT_MOST:
+                realControlLength = Math.min(contentSize, controlMaxSize);
+                break;
+            case MeasureSpec.EXACTLY:
+                realControlLength = controlMaxSize;
+                break;
+            default:
+                realControlLength = contentSize;
+                break;
+        }
+        return realControlLength;
+    }
+
+    public void calculateLinesAndChildPosition(List<LineDefinition> lines) {
+        int prevLinesThickness = 0;
+        final int linesCount = lines.size();
+        for (int i = 0; i < linesCount; i++) {
+            final LineDefinition line = lines.get(i);
+            line.setLineStartThickness(prevLinesThickness);
+            prevLinesThickness += line.getLineThickness();
+            int prevChildThickness = 0;
+            final List<View> childViews = line.getViews();
+            final int childCount = childViews.size();
+            for (int j = 0; j < childCount; j++) {
+                View child = childViews.get(j);
+                LayoutParams lp = (LayoutParams) child.getLayoutParams();
+                lp.setInlineStartLength(prevChildThickness);
+                prevChildThickness += lp.getLength() + lp.getSpacingLength();
+            }
+        }
+    }
+
+    public void applyPositionsToViews(LineDefinition line) {
+        final List<View> childViews = line.getViews();
+        final int childCount = childViews.size();
+        for (int i = 0; i < childCount; i++) {
+            final View child = childViews.get(i);
+            LayoutParams layoutParams = (LayoutParams) child.getLayoutParams();
+            if (this.config.getOrientation() == HORIZONTAL) {
+                layoutParams.setPosition(
+                        this.getPaddingLeft() + line.getLineStartLength() + layoutParams.getInlineStartLength(),
+                        this.getPaddingTop() + line.getLineStartThickness() + layoutParams.getInlineStartThickness());
+                child.measure(
+                        MeasureSpec.makeMeasureSpec(layoutParams.getLength(), MeasureSpec.EXACTLY),
+                        MeasureSpec.makeMeasureSpec(layoutParams.getThickness(), MeasureSpec.EXACTLY)
+                );
+            } else {
+                layoutParams.setPosition(
+                        this.getPaddingLeft() + line.getLineStartThickness() + layoutParams.getInlineStartThickness(),
+                        this.getPaddingTop() + line.getLineStartLength() + layoutParams.getInlineStartLength());
+                child.measure(
+                        MeasureSpec.makeMeasureSpec(layoutParams.getThickness(), MeasureSpec.EXACTLY),
+                        MeasureSpec.makeMeasureSpec(layoutParams.getLength(), MeasureSpec.EXACTLY)
+                );
+            }
+        }
+    }
+
+    public void applyGravityToLines(List<LineDefinition> lines, int realControlLength, int realControlThickness) {
+        final int linesCount = lines.size();
+        if (linesCount <= 0) {
+            return;
+        }
+
+        final int totalWeight = linesCount;
+        LineDefinition lastLine = lines.get(linesCount - 1);
+        int excessThickness = realControlThickness - (lastLine.getLineThickness() + lastLine.getLineStartThickness());
+
+        if (excessThickness < 0) {
+            excessThickness = 0;
+        }
+
+        int excessOffset = 0;
+        for (int i = 0; i < linesCount; i++) {
+            final LineDefinition child = lines.get(i);
+            int weight = 1;
+            int gravity = this.getGravity(null);
+            int extraThickness = Math.round(excessThickness * weight / totalWeight);
+
+            final int childLength = child.getLineLength();
+            final int childThickness = child.getLineThickness();
+
+            Rect container = new Rect();
+            container.top = excessOffset;
+            container.left = 0;
+            container.right = realControlLength;
+            container.bottom = childThickness + extraThickness + excessOffset;
+
+            Rect result = new Rect();
+            Gravity.apply(gravity, childLength, childThickness, container, result);
+
+            excessOffset += extraThickness;
+            child.setLineStartLength(child.getLineStartLength() + result.left);
+            child.setLineStartThickness(child.getLineStartThickness() + result.top);
+            child.setLength(result.width());
+            child.setThickness(result.height());
+        }
+    }
+
+    public void applyGravityToLine(LineDefinition line) {
+        final List<View> views = line.getViews();
+        final int viewCount = views.size();
+        if (viewCount <= 0) {
+            return;
+        }
+
+        float totalWeight = 0;
+        for (int i = 0; i < viewCount; i++) {
+            final View prev = views.get(i);
+            LayoutParams plp = (LayoutParams) prev.getLayoutParams();
+            totalWeight += this.getWeight(plp);
+        }
+
+        View lastChild = views.get(viewCount - 1);
+        LayoutParams lastChildLayoutParams = (LayoutParams) lastChild.getLayoutParams();
+        int excessLength = line.getLineLength() - (lastChildLayoutParams.getLength() + lastChildLayoutParams.getSpacingLength() + lastChildLayoutParams.getInlineStartLength());
+        int excessOffset = 0;
+        for (int i = 0; i < viewCount; i++) {
+            final View child = views.get(i);
+            LayoutParams layoutParams = (LayoutParams) child.getLayoutParams();
+
+            float weight = this.getWeight(layoutParams);
+            int gravity = this.getGravity(layoutParams);
+            int extraLength;
+            if (totalWeight == 0) {
+                extraLength = excessLength / viewCount;
+            } else {
+                extraLength = Math.round(excessLength * weight / totalWeight);
+            }
+
+            final int childLength = layoutParams.getLength() + layoutParams.getSpacingLength();
+            final int childThickness = layoutParams.getThickness() + layoutParams.getSpacingThickness();
+
+            Rect container = new Rect();
+            container.top = 0;
+            container.left = excessOffset;
+            container.right = childLength + extraLength + excessOffset;
+            container.bottom = line.getLineThickness();
+
+            Rect result = new Rect();
+            Gravity.apply(gravity, childLength, childThickness, container, result);
+
+            excessOffset += extraLength;
+            layoutParams.setInlineStartLength(result.left + layoutParams.getInlineStartLength());
+            layoutParams.setInlineStartThickness(result.top);
+            layoutParams.setLength(result.width() - layoutParams.getSpacingLength());
+            layoutParams.setThickness(result.height() - layoutParams.getSpacingThickness());
+        }
+    }
+
+    private int getGravity(LayoutParams lp) {
+        int parentGravity = this.config.getGravity();
+
+        int childGravity;
+        // get childGravity of child view (if exists)
+        if (lp != null && lp.gravitySpecified()) {
+            childGravity = lp.getGravity();
+        } else {
+            childGravity = parentGravity;
+        }
+
+        childGravity = getGravityFromRelative(childGravity);
+        parentGravity = getGravityFromRelative(parentGravity);
+
+        // add parent gravity to child gravity if child gravity is not specified
+        if ((childGravity & Gravity.HORIZONTAL_GRAVITY_MASK) == 0) {
+            childGravity |= parentGravity & Gravity.HORIZONTAL_GRAVITY_MASK;
+        }
+        if ((childGravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) {
+            childGravity |= parentGravity & Gravity.VERTICAL_GRAVITY_MASK;
+        }
+
+        // if childGravity is still not specified - set default top - left gravity
+        if ((childGravity & Gravity.HORIZONTAL_GRAVITY_MASK) == 0) {
+            childGravity |= Gravity.LEFT;
+        }
+        if ((childGravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) {
+            childGravity |= Gravity.TOP;
+        }
+
+        return childGravity;
+    }
+
+    private int getGravityFromRelative(int childGravity) {
+        // swap directions for vertical non relative view
+        // if it is relative, then START is TOP, and we do not need to switch it here.
+        // it will be switched later on onMeasure stage when calculations will be with length and thickness
+        if (this.config.getOrientation() == VERTICAL && (childGravity & Gravity.RELATIVE_LAYOUT_DIRECTION) == 0) {
+            int horizontalGravity = childGravity;
+            childGravity = 0;
+            childGravity |= (horizontalGravity & Gravity.HORIZONTAL_GRAVITY_MASK) >> Gravity.AXIS_X_SHIFT << Gravity.AXIS_Y_SHIFT;
+            childGravity |= (horizontalGravity & Gravity.VERTICAL_GRAVITY_MASK) >> Gravity.AXIS_Y_SHIFT << Gravity.AXIS_X_SHIFT;
+        }
+
+        // for relative layout and RTL direction swap left and right gravity
+        if (this.config.getLayoutDirection() == LAYOUT_DIRECTION_RTL && (childGravity & Gravity.RELATIVE_LAYOUT_DIRECTION) != 0) {
+            int ltrGravity = childGravity;
+            childGravity = 0;
+            childGravity |= (ltrGravity & Gravity.LEFT) == Gravity.LEFT ? Gravity.RIGHT : 0;
+            childGravity |= (ltrGravity & Gravity.RIGHT) == Gravity.RIGHT ? Gravity.LEFT : 0;
+        }
+
+        return childGravity;
+    }
+
+    private float getWeight(LayoutParams lp) {
+        return lp.weightSpecified() ? lp.getWeight() : this.config.getWeightDefault();
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        final int count = this.getChildCount();
+        for (int i = 0; i < count; i++) {
+            View child = this.getChildAt(i);
+            LayoutParams lp = (LayoutParams) child.getLayoutParams();
+            child.layout(lp.x + lp.leftMargin, lp.y + lp.topMargin,
+                    lp.x + lp.leftMargin + child.getMeasuredWidth(), lp.y + lp.topMargin + child.getMeasuredHeight());
+        }
+    }
+
+    @Override
+    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
+        boolean more = super.drawChild(canvas, child, drawingTime);
+        this.drawDebugInfo(canvas, child);
+        return more;
+    }
+
+    @Override
+    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
+        return p instanceof LayoutParams;
+    }
+
+    @Override
+    protected LayoutParams generateDefaultLayoutParams() {
+        return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+    }
+
+    @Override
+    public LayoutParams generateLayoutParams(AttributeSet attributeSet) {
+        return new LayoutParams(this.getContext(), attributeSet);
+    }
+
+    @Override
+    protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
+        return new LayoutParams(p);
+    }
+
+    private void drawDebugInfo(Canvas canvas, View child) {
+        if (!isDebugDraw()) {
+            return;
+        }
+
+        Paint childPaint = this.createPaint(0xffffff00);
+        Paint newLinePaint = this.createPaint(0xffff0000);
+
+        LayoutParams lp = (LayoutParams) child.getLayoutParams();
+
+        if (lp.rightMargin > 0) {
+            float x = child.getRight();
+            float y = child.getTop() + child.getHeight() / 2.0f;
+            canvas.drawLine(x, y, x + lp.rightMargin, y, childPaint);
+            canvas.drawLine(x + lp.rightMargin - 4.0f, y - 4.0f, x + lp.rightMargin, y, childPaint);
+            canvas.drawLine(x + lp.rightMargin - 4.0f, y + 4.0f, x + lp.rightMargin, y, childPaint);
+        }
+
+        if (lp.leftMargin > 0) {
+            float x = child.getLeft();
+            float y = child.getTop() + child.getHeight() / 2.0f;
+            canvas.drawLine(x, y, x - lp.leftMargin, y, childPaint);
+            canvas.drawLine(x - lp.leftMargin + 4.0f, y - 4.0f, x - lp.leftMargin, y, childPaint);
+            canvas.drawLine(x - lp.leftMargin + 4.0f, y + 4.0f, x - lp.leftMargin, y, childPaint);
+        }
+
+        if (lp.bottomMargin > 0) {
+            float x = child.getLeft() + child.getWidth() / 2.0f;
+            float y = child.getBottom();
+            canvas.drawLine(x, y, x, y + lp.bottomMargin, childPaint);
+            canvas.drawLine(x - 4.0f, y + lp.bottomMargin - 4.0f, x, y + lp.bottomMargin, childPaint);
+            canvas.drawLine(x + 4.0f, y + lp.bottomMargin - 4.0f, x, y + lp.bottomMargin, childPaint);
+        }
+
+        if (lp.topMargin > 0) {
+            float x = child.getLeft() + child.getWidth() / 2.0f;
+            float y = child.getTop();
+            canvas.drawLine(x, y, x, y - lp.topMargin, childPaint);
+            canvas.drawLine(x - 4.0f, y - lp.topMargin + 4.0f, x, y - lp.topMargin, childPaint);
+            canvas.drawLine(x + 4.0f, y - lp.topMargin + 4.0f, x, y - lp.topMargin, childPaint);
+        }
+
+        if (lp.isNewLine()) {
+            if (this.config.getOrientation() == HORIZONTAL) {
+                float x = child.getLeft();
+                float y = child.getTop() + child.getHeight() / 2.0f;
+                canvas.drawLine(x, y - 6.0f, x, y + 6.0f, newLinePaint);
+            } else {
+                float x = child.getLeft() + child.getWidth() / 2.0f;
+                float y = child.getTop();
+                canvas.drawLine(x - 6.0f, y, x + 6.0f, y, newLinePaint);
+            }
+        }
+    }
+
+    private Paint createPaint(int color) {
+        Paint paint = new Paint();
+        paint.setAntiAlias(true);
+        paint.setColor(color);
+        paint.setStrokeWidth(2.0f);
+        return paint;
+    }
+
+    public int getOrientation() {
+        return this.config.getOrientation();
+    }
+
+    public void setOrientation(int orientation) {
+        this.config.setOrientation(orientation);
+        this.requestLayout();
+    }
+
+    public boolean isDebugDraw() {
+        return this.config.isDebugDraw() || debugDraw();
+    }
+
+    public void setDebugDraw(boolean debugDraw) {
+        this.config.setDebugDraw(debugDraw);
+        this.invalidate();
+    }
+
+    private boolean debugDraw() {
+        try {
+            // android add this method at 4.1
+            Method m = ViewGroup.class.getDeclaredMethod("debugDraw", (Class[]) null);
+            m.setAccessible(true);
+            return (boolean) m.invoke(this, new Object[]{null});
+        } catch (Exception e) {
+            // if no such method (android not support this at lower api level), return false
+            // ignore this, it's safe here
+        }
+
+        return false;
+    }
+
+    public float getWeightDefault() {
+        return this.config.getWeightDefault();
+    }
+
+    public void setWeightDefault(float weightDefault) {
+        this.config.setWeightDefault(weightDefault);
+        this.requestLayout();
+    }
+
+    public int getGravity() {
+        return this.config.getGravity();
+    }
+
+    public void setGravity(int gravity) {
+        this.config.setGravity(gravity);
+        this.requestLayout();
+    }
+
+    public int getLayoutDirection() {
+        if (this.config == null) {
+            // Workaround for android sdk that wants to use virtual methods within constructor.
+            return LAYOUT_DIRECTION_LTR;
+        }
+
+        return this.config.getLayoutDirection();
+    }
+
+    public void setLayoutDirection(int layoutDirection) {
+        this.config.setLayoutDirection(layoutDirection);
+        this.requestLayout();
+    }
+
+    public boolean isSingleLine() {
+        return isSingleLine;
+    }
+
+    public void setSingleLine(boolean singleLine) {
+        isSingleLine = singleLine;
+    }
+
+    public static class LayoutParams extends MarginLayoutParams {
+        @ViewDebug.ExportedProperty(mapping = {
+                @ViewDebug.IntToString(from = Gravity.NO_GRAVITY, to = "NONE"),
+                @ViewDebug.IntToString(from = Gravity.TOP, to = "TOP"),
+                @ViewDebug.IntToString(from = Gravity.BOTTOM, to = "BOTTOM"),
+                @ViewDebug.IntToString(from = Gravity.LEFT, to = "LEFT"),
+                @ViewDebug.IntToString(from = Gravity.RIGHT, to = "RIGHT"),
+                @ViewDebug.IntToString(from = Gravity.CENTER_VERTICAL, to = "CENTER_VERTICAL"),
+                @ViewDebug.IntToString(from = Gravity.FILL_VERTICAL, to = "FILL_VERTICAL"),
+                @ViewDebug.IntToString(from = Gravity.CENTER_HORIZONTAL, to = "CENTER_HORIZONTAL"),
+                @ViewDebug.IntToString(from = Gravity.FILL_HORIZONTAL, to = "FILL_HORIZONTAL"),
+                @ViewDebug.IntToString(from = Gravity.CENTER, to = "CENTER"),
+                @ViewDebug.IntToString(from = Gravity.FILL, to = "FILL")
+        })
+
+        private boolean newLine = false;
+        private int gravity = Gravity.NO_GRAVITY;
+        private float weight = -1.0f;
+        private int inlineStartLength;
+        private int length;
+        private int thickness;
+        private int inlineStartThickness;
+        private int x;
+        private int y;
+        public int orientation;
+
+        public LayoutParams(Context context, AttributeSet attributeSet) {
+            super(context, attributeSet);
+            this.readStyleParameters(context, attributeSet);
+        }
+
+        public LayoutParams(int width, int height) {
+            super(width, height);
+        }
+
+        public LayoutParams(ViewGroup.LayoutParams layoutParams) {
+            super(layoutParams);
+        }
+
+        public boolean gravitySpecified() {
+            return this.gravity != Gravity.NO_GRAVITY;
+        }
+
+        public boolean weightSpecified() {
+            return this.weight >= 0;
+        }
+
+        private void readStyleParameters(Context context, AttributeSet attributeSet) {
+            TypedArray a = context.obtainStyledAttributes(attributeSet, R.styleable.FlowLayout_LayoutParams);
+            try {
+                this.newLine = a.getBoolean(R.styleable.FlowLayout_LayoutParams_layout_newLine, false);
+                this.gravity = a.getInt(R.styleable.FlowLayout_LayoutParams_android_layout_gravity, Gravity.NO_GRAVITY);
+                this.weight = a.getFloat(R.styleable.FlowLayout_LayoutParams_layout_weight, -1.0f);
+            } finally {
+                a.recycle();
+            }
+        }
+
+
+        public void setPosition(int x, int y) {
+            this.x = x;
+            this.y = y;
+        }
+
+        public int getInlineStartLength() {
+            return inlineStartLength;
+        }
+
+        public void setInlineStartLength(int inlineStartLength) {
+            this.inlineStartLength = inlineStartLength;
+        }
+
+        public int getLength() {
+            return length;
+        }
+
+        public void setLength(int length) {
+            this.length = length;
+        }
+
+        public int getThickness() {
+            return thickness;
+        }
+
+        public void setThickness(int thickness) {
+            this.thickness = thickness;
+        }
+
+        public int getInlineStartThickness() {
+            return inlineStartThickness;
+        }
+
+        public void setInlineStartThickness(int inlineStartThickness) {
+            this.inlineStartThickness = inlineStartThickness;
+        }
+
+        int getSpacingLength() {
+            if (orientation == FlowLayout.HORIZONTAL) {
+                return this.leftMargin + this.rightMargin;
+            } else {
+                return this.topMargin + this.bottomMargin;
+            }
+        }
+
+        int getSpacingThickness() {
+            if (orientation == FlowLayout.HORIZONTAL) {
+                return this.topMargin + this.bottomMargin;
+            } else {
+                return this.leftMargin + this.rightMargin;
+            }
+        }
+
+        public int getX() {
+            return x;
+        }
+
+        public int getY() {
+            return y;
+        }
+
+        public int getGravity() {
+            return gravity;
+        }
+
+        public void setGravity(int gravity) {
+            this.gravity = gravity;
+        }
+
+        public float getWeight() {
+            return weight;
+        }
+
+        public void setWeight(float weight) {
+            this.weight = weight;
+        }
+
+        public boolean isNewLine() {
+            return newLine;
+        }
+
+        public void setNewLine(boolean newLine) {
+            this.newLine = newLine;
+        }
+
+
+    }
+}
+

+ 77 - 0
cs_ninegrid/src/main/java/com/guadou/ninegrid/flownine/LayoutConfiguration.java

@@ -0,0 +1,77 @@
+package com.guadou.ninegrid.flownine;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.view.Gravity;
+
+import com.guadou.ninegrid.R;
+
+public class LayoutConfiguration {
+    private int orientation = FlowLayout.HORIZONTAL;
+    private boolean debugDraw = false;
+    private float weightDefault = 0;
+    private int gravity = Gravity.LEFT | Gravity.TOP;
+    private int layoutDirection = FlowLayout.LAYOUT_DIRECTION_LTR;
+
+    public LayoutConfiguration(Context context, AttributeSet attributeSet) {
+        TypedArray a = context.obtainStyledAttributes(attributeSet, R.styleable.FlowLayout);
+        try {
+            this.setOrientation(a.getInteger(R.styleable.FlowLayout_android_orientation, FlowLayout.HORIZONTAL));
+            this.setDebugDraw(a.getBoolean(R.styleable.FlowLayout_debugDraw, false));
+            this.setWeightDefault(a.getFloat(R.styleable.FlowLayout_weightDefault, 0.0f));
+            this.setGravity(a.getInteger(R.styleable.FlowLayout_android_gravity, Gravity.NO_GRAVITY));
+            this.setLayoutDirection(a.getInteger(R.styleable.FlowLayout_layoutDirection, FlowLayout.LAYOUT_DIRECTION_LTR));
+        } finally {
+            a.recycle();
+        }
+    }
+
+    public int getOrientation() {
+        return this.orientation;
+    }
+
+    public void setOrientation(int orientation) {
+        if (orientation == FlowLayout.VERTICAL) {
+            this.orientation = orientation;
+        } else {
+            this.orientation = FlowLayout.HORIZONTAL;
+        }
+    }
+
+    public boolean isDebugDraw() {
+        return this.debugDraw;
+    }
+
+    public void setDebugDraw(boolean debugDraw) {
+        this.debugDraw = debugDraw;
+    }
+
+    public float getWeightDefault() {
+        return this.weightDefault;
+    }
+
+    public void setWeightDefault(float weightDefault) {
+        this.weightDefault = Math.max(0, weightDefault);
+    }
+
+    public int getGravity() {
+        return this.gravity;
+    }
+
+    public void setGravity(int gravity) {
+        this.gravity = gravity;
+    }
+
+    public int getLayoutDirection() {
+        return layoutDirection;
+    }
+
+    public void setLayoutDirection(int layoutDirection) {
+        if (layoutDirection == FlowLayout.LAYOUT_DIRECTION_RTL) {
+            this.layoutDirection = layoutDirection;
+        } else {
+            this.layoutDirection = FlowLayout.LAYOUT_DIRECTION_LTR;
+        }
+    }
+}

+ 76 - 0
cs_ninegrid/src/main/java/com/guadou/ninegrid/flownine/LineDefinition.java

@@ -0,0 +1,76 @@
+package com.guadou.ninegrid.flownine;
+
+import android.view.View;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class LineDefinition {
+    private final List<View> views = new ArrayList<>();
+    private final int maxLength;
+    private int lineLength;
+    private int lineThickness;
+    private int lineStartThickness;
+    private int lineStartLength;
+
+    public LineDefinition(int maxLength) {
+        this.lineStartThickness = 0;
+        this.lineStartLength = 0;
+        this.maxLength = maxLength;
+    }
+
+    public void addView(View child) {
+        this.addView(this.views.size(), child);
+    }
+
+    public void addView(int i, View child) {
+        final FlowLayout.LayoutParams lp = (FlowLayout.LayoutParams) child.getLayoutParams();
+
+        this.views.add(i, child);
+
+        this.lineLength = this.lineLength + lp.getLength() + lp.getSpacingLength();
+        this.lineThickness = Math.max(this.lineThickness, lp.getThickness() + lp.getSpacingThickness());
+    }
+
+    public boolean canFit(View child) {
+        final FlowLayout.LayoutParams lp = (FlowLayout.LayoutParams) child.getLayoutParams();
+        return lineLength + lp.getLength() + lp.getSpacingLength() <= maxLength;
+    }
+
+    public int getLineStartThickness() {
+        return lineStartThickness;
+    }
+
+    public void setLineStartThickness(int lineStartThickness) {
+        this.lineStartThickness = lineStartThickness;
+    }
+
+    public int getLineThickness() {
+        return lineThickness;
+    }
+
+    public int getLineLength() {
+        return lineLength;
+    }
+
+    public int getLineStartLength() {
+        return lineStartLength;
+    }
+
+    public void setLineStartLength(int lineStartLength) {
+        this.lineStartLength = lineStartLength;
+    }
+
+    public List<View> getViews() {
+        return views;
+    }
+
+    public void setThickness(int thickness) {
+        this.lineThickness = thickness;
+    }
+
+    public void setLength(int length) {
+        this.lineLength = length;
+    }
+}
+

+ 240 - 0
cs_ninegrid/src/main/java/com/guadou/ninegrid/nine_grid_layout/AbstractNineGridLayout.java

@@ -0,0 +1,240 @@
+package com.guadou.ninegrid.nine_grid_layout;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.guadou.ninegrid.R;
+
+import java.lang.reflect.Array;
+
+/**
+ * 抽象九宫格-具体的布局和测量在这里完成
+ */
+public abstract class AbstractNineGridLayout<T> extends ViewGroup {
+
+    private static final int MAX_CHILDREN_COUNT = 9;
+    private int itemWidth;
+    private int itemHeight;
+    private int horizontalSpacing;
+    private int verticalSpacing;
+    private boolean singleMode;
+    private boolean fourGridMode;
+    private int singleWidth;
+    private int singleHeight;
+    private boolean singleModeOverflowScale;
+//    private NineGridItemCacheBean mNineGridItemCacheBean;
+
+    public AbstractNineGridLayout(Context context) {
+        this(context, null);
+    }
+
+    public AbstractNineGridLayout(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        if (attrs != null) {
+            TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.NineGridLayout);
+            int spacing = a.getDimensionPixelSize(R.styleable.NineGridLayout_spacing, 0);
+            horizontalSpacing = a.getDimensionPixelSize(R.styleable.NineGridLayout_horizontal_spacing, spacing);
+            verticalSpacing = a.getDimensionPixelSize(R.styleable.NineGridLayout_vertical_spacing, spacing);
+            singleMode = a.getBoolean(R.styleable.NineGridLayout_single_mode, true);
+            fourGridMode = a.getBoolean(R.styleable.NineGridLayout_four_gird_mode, true);
+            singleWidth = a.getDimensionPixelSize(R.styleable.NineGridLayout_single_mode_width, 0);
+            singleHeight = a.getDimensionPixelSize(R.styleable.NineGridLayout_single_mode_height, 0);
+            singleModeOverflowScale = a.getBoolean(R.styleable.NineGridLayout_single_mode_overflow_scale, true);
+            a.recycle();
+        }
+
+        //优先填充布局,再执行测量和绘制
+        fill();
+    }
+
+    /**
+     * 设置显示的数量
+     */
+    public void setDisplayCount(int count) {
+        int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            getChildAt(i).setVisibility(i < count ? VISIBLE : GONE);
+        }
+    }
+
+    /**
+     * 设置单独布局的宽和高
+     */
+    public void setSingleModeSize(int w, int h) {
+        if (w != 0 && h != 0) {
+            this.singleWidth = w;
+            this.singleHeight = h;
+        }
+    }
+
+    protected void fill(ViewGetter viewGetter) {
+        removeAllViews();
+        for (int i = 0; i < MAX_CHILDREN_COUNT; i++) {
+            addView(viewGetter.getView(i));
+        }
+    }
+
+    /**
+     * 一般用这个方法填充布局,每一个小布局的布局文件
+     */
+    protected void fill(int layoutId) {
+        removeAllViews();
+        for (int i = 0; i < MAX_CHILDREN_COUNT; i++) {
+            LayoutInflater.from(getContext()).inflate(layoutId, this);
+        }
+    }
+
+    /**
+     * 返回每一个小布局的内部控件ID,用数组包装返回
+     */
+    @SuppressWarnings("unchecked")
+    protected <V extends View> V[] findInChildren(int viewId, Class<V> clazz) {
+        V[] result = (V[]) Array.newInstance(clazz, getChildCount());
+        for (int i = 0; i < result.length; i++) {
+            result[i] = (V) getChildAt(i).findViewById(viewId);
+        }
+        return result;
+    }
+
+    //子类去实现-填充布局文件
+    protected abstract void fill();
+
+    //子类去实现-对布局文件赋值(专门去给adapter去调用的)
+    public abstract void render(Activity activity, T data);
+
+
+    //提供缓存对象出去,给Adapter去保存索引
+//    public NineGridItemCacheBean obtainNineGridItemCacheBean() {
+//        return mNineGridItemCacheBean;
+//    }
+//
+//    public void setNineGridItemCacheBean(NineGridItemCacheBean cacheBean, OnInflateFinishListener inflateFinish) {
+//        mNineGridItemCacheBean = cacheBean;
+//        mListener = inflateFinish;
+//    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+//        YYLogUtils.e("onMeasure");
+
+//        if (mNineGridItemCacheBean == null)
+//            mNineGridItemCacheBean = new NineGridItemCacheBean();
+//
+//        //判断缓存,如果可以,直接测量出来占位
+//        if (mNineGridItemCacheBean.widgetWidth != 0 && mNineGridItemCacheBean.widgetHeight != 0) {
+//
+//            setMeasuredDimension(mNineGridItemCacheBean.widgetWidth, mNineGridItemCacheBean.widgetHeight);
+//            YYLogUtils.e("测量完毕回调出去1");
+//            //测量完毕回调出去
+//            mListener.onFinish(mNineGridItemCacheBean);
+//        } else {
+
+        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+        int widthSize = MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft() - getPaddingRight();
+
+        int notGoneChildCount = getNotGoneChildCount();
+
+        //判断子布局的缓存
+//            if (mNineGridItemCacheBean.childHeight != 0 && mNineGridItemCacheBean.childWidth != 0) {
+//
+//                itemWidth = mNineGridItemCacheBean.childWidth;
+//                itemHeight = mNineGridItemCacheBean.childHeight;
+//
+//            } else {
+
+        if (notGoneChildCount == 1 && singleMode) {
+            itemWidth = singleWidth > 0 ? singleWidth : widthSize;
+            itemHeight = singleHeight > 0 ? singleHeight : widthSize;
+            if (itemWidth > widthSize && singleModeOverflowScale) {
+                itemWidth = widthSize;  //单张图片先定宽度。
+                itemHeight = (int) (widthSize * 1f / singleWidth * singleHeight);  //根据宽度计算高度
+            }
+        } else {
+            itemWidth = (widthSize - horizontalSpacing * 2) / 3;
+            itemHeight = itemWidth;
+        }
+
+        //缓存赋值
+//                mNineGridItemCacheBean.childWidth = itemWidth;
+//                mNineGridItemCacheBean.childHeight = itemHeight;
+
+//            }
+
+        //测量子布局
+        measureChildren(MeasureSpec.makeMeasureSpec(itemWidth, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(itemHeight, MeasureSpec.EXACTLY));
+
+
+        if (heightMode == MeasureSpec.EXACTLY) {
+            setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
+        } else {
+            notGoneChildCount = Math.min(notGoneChildCount, MAX_CHILDREN_COUNT);
+            int height = ((notGoneChildCount - 1) / 3 + 1) * (itemHeight + verticalSpacing) - verticalSpacing + getPaddingTop() + getPaddingBottom();
+
+            setMeasuredDimension(widthMeasureSpec, MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
+
+            //缓存赋值
+//                mNineGridItemCacheBean.widgetWidth = widthMeasureSpec;
+//                mNineGridItemCacheBean.widgetHeight = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
+
+//                YYLogUtils.e("测量完毕回调出去2");
+            //测量完毕回调出去
+//                if (mListener != null) mListener.onFinish(mNineGridItemCacheBean);
+        }
+
+//        }
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+//        YYLogUtils.e("onLayout");
+        int childCount = getChildCount();
+        int notGoneChildCount = getNotGoneChildCount();
+        int position = 0;
+        for (int i = 0; i < childCount; i++) {
+            View child = getChildAt(i);
+            if (child.getVisibility() == View.GONE) {
+                continue;
+            }
+            int row = position / 3;
+            int col = position % 3;
+
+            if (notGoneChildCount == 4 && fourGridMode) {
+                row = position / 2;
+                col = position % 2;
+            }
+
+            int x = col * itemWidth + getPaddingLeft() + horizontalSpacing * col;
+            int y = row * itemHeight + getPaddingTop() + verticalSpacing * row;
+            child.layout(x, y, x + itemWidth, y + itemHeight);
+
+            position++;
+            if (position == MAX_CHILDREN_COUNT) {
+                break;
+            }
+        }
+    }
+
+    //获取没有隐藏的子布局
+    private int getNotGoneChildCount() {
+        int childCount = getChildCount();
+        int notGoneCount = 0;
+        for (int i = 0; i < childCount; i++) {
+            if (getChildAt(i).getVisibility() != View.GONE) {
+                notGoneCount++;
+            }
+        }
+        return notGoneCount;
+    }
+
+
+//    private OnInflateFinishListener mListener;
+//
+//    public interface OnInflateFinishListener {
+//        void onFinish(NineGridItemCacheBean cacheBean);
+//    }
+}

+ 28 - 0
cs_ninegrid/src/main/java/com/guadou/ninegrid/nine_grid_layout/NineGridLayout.java

@@ -0,0 +1,28 @@
+package com.guadou.ninegrid.nine_grid_layout;
+
+import android.app.Activity;
+import android.content.Context;
+import android.util.AttributeSet;
+
+/**
+ * 基类的九宫格-给别的自定义九宫格继承的
+ */
+public class NineGridLayout extends AbstractNineGridLayout {
+
+    public NineGridLayout(Context context) {
+        super(context);
+    }
+
+    public NineGridLayout(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void fill() {
+    }
+
+    @Override
+    public void render(Activity activity, Object data) {
+
+    }
+}

+ 77 - 0
cs_ninegrid/src/main/java/com/guadou/ninegrid/nine_grid_layout/SimpleImageViewNineGrid.kt

@@ -0,0 +1,77 @@
+package com.guadou.ninegrid.nine_grid_layout
+
+import android.app.Activity
+import android.content.Context
+import android.util.AttributeSet
+import android.widget.ImageView
+import com.guadou.lib_baselib.engine.ImagePreviewUtils
+import com.guadou.lib_baselib.ext.click
+import com.guadou.ninegrid.ImageInfo
+import com.guadou.ninegrid.ImageLoader
+import com.guadou.ninegrid.NineGlideLoader
+import com.guadou.ninegrid.R
+
+/**
+ * 默认的图片九宫格
+ */
+class SimpleImageViewNineGrid(context: Context?, attrs: AttributeSet?) : AbstractNineGridLayout<List<ImageInfo?>?>(context, attrs) {
+
+    private lateinit var imageViews: Array<ImageView>
+    private val mImageLoader: ImageLoader
+
+    override fun fill() {
+        fill(R.layout.item_image_grid)
+
+        imageViews = findInChildren(R.id.iv_image, ImageView::class.java)
+    }
+
+    override fun render(activity: Activity, data: List<ImageInfo?>?) {
+
+        data?.let {
+
+            setSingleModeSize(it[0]?.getImageViewWidth()!!, it[0]?.getImageViewHeight()!!)
+
+            setDisplayCount(it.size)
+
+            for (i in it.indices) {
+                val url = it[i]?.getThumbnailUrl()
+                val imageView = imageViews[i]
+
+                //使用自定义的Loader加载
+                mImageLoader.onDisplayImage(context, imageView, url)
+
+                //点击事件
+                setClickListener(activity, imageView, i, it)
+            }
+        }
+
+    }
+
+    //设置内部每一个图片的点击事件,跳转到预览页面
+    private fun setClickListener(activity: Activity, imageView: ImageView, position: Int, list: List<ImageInfo?>) {
+        imageView.click {
+            //开启多图预览
+            ImagePreviewUtils.multipleImagePreview(
+                activity,
+                imageView,
+                list.map { it?.thumbnailUrl as Any },
+                position,
+                R.drawable.layer_main_placeholder
+            ) { popupView, position ->
+                //当预览的图片滚动的时候需要选择是哪一个ImageView来生效了
+                popupView.updateSrcView(imageViews[position])
+            }
+        }
+    }
+
+    //获取到指定索引的投票图片控件
+    fun getImageView(index: Int): ImageView {
+        return if (index >= imageViews.size) imageViews[index - 1] else imageViews[index]
+    }
+
+    //默认在xml中使用
+    init {
+        mImageLoader = NineGlideLoader()
+    }
+
+}

+ 10 - 0
cs_ninegrid/src/main/java/com/guadou/ninegrid/nine_grid_layout/ViewGetter.java

@@ -0,0 +1,10 @@
+package com.guadou.ninegrid.nine_grid_layout;
+
+import android.view.View;
+
+/**
+ * Created by CaoDongping on 5/13/16.
+ */
+public interface ViewGetter {
+    View getView(int position);
+}

+ 82 - 0
cs_ninegrid/src/main/java/com/guadou/ninegrid/roundimg/CustomRoundImageView.java

@@ -0,0 +1,82 @@
+package com.guadou.ninegrid.roundimg;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Path;
+import android.util.AttributeSet;
+
+import androidx.appcompat.widget.AppCompatImageView;
+
+/**
+ * 自定义的圆角图片控件
+ */
+public class CustomRoundImageView extends AppCompatImageView {
+    float width, height;
+    private int defaultRadius = NiceUtils.dp2px(getContext(), 6);
+
+    private int leftTopRadius;
+    private int rightTopRadius;
+    private int rightBottomRadius;
+    private int leftBottomRadius;
+
+    public CustomRoundImageView(Context context) {
+        this(context, null);
+        init(context, null);
+    }
+
+    public CustomRoundImageView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+        init(context, attrs);
+    }
+
+    public CustomRoundImageView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        init(context, attrs);
+    }
+
+    private void init(Context context, AttributeSet attrs) {
+
+        leftTopRadius = defaultRadius;
+        rightTopRadius = defaultRadius;
+        rightBottomRadius = defaultRadius;
+        leftBottomRadius = defaultRadius;
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+        width = getWidth();
+        height = getHeight();
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        int maxLeft = Math.max(leftTopRadius, leftBottomRadius);
+        int maxRight = Math.max(rightTopRadius, rightBottomRadius);
+        int minWidth = maxLeft + maxRight;
+        int maxTop = Math.max(leftTopRadius, rightTopRadius);
+        int maxBottom = Math.max(leftBottomRadius, rightBottomRadius);
+        int minHeight = maxTop + maxBottom;
+        if (width >= minWidth && height > minHeight) {
+            @SuppressLint("DrawAllocation") Path path = new Path();
+            //四个角:右上,右下,左下,左上
+            path.moveTo(leftTopRadius, 0);
+            path.lineTo(width - rightTopRadius, 0);
+            path.quadTo(width, 0, width, rightTopRadius);
+
+            path.lineTo(width, height - rightBottomRadius);
+            path.quadTo(width, height, width - rightBottomRadius, height);
+
+            path.lineTo(leftBottomRadius, height);
+            path.quadTo(0, height, 0, height - leftBottomRadius);
+
+            path.lineTo(0, leftTopRadius);
+            path.quadTo(0, 0, leftTopRadius, 0);
+
+            canvas.clipPath(path);
+        }
+        super.onDraw(canvas);
+    }
+
+}

+ 92 - 0
cs_ninegrid/src/main/java/com/guadou/ninegrid/roundimg/ForceClickImageView.java

@@ -0,0 +1,92 @@
+package com.guadou.ninegrid.roundimg;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Rect;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.StateListDrawable;
+import android.util.AttributeSet;
+
+import com.guadou.ninegrid.R;
+import com.guadou.ninegrid.roundimg.CustomRoundImageView;
+
+/**
+ * 朋友圈的imageview,包含点击动作
+ */
+public class ForceClickImageView extends CustomRoundImageView {
+
+    //前景层
+    private Drawable mForegroundDrawable;
+    private Rect mCachedBounds = new Rect();
+
+    public ForceClickImageView(Context context) {
+        this(context, null);
+    }
+
+    public ForceClickImageView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public ForceClickImageView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        init(context, attrs, true);
+        setFocusable(true);
+        setScaleType(ScaleType.CENTER_CROP);
+    }
+
+    /**
+     * 初始化
+     */
+    private void init(Context context, AttributeSet attrs, boolean needDefaultForceGroundColor) {
+        final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ForceClickImageView);
+        mForegroundDrawable = a.getDrawable(R.styleable.ForceClickImageView_foregroundColor);
+        if (mForegroundDrawable instanceof ColorDrawable || (attrs == null && needDefaultForceGroundColor)) {
+            int foreGroundColor = a.getColor(R.styleable.ForceClickImageView_foregroundColor, 0x882b2b2b);
+            mForegroundDrawable = new StateListDrawable();
+            ColorDrawable forceDrawable = new ColorDrawable(foreGroundColor);
+            ColorDrawable normalDrawable = new ColorDrawable(Color.TRANSPARENT);
+            ((StateListDrawable) mForegroundDrawable).addState(new int[]{android.R.attr.state_pressed}, forceDrawable);
+            ((StateListDrawable) mForegroundDrawable).addState(new int[]{android.R.attr.state_focused}, forceDrawable);
+            ((StateListDrawable) mForegroundDrawable).addState(new int[]{android.R.attr.state_enabled}, normalDrawable);
+            ((StateListDrawable) mForegroundDrawable).addState(new int[]{}, normalDrawable);
+        }
+        if (mForegroundDrawable != null) {
+            mForegroundDrawable.setCallback(this);
+        }
+        a.recycle();
+    }
+
+
+    @Override
+    protected void drawableStateChanged() {
+        super.drawableStateChanged();
+        if (mForegroundDrawable != null && mForegroundDrawable.isStateful()) {
+            mForegroundDrawable.setState(getDrawableState());
+            invalidate();
+        }
+    }
+
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        super.onDraw(canvas);
+        if (mForegroundDrawable != null) {
+            if (getDrawable() != null) {
+                mForegroundDrawable.setBounds(getDrawable().getBounds());
+            } else {
+                mForegroundDrawable.setBounds(mCachedBounds);
+            }
+            mForegroundDrawable.draw(canvas);
+        }
+    }
+
+    @Override
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        super.onSizeChanged(w, h, oldw, oldh);
+        if (mForegroundDrawable != null) mCachedBounds.set(0, 0, w, h);
+    }
+
+}

+ 10 - 0
cs_ninegrid/src/main/java/com/guadou/ninegrid/roundimg/NiceUtils.java

@@ -0,0 +1,10 @@
+package com.guadou.ninegrid.roundimg;
+
+import android.content.Context;
+
+public class NiceUtils {
+    public static int dp2px(Context context, float dipValue) {
+        final float scale = context.getResources().getDisplayMetrics().density;
+        return (int) (dipValue * scale + 0.5f);
+    }
+}

+ 0 - 0
cs_ninegrid/src/main/java/com/guadou/ninegrid/roundimg/NineGridViewWrapper.java


部分文件因为文件数量过多而无法显示