1,系統自帶的間割線
系統自帶的間割線實現方法很簡單,看下面的代碼:
rv_content.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
rv_content.adapter = rcAdapter
rv_content.addItemDecoration(DividerItemDecoration(this, DividerItemDecoration.VERTICAL))
這樣就實現了間割線的添加,效果如下:
上面的效果,是將方向設置為:LinearLayoutManager.VERTICAL
,那么將方向設置為LinearLayoutManager.HORIZONTAL
,此時效果為:
上面的顯示方式為LinearLayoutManager
,那么將顯示方式設置為GridLayoutManager
時,也就是:
rv_content.layoutManager = GridLayoutManager(this, 3,GridLayoutManager.VERTICAL, false)
此時的效果為:
此時,應該察覺到,系統提供的間隔線類DividerItemDecoration
只能適用于一些簡單的情形。當布局復雜時,系統的間隔線就不能滿足我們的要求了,此時我們就要自己動手來寫一個自己的間隔線或者使用第三方的間隔線。
2, 自定義間隔線
通過閱讀代碼,我們可以發現系統間割線DividerItemDecoration
是繼承RecyclerView.ItemDecoration
并實現了onDraw()
和getItemOffsets()
方法 。
那么我們照著DividerItemDecoration
來寫自己的間隔線類MyItemDecoration
,代碼如下:
class MyItemDecoration(context: Context) : RecyclerView.ItemDecoration(){
private var mOrientation: Int? = null
private var dividerLine: Drawable? = null
init {
val typedArray = context.obtainStyledAttributes(ATTRS)
dividerLine = typedArray!!.getDrawable(0)
typedArray.recycle()
}
override fun onDraw(c: Canvas?, parent: RecyclerView?, state: RecyclerView.State?) {
drawHorizontalLine(c, parent, state)
drawVerticalLine(c, parent, state)
}
override fun getItemOffsets(outRect: Rect?, view: View?, parent: RecyclerView?, state: RecyclerView.State?) {
val spanCount = getSpanCount(parent)
val childCount = parent!!.adapter.itemCount
val itemPosition = ((view!!.layoutParams)as RecyclerView.LayoutParams).viewLayoutPosition
if (isLastRow(parent, itemPosition, spanCount, childCount)){
outRect!!.set(0, 0, dividerLine!!.intrinsicWidth, 0)
}else if (isLastColum(parent, itemPosition, spanCount, childCount)){
outRect!!.set(0, 0, 0, dividerLine!!.intrinsicHeight)
}else{
outRect!!.set(0, 0, dividerLine!!.intrinsicWidth, dividerLine!!.intrinsicHeight)
}
}
/**
* 畫豎線
*/
private fun drawVerticalLine(c: Canvas?, parent: RecyclerView?, state: RecyclerView.State?) {
for (i in 0..(parent!!.childCount - 1)){
val child: View = parent.getChildAt(i)
//獲取child布局參數
val params: RecyclerView.LayoutParams = child.layoutParams as RecyclerView.LayoutParams
val left = child.right + params.rightMargin
val right = left + dividerLine!!.intrinsicWidth
val top = child.top - params.topMargin
val bottom = child.bottom + params.bottomMargin
dividerLine!!.setBounds(left, top, right, bottom)
dividerLine!!.draw(c)
}
}
/**
* 畫橫線
*/
private fun drawHorizontalLine(c: Canvas?, parent: RecyclerView?, state: RecyclerView.State?) {
for (i in 0..(parent!!.childCount - 1)){
val child: View = parent.getChildAt(i)
val params: RecyclerView.LayoutParams = child.layoutParams as RecyclerView.LayoutParams
val left = child.left - params.leftMargin
val right = child.right + params.rightMargin+ dividerLine!!.intrinsicWidth
val top = child.bottom + params.bottomMargin
val bottom = top + dividerLine!!.intrinsicHeight
dividerLine!!.setBounds(left, top, right, bottom)
dividerLine!!.draw(c)
}
}
/**
* 獲取列數
*/
private fun getSpanCount(parent: RecyclerView?): Int{
var spanCount: Int = -1
val layoutManager: RecyclerView.LayoutManager = parent!!.layoutManager
if (layoutManager is GridLayoutManager){
spanCount = layoutManager.spanCount
}else if(layoutManager is StaggeredGridLayoutManager){
spanCount = layoutManager.spanCount
}
return spanCount
}
/**
* 判定是否為最后一列
*/
private fun isLastColum(parent: RecyclerView?, pos: Int, spanCount: Int, childCount: Int): Boolean{
val layoutManager: RecyclerView.LayoutManager = parent!!.layoutManager
if (layoutManager is GridLayoutManager){
if ((pos + 1)% spanCount == 0) {//如果是最后一列,則不在繪制右邊
return true
}
}else if(layoutManager is StaggeredGridLayoutManager){
val orientation = layoutManager.orientation
if (orientation == StaggeredGridLayoutManager.VERTICAL){
if ((pos + 1)% spanCount == 0) {//如果是最后一列,則不在繪制右邊
return true
}
}else{
val childNum = childCount - childCount % spanCount
if (pos >= childNum) {
return true
}
}
}
return false
}
/**
* 判定是否為最后一行
*/
private fun isLastRow(parent: RecyclerView?, pos: Int, spanCount: Int, childCount: Int): Boolean{
val layoutManager: RecyclerView.LayoutManager = parent!!.layoutManager
if (layoutManager is GridLayoutManager){
val childNum = if(childCount % spanCount == 0) childCount - spanCount else childCount - childCount % spanCount
if (pos >= childNum) {//如果是最后一行,則不在繪制底邊
return true
}
}else if(layoutManager is StaggeredGridLayoutManager){
val orientation = layoutManager.orientation
if (orientation == StaggeredGridLayoutManager.VERTICAL){//縱向滾動
val childNum = childCount - childCount % spanCount
if (pos >= childNum) {//如果是最后一行,則不在繪制底邊
return true
}
}else{//橫向滾動
if ((pos + 1) % spanCount == 0) {
return true
}
}
}
return false
}
companion object{
private var ATTRS = intArrayOf(android.R.attr.listDivider)
}
}
運行程序,看效果圖為:
3,第三方分割線
請參考:
github地址:[Y_DividerItemDecoration]:(https://github.com/yanyusong/Y_DividerItemDecoration)
下面來看看對這個第三方jar包的簡單使用示例:
實現這個效果也很簡單,代碼為:
class RecyclerViewNewListDividerActivity: BaseKotlinActivity(){
private var mAdapter: Y_MultiRecyclerAdapter? = null
private var y_ItemEntityList: Y_ItemEntityList? = null
private var context: Context = this
override fun getLayoutResoucesId(): Int {
return R.layout.activity_recycler_view_simple
}
override fun init() {
y_ItemEntityList = Y_ItemEntityList()
initToolBarScroll()
y_ItemEntityList!!.addItems(R.layout.item_rc_4st, itemList).addOnBind(R.layout.item_rc_4st
, object : Y_OnBind<String>{
override fun onBindChildViewData(holder: GeneralRecyclerViewHolder?, itemData: String?, position: Int) {
holder!!.setText(R.id.tv, itemData)
}
})
rv_content.layoutManager = GridLayoutManager(this, 2, GridLayoutManager.VERTICAL, false)//設置顯示方式--瀑布流
mAdapter = Y_MultiRecyclerAdapter(this, y_ItemEntityList)
rv_content.adapter = mAdapter
/**
* 第三方----子項之間的分割線位置
*/
rv_content.addItemDecoration(MyDividerItemDecoration(this))
mAdapter!!.setOnItemClickListener { position -> showToast("onClick-->"+ position) }
}
private fun initToolBarScroll() {
val param: AppBarLayout.LayoutParams = tb_toolbar.layoutParams as AppBarLayout.LayoutParams
param.scrollFlags = AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL or AppBarLayout.LayoutParams.SCROLL_FLAG_EXIT_UNTIL_COLLAPSED
}
class MyDividerItemDecoration(val context: Context): Y_DividerItemDecoration(context) {
override fun getDivider(itemPosition: Int): Y_Divider {
var divider: Y_Divider? = null
when(itemPosition) {
else -> {
/**
* 設置底部線
* setBottomSideLine(boolean isHave, @ColorInt int color, float widthDp, float startPaddingDp, float endPaddingDp)
* isHave:true 顯示線;false 不顯示
* color:線的顏色。@ColorInt int color 表示這里需要的是一個顏色值,而不是顏色id。因此直接使用R.color.XXX是不行的,可以通過ContextCompat.getColor(context, R.color.black)來獲取
* widthDp:線的高度
* startPaddingDp:距離左邊多少dp開始畫線
* endPaddingDp:距離右邊多少dp停止畫線
*/
val count = if(itemList.size%2==0) itemList.size - 2 else itemList.size - itemList.size%2
if (itemPosition >= count){
if (itemPosition % 2 == 0){
divider = Y_DividerBuilder().setRightSideLine(true, ContextCompat.getColor(context, R.color.colorAccent), 2F, 0F, 0F)
.create()
}else{
divider = Y_DividerBuilder().setBottomSideLine(true, ContextCompat.getColor(context, R.color.trans), 2F, 0F, 0F).create()
}
}else{
if (itemPosition % 2 == 0){
divider = Y_DividerBuilder().setRightSideLine(true, ContextCompat.getColor(context, R.color.colorAccent), 2F, 0F, 0F)
.setBottomSideLine(true, ContextCompat.getColor(context, R.color.black), 2F, 0F, 0F).create()
}else{
divider = Y_DividerBuilder().setBottomSideLine(true, ContextCompat.getColor(context, R.color.black), 2F, 0F, 0F).create()
}
}
}
}
return divider!!
}
}
companion object{
// private val itemList = listOf("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "W", "X", "Y", "Z", "Z")
private val itemList = listOf("a", "b", "c", "d", "e")
}
}
上面這個效果的關鍵代碼都在Y_DividerItemDecoration
類的getDivider
方法中,這個jar包中,給提供了設置上下左右線的方法,使用起來并不復雜。
在看下圖效果:
這個效果實現的關鍵就是每行的列數,有1列的,2列的,3列的,4列的幾種,看列數獲取的方法:
/**
* 這里的“12”總共的列數,因為布局列數不定,有1,2,3,4幾種,這樣只有取得它們的公倍數,才能使計算方便
*/
val layoutManager = GridLayoutManager(this, 12, GridLayoutManager.VERTICAL, false)//設置顯示方式
layoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup(){
override fun getSpanSize(position: Int): Int {
if (position == 0 || position == 1) {
return 6
} else if (position == 6 || position == 10) {
return 12
} else if (position in 7..9) {
return 4
} else if (position in 2..5) {
return 3
}
return 3
}
}
rv_content.layoutManager = layoutManager
getDivider
方法的實現:
class MyNewDividerItemDecoration(val context: Context): Y_DividerItemDecoration(context) {
override fun getDivider(itemPosition: Int): Y_Divider {
var divider: Y_Divider? = null
if (itemPosition in 1..6 || itemPosition == 9 || itemPosition == 10) {
divider = Y_DividerBuilder()
.setBottomSideLine(true, ContextCompat.getColor(context, R.color.colorAccent), 2f, 0f, 0f)
.create()
} else if (itemPosition == 0 || itemPosition == 7 || itemPosition == 8) {
divider = Y_DividerBuilder()
.setRightSideLine(true, ContextCompat.getColor(context, R.color.black), 2f, 0f, 0f)
.setBottomSideLine(true, ContextCompat.getColor(context, R.color.colorAccent), 2f, 0f, 0f)
.create()
} else if (itemPosition in 11..21) {
when ((itemPosition - 10) % 4) {
1, 2, 3 -> {
divider = Y_DividerBuilder()
.setRightSideLine(true, ContextCompat.getColor(context, R.color.black), 2f, 0f, 0f)
.setBottomSideLine(true, ContextCompat.getColor(context, R.color.colorAccent), 2f, 0f, 0f)
.create()
}
0 -> {
divider = Y_DividerBuilder()
.setBottomSideLine(true, ContextCompat.getColor(context, R.color.colorAccent), 2f, 0f, 0f)
.create()
}
else -> {
divider = Y_DividerBuilder().setBottomSideLine(true, ContextCompat.getColor(context, R.color.trans), 2F, 0F, 0F).create()
}
}
}
return divider!!
}
}
關于RecyclerView的分割線,下一篇寫RecyclerView的條目動畫
參考文檔
1,[Android RecyclerView 使用完全解析 體驗藝術般的控件]:http://blog.csdn.net/lmj623565791/article/details/45059587
2,間隔線第三方github地址:[Y_DividerItemDecoration]:https://github.com/yanyusong/Y_DividerItemDecoration