ConstraintLayout을 사용하면 플랫 뷰 계층 구조(중첩 뷰 그룹이 없음)로 크고 복잡한 레이아웃을 만들 수 있습니다.

 

 ConstraintLayout에서 뷰의 위치를 정의하려면 보기의 가로 및 세로 제약조건을 각각 하나 이상 추가해야 합니다. 

각 제약조건은 다른 뷰, 상위 레이아웃 또는 보이지 않는 안내선을 기준으로 한 정렬 또는 연결을 나타냅니다. 

각 제약조건은 세로 또는 가로 축을 따라 뷰의 위치를 정의하므로, 각 뷰에는 축마다 하나 이상의 제약조건이 있어야 합니다.

 

뷰를 Layout Editor에 놓으면 제약조건이 없어도 둔 위치에 그래돌 남습니다. 이는 단지 더 쉽게 편집하도록 한 것이며, 기기에서 레이아웃을 실행할 때 뷰에 제약조건이 없으면 [0,0](맨 위 왼쪽 모서리) 위치에 그립니다.

 

제약조건이 누락되어도 컴파일 오류가 발생하지는 않지만, Layout Editor에서는 누락된 제약조건을 툴바에 오류로 표시합니다. 오류 및 기타 경고를 보려면 Show Warnings and Errors를 클릭하세요. 제약조건이 누락되지 않도록 Layout Editor에서는 자동 연결 및 제약조건 추론 기능을 사용하여 제약조건을 자동으로 추가합니다.

 

ConstraintLayout을 프로젝트에 추가 

프로젝트에서 ConstraintLayout을 사용하려면 다음을 진행합니다.

1. 모듈 수준 build.gradle 파일에 선언된 maven.google.com 저장소가 있는지 확인합니다.

    repositories {
        google
()
   
}

2. 다음 예와 같이 동일한 build.gradle 파일에 종속 항목으로 라이브러리를 추가합니다. 최신버전은 다음 예에 표시된 버전과 다를 수 있습니다.

  dependencies {
    implementation
"androidx.constraintlayout:constraintlayout:2.0.0"
}

3. 툴바 또는 동기화 알림에서 Sync Project with Gradle Files를 클릭합니다.

 

 제약조건 추가 또는 삭제

상위 요소 포지셔닝

그림7. 상위 요소의 가로제약조건

 

뷰의측면을 레이아웃의 대응하는 가장자리로 제한합니다.

 

그림에서 뷰의 왼쪽은 상위 레이아웃의 왼쪽 가장자리에 연결되어 있습니다. 여백을 사용하여 가장자리로부터의 거리를 정의할 수 있습니다.

 

 

 

위치 순서 지정

 

 가로 또는 세로로 두 뷰가 표시되는 순서를 정의합니다.

 

그림에서 B는 항상 A의 오른쪽에 있도록 제한되고 C는 A 아래 있도록 제한됩니다. 그러나 이 제약조건은 정렬을 의미하지 않으므로, B는 여전히 위 아래로 이동할 수 있습니다.

 

 

  

정렬

 

뷰의 가장자리를 다른 뷰의 가장자리에 맞게 정렬합니다.

 

위의 그림에서 B의 왼쪽은 A의 왼쪽에 맞게 정렬됩니다.

뷰의 중심으로 정렬하려면 양쪽에 제약조건을 만듭니다.

 

 

 

 

 

제약조건에서 안쪽으로 보기를 드래그하여 기준에서 벗어나 정렬할 수 있습니다.   

예를 들어 아래 그림에서는 24dp 벗어나 정렬된 B를 보여줍니다.

이와 같은 오프셋은 제한된 뷰의 여백으로 정의됩니다. 

 

정렬할 뷰를 모두 선택하나 후 툴바에서 Align을 클릭하여 정렬 유형을 선택할 수도 있습니다.

 

 

기준선 정렬 

  

뷰의 텍스트 기준선을 다른 뷰의 텍스트 기준선에 맞춥니다.

 

그림에서 B의 첫 번째 줄은 A의 텍스트에 맞게 정렬됩니다.

 

기준선 제약조건을 만들려면 제한할 텍스트 뷰를 마우스 오른쪽 버튼으로 클릭한 다음 Show Baseline을 클릭합니다. 그런다음 텍스트 기준선을 클릭하고 선을 다른 기준선으로 드래그 합니다. 

  

안내선으로 제한 

 

뷰를 제한할 수 있는 세로 또는 가로 안내선을 추가할 수 있습니다. 안내선은 앱 사용자에게 표시되지 않습니다. 레이아웃의 가장자리를 기준으로 dp 단위 또는 백분율을 기반으로 레이아웃에 안내선을 배치할 수 있습니다. 

  

안내선을 만들려면 툴바에서 Guidelines를 클릭한 다음 Add Vertical Gduieline 또는 Add Horizontal Guideline을 클릭합니다.

 

