一、前言

之前的方法在某些情况下使用会有问题,这个新的类适配了各种情况,可以在线下布局,网格布局,垂直,水平方向上都能实现很好的分隔效果。

二、使用方法详解

  1. val build = IntervalItemDecoration.Builder()
  2. .divider(space)//设置每个 item 之间的间距
  3. // .dividerHorrizontal(space)//设置 item 左右间隔
  4. // .dividerVertical(space)//设置 item 上下间隔
  5. .margin(space)//设置 recyclerview 四周间隔
  6. // .horriontalMargin(space)//设置 recyclerview 左右间隔
  7. // .verticalMargin(space * 2)//设置 recyclerview上下间隔
  8. // .leftMargin(space)//单独设置 recyclerview 左边间隔
  9. // .rightMargin(space)//单独设置 recyclerview 右边间隔
  10. // .topMargin(space)//单独设置 recyclerview 上边间隔
  11. // .bottomMargin(space)//单独设置 recyclerview 下边间隔
  12. .build()

三、详细代码和引入地址

  1. class IntervalItemDecoration private constructor(private val builder: Builder) :
  2. RecyclerView.ItemDecoration() {
  3. //每个 item 上下左右两侧间隔
  4. private var divider = 0
  5. // 每个item左右两侧的间距
  6. private var dividerHorrizontal = 0
  7. // 每个item上下的间距
  8. private var dividerVertical = 0
  9. //整个 recyclerview 间距
  10. private var margin = 0
  11. //整个 recyclerview 左右间距
  12. private var horriontalMargin = 0
  13. //整个 recyclerview 上下间距
  14. private var verticalMargin = 0
  15. // 整个RecyclerView的左间距
  16. private var leftMargin = 0
  17. // 整个RecyclerView的顶部间距
  18. private var topMargin = 0
  19. // 整个RecyclerView的右间距
  20. private var rightMargin = 0
  21. // 整个RecyclerView的底部间距
  22. private var bottomMargin = 0
  23. override fun getItemOffsets(
  24. outRect: Rect,
  25. view: View,
  26. parent: RecyclerView,
  27. state: RecyclerView.State
  28. ) {
  29. super.getItemOffsets(outRect, view, parent, state)
  30. // 得到当前Item在RecyclerView中的位置,从0开始
  31. // 得到当前Item在RecyclerView中的位置,从0开始
  32. val position = parent.getChildAdapterPosition(view)
  33. // 得到RecyclerView中Item的总个数
  34. // 得到RecyclerView中Item的总个数
  35. val count = parent.adapter!!.itemCount
  36. if (parent.layoutManager is GridLayoutManager) { // 网格布局
  37. val gridLayoutManager =
  38. parent.layoutManager as GridLayoutManager?
  39. // 得到网格布局的列数
  40. val spanCount = gridLayoutManager!!.spanCount
  41. // 判断该网格布局是水平还是垂直
  42. if (LinearLayoutManager.VERTICAL == gridLayoutManager.orientation) { // 垂直
  43. if (spanCount == 1) { // 列数为1
  44. verticalColumnOne(outRect, position, count)
  45. } else { // 列数大于1
  46. verticalColumnMulti(outRect, position, count, spanCount)
  47. }
  48. } else if (LinearLayoutManager.HORIZONTAL == gridLayoutManager.orientation) { // 水平
  49. if (spanCount == 1) { // 行数为1
  50. horizontalColumnOne(outRect, position, count)
  51. } else { // 行数大于1
  52. horizontalColumnMulti(outRect, position, count, spanCount)
  53. }
  54. }
  55. } else if (parent.layoutManager is LinearLayoutManager) { // 线性布局
  56. val layoutManager =
  57. parent.layoutManager as LinearLayoutManager?
  58. if (LinearLayoutManager.VERTICAL == layoutManager!!.orientation) { // 垂直
  59. verticalColumnOne(outRect, position, count)
  60. } else if (LinearLayoutManager.HORIZONTAL == layoutManager.orientation) { // 水平
  61. horizontalColumnOne(outRect, position, count)
  62. }
  63. } else if (parent.layoutManager is StaggeredGridLayoutManager) { // 流布局
  64. //TODO 瀑布流布局相关
  65. }
  66. }
  67. /**
  68. * 列表垂直且列数为1
  69. *
  70. * @param outRect 包括左上右下四个参数,分别控制view左上右下的margin
  71. * @param position 当前view所处位置
  72. * @param count RecyclerView中Item的总个数
  73. */
  74. private fun verticalColumnOne(
  75. outRect: Rect,
  76. position: Int,
  77. count: Int
  78. ) {
  79. when (position) {
  80. 0 -> { // 位置为0时(即第一个Item),不设置底部间距
  81. outRect[leftMargin, topMargin, rightMargin] = 0
  82. }
  83. count - 1 -> { // 最后一个Item
  84. outRect[leftMargin, dividerVertical, rightMargin] = bottomMargin
  85. }
  86. else -> { // 中间的Item,不设置底部间距
  87. outRect[leftMargin, dividerVertical, rightMargin] = 0
  88. }
  89. }
  90. }
  91. /**
  92. * 列表垂直且列数大于1
  93. *
  94. * @param outRect 包括左上右下四个参数,分别控制view左上右下的margin
  95. * @param position 当前view所处位置
  96. * @param count RecyclerView中Item的总个数
  97. * @param spanCount 布局的列数
  98. */
  99. private fun verticalColumnMulti(
  100. outRect: Rect,
  101. position: Int,
  102. count: Int,
  103. spanCount: Int
  104. ) {
  105. // 由于是网格布局,故每个item宽度是固定的,这里计算出每个item的左右边距之和
  106. val mEachSpace: Int =
  107. (leftMargin + rightMargin + (spanCount - 1) * dividerHorrizontal) / spanCount
  108. // 通过计算得出总行数
  109. val totalRow = count / spanCount + if (count % spanCount == 0) 0 else 1
  110. // 计算得出当前view所在的行
  111. val row = position / spanCount
  112. val column = position % spanCount
  113. val diff = (mEachSpace - rightMargin - leftMargin) / (spanCount - 1)
  114. val left = (column + 1 - 1) * diff + leftMargin
  115. val right = mEachSpace - left
  116. when (row) {
  117. 0 -> {
  118. outRect[left, topMargin, right] = dividerVertical
  119. }
  120. totalRow - 1 -> {
  121. outRect[left, 0, right] = bottomMargin
  122. }
  123. else -> {
  124. outRect[left, 0, right] = dividerVertical
  125. }
  126. }
  127. }
  128. /**
  129. * 列表水平且行数为1
  130. *
  131. * @param outRect 包括左上右下四个参数,分别控制view左上右下的margin
  132. * @param position 当前view所处位置
  133. * @param count RecyclerView中Item的总个数
  134. */
  135. private fun horizontalColumnOne(
  136. outRect: Rect,
  137. position: Int,
  138. count: Int
  139. ) {
  140. when (position) {
  141. 0 -> { // 位置为0时(即第一个Item)
  142. outRect[leftMargin, topMargin, dividerHorrizontal / 2] = bottomMargin
  143. }
  144. count - 1 -> { // 最后一个Item
  145. outRect[dividerHorrizontal / 2, topMargin, rightMargin] = bottomMargin
  146. }
  147. else -> { // 中间的Item
  148. outRect[dividerHorrizontal / 2, topMargin, dividerHorrizontal / 2] = bottomMargin
  149. }
  150. }
  151. }
  152. /**
  153. * 列表水平且行数大于1
  154. *
  155. * @param outRect 包括左上右下四个参数,分别控制view左上右下的margin
  156. * @param position 当前view所处位置
  157. * @param count RecyclerView中Item的总个数
  158. * @param spanCount 布局的行数
  159. */
  160. private fun horizontalColumnMulti(
  161. outRect: Rect,
  162. position: Int,
  163. count: Int,
  164. spanCount: Int
  165. ) {
  166. // 通过计算得出总列数
  167. val totalColumn = count / spanCount + if (count % spanCount == 0) 0 else 1
  168. // 计算得出当前view所在的列
  169. val column = position / spanCount
  170. // 通过对position加1对spanCount取余得到row
  171. // 保证row等于1为第一行,等于0为最后一个,其它值为中间行
  172. val row = (position + 1) % spanCount
  173. val mEachSpace: Int =
  174. (topMargin + bottomMargin + (spanCount - 1) * dividerVertical) / spanCount
  175. val diff = (mEachSpace - bottomMargin - topMargin) / (spanCount - 1)
  176. val top = (position % spanCount + 1 - 1) * diff + topMargin
  177. val bottom = mEachSpace - top
  178. when (row) {
  179. 1 -> {
  180. outRect[if (column == 0) leftMargin else dividerHorrizontal / 2, top, if (column == totalColumn - 1) rightMargin else dividerHorrizontal / 2] =
  181. bottom
  182. }
  183. 0 -> {
  184. outRect[if (column == 0) leftMargin else dividerHorrizontal / 2, top, if (column == totalColumn - 1) rightMargin else dividerHorrizontal / 2] =
  185. bottom
  186. }
  187. else -> {
  188. outRect[if (column == 0) leftMargin else dividerHorrizontal / 2, top, if (column == totalColumn - 1) rightMargin else dividerHorrizontal / 2] =
  189. bottom
  190. }
  191. }
  192. }
  193. class Builder {
  194. private val iid = IntervalItemDecoration(this)
  195. fun divider(divider: Int): Builder {
  196. iid.divider = divider
  197. return this
  198. }
  199. fun dividerHorrizontal(dividerHorrizontal: Int): Builder {
  200. iid.dividerHorrizontal = dividerHorrizontal
  201. return this
  202. }
  203. fun dividerVertical(dividerVertical: Int): Builder {
  204. iid.dividerVertical = dividerVertical
  205. return this
  206. }
  207. fun margin(margin: Int): Builder {
  208. iid.margin = margin
  209. return this
  210. }
  211. fun horriontalMargin(horriontalMargin: Int): Builder {
  212. iid.horriontalMargin = horriontalMargin
  213. return this
  214. }
  215. fun verticalMargin(verticalMargin: Int): Builder {
  216. iid.verticalMargin = verticalMargin
  217. return this
  218. }
  219. fun leftMargin(leftMargin: Int): Builder {
  220. iid.leftMargin = leftMargin
  221. return this
  222. }
  223. fun topMargin(topMargin: Int): Builder {
  224. iid.topMargin = topMargin
  225. return this
  226. }
  227. fun rightMargin(rightMargin: Int): Builder {
  228. iid.rightMargin = rightMargin
  229. return this
  230. }
  231. fun bottomMargin(bottomMargin: Int): Builder {
  232. iid.bottomMargin = bottomMargin
  233. return this
  234. }
  235. fun build(): IntervalItemDecoration {
  236. initSet()
  237. return iid
  238. }
  239. private fun initSet() {
  240. iid.run {
  241. if (divider != 0) {
  242. dividerHorrizontal = divider
  243. dividerVertical = divider
  244. }
  245. if (margin != 0) {
  246. leftMargin = margin
  247. rightMargin = margin
  248. topMargin = margin
  249. bottomMargin = margin
  250. }
  251. if (verticalMargin != 0) {
  252. topMargin = verticalMargin
  253. bottomMargin = verticalMargin
  254. }
  255. if (horriontalMargin != 0) {
  256. leftMargin = horriontalMargin
  257. rightMargin = horriontalMargin
  258. }
  259. }
  260. }
  261. }
  262. }

StickyDecration