손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손

5313 단어
손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손 손
키워드: kotlin, custom, ViewGroup
custom view group 쓰기 프로세스
1. override onLayout
우선 가장 직감적인 방법은 적는 것이다public class CustomViewGroup extends ViewGroup {}.kotlin에 대해서는 class CustomViewGroup : ViewGroup {}입니다.그리고 컴파일러의 제시에 따라 우리는 onLayout 방법을 실현한다.그럼 이onLayout의 역할은 무엇일까요?
소스 코드를 간단히 살펴보면 View의 소스 코드에 대한 답이 표시됩니다.
public void layout(int l, int t, int r, int b) {
    // ...
    if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) {
        // ...    
        onLayout(changed, l, t, r, b);
        // ...     
    }
    // ...

이 코드는 onLayoutlayout 방법에서 호출되었다는 것을 알려준다.명명된 각도에서 보면 on는 언제 나타날지 나타낸다.유사한 것은 사용자 정의view를 쓸 때 자주 쓰는 onMeasuremeasure 방법에서 호출된 것이다.그렇게 똑똑한 독자님, 저희가activity를 쓸 때 쓴 onCreate 방법도Activitycreate에서 사용한 거 아니에요?
하하, 물론 아니지.onCreate는Activity의 performCreate 방법에서 호출된 것이다.그러나 원리는 유사하다onXxx는 모두 실제xxx를 할 때 호출된다.이 xxx 방법들은 기본적으로final이다.
본전으로 돌아가다.이것onLayout의 용도는 무엇입니까?onLayout 함수는 layout 함수에서 호출되는데 자연히 레이아웃과 관련된 논리를 처리하는 것이다.함수 서명 보기:
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int)

네 개의 매개 변수left,top,right,bottom은 우리에게 경계를 그려준 것과 같다. 우리는 이 화포에 그림을 그릴 것이다. 초과할 수 없다.이후 우리onLayout의 논리는 우리의Custom View Group의children을 어떻게 배열하는가이다.이것은 업무에 따라 해야 한다.단지 테스트를 위해서라면, 우리는 간단하게 그들을 하나하나 빈틈없이 배열할 수 있다.우리가 onLayout를 다 쓴 후에 프로젝트를 실행합니다.사고가 나지 않으면 우리는 아무것도 볼 수 없다.왜?왜냐하면 우리는 아직 매우 중요한 부분인 측량이 없어졌기 때문이다.
2. override onMeasure
컴파일러는 override on Layout이 필요하다는 것만 알려줬지만 overrid on Measure가 필요하다는 것은 알려주지 않았다.자세히 생각해 보면 디스플레이 생활에서 만약에 우리가 2d의 종이를 가지고 자view를 그리려고 한다면 우리는 나의 자view의 배열 방식만 알고 있을 뿐이다. 반드시 먼저 다른 사람에게 우리의 종이의 크기를 알려줘야 우리가 그림을 그릴 수 있다.onMeasure는 Custom View Group의parent에 우리가 필요로 하는 크기를 설명하는 작업을 했습니다.
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {

    val width = getSize(defaultSize = 300, measureSpec = widthMeasureSpec)
    val height = getSize(defaultSize = 300, measureSpec = heightMeasureSpec)

    measureChildren(widthMeasureSpec, heightMeasureSpec)

    setMeasuredDimension(width, height)
}

그 중에서 measureChildren(widthMeasureSpec, heightMeasureSpec)는 귀속지 measure 서브뷰 작업을 완성했다.마지막 문장setMeasuredDimension(width, height)은 매우 중요하다. 모든 onMeasure 방법은 그것을 현저하게 호출해야 한다.
3. 코드 올리기
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {

    val width = getSize(defaultSize = 300, measureSpec = widthMeasureSpec)
    val height = getSize(defaultSize = 300, measureSpec = heightMeasureSpec)

    measureChildren(widthMeasureSpec, heightMeasureSpec)

    setMeasuredDimension(width, height)
}

override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
    var currentTop = 0
    var currentLeft = 0
    var currentRowHeight = 0
    for (i in 0..childCount) {
        val child = getChildAt(i) ?: continue
        val childWidth = child.measuredWidth
        val childHeight = child.measuredHeight

        // child   width or height     parent   width   height,    
        if (childWidth > measuredWidth
                || childHeight > measuredHeight) {
            continue
        }

        if (currentTop + childHeight > measuredHeight) {
            continue
        }

        if (currentLeft + childWidth > measuredWidth) {
            currentLeft = 0
            currentTop += currentRowHeight
            currentRowHeight = 0
        }

        if (currentLeft + childWidth <= measuredWidth
                && currentTop + childHeight <= measuredHeight) {

            child.layout(currentLeft, currentTop, currentLeft + childWidth, currentTop + childHeight)

            currentLeft += childWidth
            if (childHeight > currentRowHeight) {
                currentRowHeight = childHeight
            }
        }

    }
}


private fun getSize(defaultSize: Int, measureSpec: Int): Int {

    val size = MeasureSpec.getSize(measureSpec)
    val mode = MeasureSpec.getMode(measureSpec)

    when (mode) {
        MeasureSpec.EXACTLY -> {
            return size
        }

        MeasureSpec.AT_MOST -> {
            return Math.min(size, defaultSize)
        }

        MeasureSpec.UNSPECIFIED -> {
            return defaultSize
        }

        else -> {
            return defaultSize
        }
    }
}

코드에서 layout child의 핵심 문장은 다음과 같습니다.
child.layout(currentLeft, currentTop, currentLeft + childWidth, currentTop + childHeight)

4. 소결
Custom View Group을 작성할 때 이 몇 가지 작업을 한 번에 수행해야 합니다.
  • override onMeasure
  • measureChildren(widthMeasureSpec, heightMeasureSpec)
  • setMeasuredDimension(width, height)

  • override onLayout
  • 당신이 필요로 하는 업무 논리 정리
  • child.layout(currentLeft, currentTop, currentLeft + childWidth, currentTop + childHeight)

  • 좋은 웹페이지 즐겨찾기