점선을 드래그하여 위치를 변경하고 안내선 가장자리의 원을 클릭하여 측정 모드를 전환합니다.

 

경계선으로 제한 

  

안내선과 비슷하게 경계선은 뷰를 제한하는 데 사용할 수 있는 표시되지 않는 선입니다. 단, 경계선은 자체 위치를 정의하지 않으며, 경계선 내로 제한된 뷰 위치를 기반으로 경계선 위치가 이동됩니다. 뷰를 특정한 하나의 뷰가 아니라 뷰 집합으로 제한하려고 할 때 유용합니다.

 

예를 들어 그림에서는 C가 경계선의 오른쪽으로 제한된다는 것을 보여줍니다. 경계는 A와 B의 끝으로 설정됩니다. 따라서 A 또는 B의 오른쪽 중 맨 오른쪽에 있는 것에 따라 경계선이 이동합니다. 

 

경계선을 만들려면 다음 단계를 따르세요.

 1. 툴바에서 Guidelines를 클릭한 후 Add VerticalBarrier 또는 Add Horizontal Barrier를 클릭합니다.

 

 2. Component Tree 창에서 경계선 내의 원하는 뷰를 선택하여 경계선 구성요소로 드래그합니다.

 

 3. Component Tree에서 경계선을 선택하고 Attributes 창을 연 후 barrierDirection을 설정합니다.

 

이제 다른 뷰에서 경계선으로의 제약조건을 만들 수 있습니다. 

 

제약조건 편향 조정 

뷰의 양쪽에 제약 조건을 추가하면 두 제약 조건 사이의 중심에 뷰가 위치하며 기본적으로 편향은 50%입니다. 

 

뷰 크기 조정 

그림 14. 보기를 선택할 때 Attributes 창에는 1 크기 비율, 2 제약조건 삭제, 3 높이/너비 모드, 4 여백 및 5 제약조건 편향을 제어하는 기능이 포함되어 있습니다. 6 제약조건 목록에서 제약조건을 클릭하여 Layout Editor에서 개별 제약조건을 강조 표시할 수도 있습니다.

 

 그림 14에서 번호 3으로 표시된 기호를 클릭하여 높이와 너비를 계산하는 방법을 변경할 수 있습니다.

 

  • 고정 : 아래 텍스트 상자에서 특정 측정기준을 지정하거나 편집기에서 뷰의 크기를 조정합니다.

 

 

  • 콘텐츠 래핑 : 뷰가 콘텐츠에 맞게 필요한 만큼만 확장됩니다.

 

 

  • 제약조건과 일치 : 뷰가 양쪽의 제약조건에 맞게 최대한 많이 확장됩니다(뷰의 여백을 처리한 후).
    그러나 다음 속성과 값을 사용하여 동작을 수정할 수 있습니다.

  • layout_constraintWidth_default

    • 넓히기 : 양쪽의 제약조건에 맞게 뷰를 최대한 확장합니다. 이것이 기본 동작입니다.

    • 래핑 : 콘텐츠에 맞게 필요한 만큼만 뷰를 확장하지만, 제약조건에 필요하면 여전히 뷰를 그보다 작게 만들 수 있습니다. 따라서 이 모드를 사용하는 것과 콘텐츠 래핑을 사용하는 것의 차이점은 너비를 콘텐츠 래핑으로 설정하면 너비가 항상 콘텐츠 너비와 정확히 일치하는 반면, layout_constraintWidth_default를 래핑으로 설정한 상태에서 제약조건과 일치를 사용하면 뷰가 콘텐츠 너비보다 작아질 수 있습니다.

  • layout_contraintWidth_min

    뷰의 최소 너비에 dp 측정기준을 사용합니다.

  • layout_constraintWidth_max

    뷰의 최대 너비에 dp 측정기준을 사용합니다.

키 프레임 애니메이션

 ConstraintLayout에서 ConstraintSet 및 TransitionManager를 사용하여 요소의 크기와 위치 변경사항을 애니메이션으로 보여줄 수 있습니다.

★ 참고 : TransitionManager는 Android 4.0 (API 레벨 14) 이상용 지원 라이브러리에서 사용할 수 있습니다.

ConstraintSet 는 ConstraintLayout 에 있는 모든 하위 요소의 제약조건, 여백 및 패딩을 나타내는 경량 개체입니다.

ConstraintSet 를 보고있는 ConstraintLayout에 적용하면 레이아웃에서 모든 하위 요소의 제약조건을 업데이트합니다.

 

ConstraintSet 를 사용하여 애니메이션을 빌드하려면 애니메이션의 시작 및 종료 키프레임 역할을 할 두 개의 레이아웃 파일을 지정합니다. 그런다음 두 번째 키프레임 파일에서 ConstraintSet 를 로드하고 보고있는 ConstraintLayout에 적용할 수 있습니다.

 ★ 중요 : ConstraintSet 애니메이션은 하위 요소의 크기와 위치만 애니메이션으로 보여줍니다.
