물에 살고싶은 개발자

[Kotlin] ConstraintLayout 동적으로 제약조건 변경하는 방법 본문

Android

[Kotlin] ConstraintLayout 동적으로 제약조건 변경하는 방법

돼지사랑 2020. 10. 16. 18:28

언제나 그랫듯 선결론! 아래 예제처럼 하면된다.

주의!! 이 방법을 사용하기 위해서는 예제에 있는 constraintLayout의 하위뷰에 모두 id를 세팅해줘야 한다. 안그럼 에러난다.


val constraints = ConstraintSet()
constraints.clone(constraintLayout)
constraints.connect(
mainView.id,
ConstraintSet.TOP,
TargetView.id,
ConstraintSet.BOTTOM,
convertDpToPixel(10f, context)
)
constraints.applyTo(constraintLayout)



안드로이드로 앱을 만들다보면 ConstraintLayout을 많이 사용한다. 

그러다보면 자연스레 동적으로(코틀린 혹은 자바에서) 이 제약조건을 변경해주고자 하는 경우가 생긴다.

이게 뭐 특별한건 아니고 아래처럼 xml에서 정의되어있는 constraint 옵션들을 바꿔주는 것이다.

<ImageView
android:id="@+id/Iv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/image"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="parent" />


부연설명을 조금 하자면 xml에선 layout_constraint[]_to[]Of 형식으로 되어있는데 위 예제처럼 [] 에 위치하게 될 

Start,End,Top,Bottom들만 알맞게 넣어주면 된다.


헷갈리는 사람이 있을까봐 좀더 덧붙이면, 앞에 있는 []에는 주체가 되는 앱. 그러니까 위 예제에선 Iv라는 아이디를 가진 ImageView를 의미한다.

그 뒤에 toStartOf는 "parent"에 들어갈 대상이 된다. 즉 ImageView의 Start(뷰의 왼쪽)을 parent(ImageView가 포함된 ConstraintLayout)의 Start(뷰의 오른쪽)에 세팅한다는 의미이다.


여기에 뭐 마진을 몇씩 넣어주면 적절하게 앱의 디자인을 만들수있다.


아무튼 기초설명은 됏고 그래서 제일 처음에 코틀린 예제를 다시 설명하자면,

여기도 길어서그렇지 특별할건 없다.


val constraints = ConstraintSet()
constraints.clone(constraintLayout)
constraints.connect(
mainView.id,
ConstraintSet.TOP,
TargetView.id,
ConstraintSet.BOTTOM,
convertDpToPixel(10f, context)
)
constraints.applyTo(constraintLayout)


mainView가 주체가 될 뷰(위 xml 예제에서의 ImageView) 

TargetView가 대상이 되는 뷰(위 xml 예제에서의 ImageView가 포함된 ConstraintLayout)


라고 생각하고 세팅을 하면 된다. 

두번째 파라미터인 ConstraintSet.TOP 이부분은 주체가 될 mainView의 TOP(뷰의 윗쪽)을 의미하고

네번째파라미터인 ConstraintSet.BOTTOM은 대상이 되는 TargetView의 BOTTOM(뷰의 아랫쪽)을 의미한다.

그리고 마지막 파라미터는 margin값인데, 저기에 그냥 정수를 때려넣으면 일반적으로 사용하는 dp값이 아닌 pixcel값으로 세팅이 되기 때문에

내가 사용하는 dp를 픽셀로 바꿔주는 유틸성 Method를 사용했다. 


예제의 두번째줄인 constraint.clone() 에서는 제약조건을 바꿀 뷰가 있는 상위뷰를 넣어주면 된다.


또한 맨 위에서 얘기했던것처럼 clone 할 constraintLayout의 모든 하위 뷰에 아이디가 다 세팅되어있는지도 체크해주자.


끝!!


Ps. 그냥 가면 아쉬울거같으니 예제에서 사용한 유틸도 함께 공유한다.

fun convertDpToPixel(dp: Float, context: Context): Int {
return (dp * (context.resources
.displayMetrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT)).toInt()
}

보너스로 픽셀->dp

fun convertPixelsToDp(px: Float, context: Context): Float {
return px / (context.resources
.displayMetrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT)
}



진짜 끗

Comments