首先先预览一下实现的效果:
红色区域是设置的分割线,可以支持设置分割线的粗度和颜色属性:
实现思路:
1.首先在线性布局里的child中插入分割线view,根据设置的分割线粗和颜色进行设置。
2.增加分割线view的点击事件setontouchlistener,比如,当手指向左移动时,缩小当前分割线左边子view的宽度,增大当前分割线右边子view的宽度,以实现分割线的左右移动和左右子view的横轴改变。联动拖动:当左边拖动到最小值(比如左边的子view 设置的minwidth是10dp)时,会判断左边所有的子view宽度是否达到了最小值,如果没有,则同时减少宽度,实现联动拖动的效果。
全部代码如下:
package com.ng.nguilib
import android.content.context
import android.graphics.color
import android.util.attributeset
import android.view.gravity
import android.view.motionevent
import android.view.view
import android.view.viewgroup
import android.widget.linearlayout
/**
* 描述:可缩放的layout
* @author jzn
* @date 2020/9/9
*/
class zoomlayout constructor(context: context, attrs: attributeset?) : linearlayout(context, attrs) {
//子layout列表
private var mchildlayoutlist: arraylist = arraylistof()
private var mintervallist: arraylist = arraylistof()
//起始点位置
private var mstartx = 0f
private var mstarty = 0f
//位移
private var mintervalx = 0f
private var mintervaly = 0f
//分割线是否添加过
private var hadadd = false
//保存每个子view的宽度
private var mchildwidthlist: arraylist = arraylistof()
private var mchildheightlist: arraylist = arraylistof()
//变化中的子view宽度
private var mrunningxlist: arraylist = arraylistof()
private var mrunningylist: arraylist = arraylistof()
//params
private var mintervallinewidth = 1
private var mintervallinecolor = 1
init {
val ta = context.obtainstyledattributes(attrs, r.styleable.zoomlayout)
mintervallinewidth = context.resources.getdimensionpixeloffset(ta.getresourceid(r.styleable.zoomlayout_intervallinewidth, r.dimen.dd10))
mintervallinecolor = ta.getcolor(r.styleable.zoomlayout_intervallinecolor, color.black)
ta.recycle()
}
override fun onmeasure(widthmeasurespec: int, heightmeasurespec: int) {
super.onmeasure(widthmeasurespec, heightmeasurespec)
refreshchildlist()
addsplit()
refreshchildsizelist()
val maxsize = if (measuredheight > measuredwidth) measuredheight else measuredwidth
//修正分割线宽度
mintervallist.foreachindexed { _, child ->
val lp: viewgroup.layoutparams = child.layoutparams
if (orientation == horizontal) {
lp.height = maxsize
} else if (orientation == vertical) {
lp.width = maxsize
}
child.layoutparams = lp
}
}
//刷新子view数组
private fun refreshchildlist() {
if (mchildlayoutlist.size != childcount) {
mchildlayoutlist.clear()
for (i in 0 until childcount) {
val childview: view = getchildat(i)
mchildlayoutlist.add(childview)
}
}
}
//刷新子view size
private fun refreshchildsizelist() {
if (mchildwidthlist.size != childcount) {
mchildwidthlist.clear()
mchildlayoutlist.foreachindexed { _, child ->
mchildwidthlist.add(child.measuredwidth)
}
mrunningxlist = mchildwidthlist
}
if (mchildheightlist.size != childcount) {
mchildheightlist.clear()
mchildlayoutlist.foreachindexed { _, child ->
mchildheightlist.add(child.measuredheight)
}
mrunningylist = mchildheightlist
}
}
//在子view中设置操作分割线
private fun addsplit() {
if (mchildlayoutlist.size == childcount && !hadadd) {
//在子view的间距中添加操作view
mchildlayoutlist.foreachindexed { index, child ->
if (index < mchildlayoutlist.size - 1) {
addintervalline(index, child)
}
}
hadadd = true
}
}
//增加垂直分割线
private fun addintervalline(number: int, child: view) {
val intervalview = view(context)
intervalview.setbackgroundcolor(mintervallinecolor)
var lp: viewgroup.layoutparams = layoutparams(measuredwidth, mintervallinewidth)
if (orientation == horizontal) {
lp = layoutparams(mintervallinewidth, measuredheight)
} else if (orientation == vertical) {
lp = layoutparams(measuredwidth, mintervallinewidth)
}
intervalview.layoutparams = lp
val targetlocation = intarray(2)
child.getlocationonscreen(targetlocation)
if (orientation == horizontal) {
intervalview.x = targetlocation[0].tofloat()
} else if (orientation == vertical) {
intervalview.y = targetlocation[1].tofloat()
}
val realindex = 1 number * 2
intervalview.setontouchlistener { view, motionevent ->
when (motionevent.action) {
motionevent.action_down -> {
mstartx = motionevent.x
mstarty = motionevent.y
}
motionevent.action_up -> {
refreshchildsizelist()
view.performclick()
}
}
mintervalx = mstartx - motionevent.x
mintervaly = mstarty - motionevent.y
if (orientation == horizontal) {
if (ischildvaluelegal(mrunningxlist[realindex - 1] - mintervalx.toint(), realindex - 1) &&
ischildvaluelegal(mrunningxlist[realindex 1] mintervalx.toint(), realindex 1)
) {
mrunningxlist[realindex - 1] -= mintervalx.toint()
mrunningxlist[realindex 1] = mintervalx.toint()
}
// 联动调整左边
if (!ischildvaluelegal(mrunningxlist[realindex - 1] - mintervalx.toint(), realindex - 1)) {
gravity = gravity.start
var fixmulti = 0
if (realindex - 2 > 0) {
for (index in 0..realindex - 2) {
//这里要判断是否是分割线
if (index % 2 == 0 && ischildvaluelegal(mrunningxlist[index] - mintervalx.toint(), index)) {
mrunningxlist[index] -= mintervalx.toint()
fixmulti
}
}
mrunningxlist[realindex 1] = mintervalx.toint() * fixmulti
}
}
//联动调整右边
if (!ischildvaluelegal(mrunningxlist[realindex 1] mintervalx.toint(), realindex 1)) {
gravity = gravity.end
var fixmulti = 0
for (index in (realindex 2) until childcount) {
if (index % 2 == 0 && ischildvaluelegal(mrunningxlist[index] mintervalx.toint(), index)) {
mrunningxlist[index] = mintervalx.toint()
fixmulti
}
}
mrunningxlist[realindex - 1] -= mintervalx.toint() * fixmulti
}
} else if (orientation == vertical) {
if (ischildvaluelegal(mrunningylist[realindex - 1] - mintervaly.toint(), realindex - 1) &&
ischildvaluelegal(mrunningylist[realindex 1] mintervaly.toint(), realindex 1)) {
mrunningylist[realindex - 1] -= mintervaly.toint()
mrunningylist[realindex 1] = mintervaly.toint()
}
// 联动调整上面
if (!ischildvaluelegal(mrunningylist[realindex - 1] - mintervaly.toint(), realindex 1)) {
gravity = gravity.top
var fixmulti = 0
if (realindex - 2 > 0) {
for (index in 0..realindex - 2) {
if (index % 2 == 0 && ischildvaluelegal(mrunningylist[index] - mintervaly.toint(), index)) {
mrunningylist[index] -= mintervaly.toint()
fixmulti
}
}
mrunningylist[realindex 1] = mintervaly.toint() * fixmulti
}
}
// 联动调整下面
if (!ischildvaluelegal(mrunningylist[realindex 1] mintervaly.toint(), realindex 1)) {
gravity = gravity.bottom
var fixmulti = 0
for (index in (realindex 2) until childcount) {
if (index % 2 == 0 && ischildvaluelegal(mrunningylist[index] mintervaly.toint(), index)) {
mrunningylist[index] = mintervaly.toint()
fixmulti
}
}
mrunningylist[realindex - 1] -= mintervaly.toint() * fixmulti
}
}
mchildlayoutlist.foreachindexed { index, child ->
val childlp: layoutparams = child.layoutparams as layoutparams
childlp.weight = 0f
if (orientation == horizontal) {
childlp.width = mrunningxlist[index]
} else if (orientation == vertical) {
childlp.height = mrunningylist[index]
}
child.layoutparams = childlp
}
//防止左越界
if (mchildlayoutlist.size != 0) {
mchildlayoutlist[0].x = 0f
}
true
}
mintervallist.add(intervalview)
addview(intervalview, realindex, lp)
}
private fun ischildvaluelegal(value: int, index: int): boolean {
val minzoom = if (orientation == horizontal) {
mchildlayoutlist[index].minimumwidth
} else {
mchildlayoutlist[index].minimumheight
}
return value > minzoom
}
}
代码下载和效果预览地址:
https://github.com/jiangzhengnan/nguilib
求start~求fork~
也欢迎提交~