색상과 같은 다른 속성은 애니메이션으로 보여주지 않습니다

간단한 코드 예에서는 단일 버튼을 맨 아래로 이동하는 애니메이션을 만드는 방법을 보여줍니다.

 

layout/keyframe_one.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/constraint_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/button2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:backgroundTint="@android:color/holo_blue_bright"
        android:onClick="animateToKeyframeTwo"
        android:text="Button"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

layout/keyframe_tow.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/constraint_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/button2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:backgroundTint="@android:color/holo_blue_bright"
        android:text="Button"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

 MainActivity.kt

class MainActivity : AppCompatActivity() {

    lateinit var constraintLayout: ConstraintLayout

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.keyframe_one)
        constraintLayout = findViewById(R.id.constraint_layout)
    }

    fun animateToKeyframeTwo(view:View) {
        val constraintSet = ConstraintSet()
        constraintSet.load(this, R.layout.keyframe_two)
        TransitionManager.beginDelayedTransition(constraintLayout)
        constraintSet.applyTo(constraintLayout)
    }
}

실행화면

Reference

ConstraintLayout : developer.android.com/training/constraint-layout?hl=ko

 

'Android > Android Developer' 카테고리의 다른 글

MotionLayout  (0) 2020.12.02
Layout 레이아웃  (0) 2020.12.01

네트워크 상태체크하기

enum class NETWORK_STATUS {
    TYPE_WIFI,
    TYPE_MOBILE,
    TYPE_NOT_CONNECTED
}

class NetworkStatus {
    companion object {

        fun getConnectivityStatus(context: Context): NETWORK_STATUS {
            val manager: ConnectivityManager? =
                context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager

            if (manager != null) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    val networkCapabilities = manager.getNetworkCapabilities(manager.activeNetwork)

                    if (networkCapabilities != null) {
                        if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
                            return NETWORK_STATUS.TYPE_WIFI
                        } else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
                            return NETWORK_STATUS.TYPE_MOBILE
                        }
                    }
                } else {
                    val networkInfo = manager.activeNetworkInfo

                    if (networkInfo != null) {
                        val type = networkInfo.type

                        if(type == ConnectivityManager.TYPE_WIFI) {
                            return NETWORK_STATUS.TYPE_WIFI
                        } else if (type == ConnectivityManager.TYPE_MOBILE) {
                            return NETWORK_STATUS.TYPE_MOBILE
                        }
                    }
                }
            }

            return NETWORK_STATUS.TYPE_NOT_CONNECTED
        }
    }
}

 

387.First Unique Character in a String

 

문제

  • 문자열이 주어지면, 처음으로 반복되지 않은 문자의 인덱스를 찾아라. 반복되지않는 문자가 없다면 -1을 리턴하기

Examples:

    s = "leetcode"

    return 0.

 

    s = "loveleetcode"

    return 2

 

Note

  • 문자열은 모두 소문자라고 가정합니다.

Solution 1. 앞에서부터 비교하기
1번 문자가 다음번째랑 같은지 안같으면 다음과 같은지 비교하다 같으면 2번 문자부터 순차적으로 비교하기
     1......n
      2.....n
       3...n

Solution 2. Map활용하기
문자를 Key, 갯수를 Value로 만들기 ( 1...n )

문자열의 앞의 문자부터 순서대로 Map의 키로 전달해 Value를 확인하여 1인 문자가 나오면 해당 인덱스를 반환한다.

( 1...n )

 

1번의 방법은 너무 많은 반복이 일어날 수 있다. 맨 마지막의 문자가 1번 쓰였을 경우 n번, n-1번, n-2번, ...., 2번, 1번의 경우까지 확인하는 경우도 있어 좋은 방법이라고 생각되지는 않는다.

 

2번의 경우는 문자열을 처음부터 끝까지 2번만 움직여보면 확인할 수 있는 방법이다.

처음에는 Map에 해당 문자별 갯수가 몇개인지 넣어두고

두번째는 문자열의 순서에 맞게 해당 문자의 갯수가 몇개인지 확인하여 해당 문자의 인덱스를 찾으면 된다.

 

Tip

더보기

Map.getOrDefault(key, defaultValue)

  • Key에 아무 값도 할당하지 않을 경우 defaultValue로 설정한 값을 리턴해주는 메서드이다.

아무 값도 할당하지 않았을 때 map[key]를 사용하면 null을 반환하므로 위의 메서드를 활용하면 좋다.

 

 

Code

 

Reference

'Algorightm' 카테고리의 다른 글

[Kotlin] 344.ReverseString [LeetCode]  (0) 2020.04.28
[Level1] 완주하지 못한 선수  (0) 2019.10.24
Hash Algorithm  (0) 2019.10.14
시간복잡도를 알아보자  (0) 2019.07.17

+ Recent posts