Constraint Layout 소개

|

Constraint Layout

ConstraintLayout은 비교적 최근에 나온 레이아웃 컴포넌트로 현재도 계속 발전되고 있는 레이아웃입니다. 다른 컴포넌트들과 상대적인 위치를 지정할 수 있다는 점에서 RelativeLayout과 비슷한 성격을 갖고 있습니다. 또한 성능도 대부분의 경우에서 RelativeLayout보다 더 좋기 때문에(RelativLayout를 사용할 때는 중첩된 Layout을 사용해야 하는 경우가 많은데, ConstraintLayout은 평면적인(Flat한) 레이아웃을 더 쉽게 만들 수 있습니다.) 새로운 레이아웃을 만들 때는 ConstraintLayout을 한 번쯤 고려해보는 것도 좋을 것 같습니다.


image

특히 ConstraintLayout은 위와 같이 중첩된 레이아웃에서 빛을 발합니다. 상위단의 레이아웃이 수정될 경우 그 안의 레이아웃에 큰 영향을 미치는 경우가 많은데(RelativeLayout은 그런 영향이 적습니다만) ConstraintLayout을 사용하면 그 영향을 상당부분 줄일 수 있습니다.

또한 Layout Editor와 같이 사용하기에도 너무나 좋은 레이아웃입니다. 그동안 RelativeLayout를 비롯한 다른 레이아웃들은 Layout Editor에서 사용하기가 쉽지 않았는데 ConstraintLayout은 아주 자연스럽게 사용할 수 있어서 상당히 좋습니다.

안드로이드 기본 SDK에 포함되어 있지 않아서, 향후 ConstraintLayout이 버전업이 되더라도 기존 프로젝트에 영향을 미치지 않는 점도 장점입니다. gradle 빌드 세팅에서 버전을 명시해놓을 수 있기 때문입니다.

여기에서 더 자세히 확인할 수 있습니다.


속성들

ConstraintLayout의 속성들은 다음과 같이 사용할 수 있습니다.

...
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
...

대충 [source] to [target] of "view"라는 형태의 공식이라고 생각하면 됩니다.

실제로 아래와 같은 레이아웃으로 작성하면 화면 중앙에 버튼이 위치되는 것을 확인할 수 있습니다.

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  tools:context=".MainActivity"
  tools:layout_editor_absoluteY="81dp">

  <Button
    android:id="@+id/button1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Button"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent"/>

</android.support.constraint.ConstraintLayout>

이 상태에서

  app:layout_constraintVertical_bias="0.7"
  app:layout_constraintHorizontal_bias="0.2"

bias 속성을 이용해서 해당 위치의 퍼센트를 조절할 수 있습니다. 위 예제는 세로 70%, 가로 20% 위치에 버튼이 존재하게 됩니다.

또한 이 상태에서

  android:layout_width="0px"
  android:layout_height="0px"

와 같이 컴포넌트의 너비와 높이를 0px로 세팅하게 되면, Match Constraint라고 해서 꽉 채운 크기의 컴포넌트로 설정됩니다.

app:layout_constraintDimensionRatio="16:9"

또는

app:layout_constraintDimensionRatio="h, 16:9"

와 같이 layout_constraintDimensionRatio 비율을 이용해서 가로/세로 비율을 설정할 수 있으며, 이 때 컴포넌트의 너비나 높이 둘 중 하나는 Match Constraint로 설정되어있어야 사용가능합니다.


Animation 효과

Constraint Layout은 컴포넌트의 재배치시 애니메이션 효과를 줄 수 있습니다.

ConstraintSet mConstraintSet1 = new ConstraintSet(); // create a Constraint Set
ConstraintSet mConstraintSet2 = new ConstraintSet(); // create a Constraint Set

mConstraintSet2.clone(context, R.layout.state2); // get constraints from layout
setContentView(R.layout.state1);
mConstraintLayout = (ConstraintLayout) findViewById(R.id.activity_main);
mConstraintSet1.clone(mConstraintLayout); // get constraints from ConstraintSet

TransitionManager.beginDelayedTransition(mConstraintLayout);
mConstraintSet1.applyTo(mConstraintLayout
  • 참고 : http://androidkt.com/constraintlayout-circular-positioning/
  • 참고 : https://www.captechconsulting.com/blogs/starting-out-with-constraint-layout-and-android-studios-visual-editor

Circle Layout 예제

|

Open Source를 이용한 Circle Layout

ArcLayout

ArcLayout은 여기에 공유되어 있습니다.

사용법은 간단합니다. 먼저 gradle에 다음과 같이 세팅합니다.


gradle 세팅

dependencies {
    ...
    implementation 'com.ogaclejapan.arclayout:library:1.1.0@aar'
}


사용법

XML에 레이아웃 설정만해도 사용할 수 있기 때문에 간단합니다.

<com.ogaclejapan.arclayout.ArcLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:arc_axisRadius="120dp"
    app:arc_color="#4DFFFFFF"
    app:arc_freeAngle="false"
    app:arc_origin="center"
    app:arc_radius="140dp"
    app:arc_reverseAngle="false">

    <Button
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:background="#f44336"
        android:gravity="center"
        android:text="A"
        android:textColor="#FFFFFF"
        app:arc_origin="center"/>

    <Button
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:background="#9c27b0"
        android:gravity="center"
        android:text="B"
        android:textColor="#FFFFFF"
        app:arc_origin="center"/>

    <Button
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:background="#3f51b5"
        android:gravity="center"
        android:text="C"
        android:textColor="#FFFFFF"
        app:arc_origin="center"/>

    <Button
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:background="#4caf50"
        android:gravity="center"
        android:text="D"
        android:textColor="#FFFFFF"
        app:arc_origin="center"/>

    <Button
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:background="#ff5722"
        android:gravity="center"
        android:text="E"
        android:textColor="#FFFFFF"
        app:arc_origin="center"/>

    </com.ogaclejapan.arclayout.ArcLayout>

image

레이아웃의 속성을 변경해서 다음과 같이 Arc 형태로 컴포넌트를 배치할 수도 있습니다.

image


Circular-Layout

Circular Layout은 여기에 공유되어 있습니다. 좋아요 개수랑 Fork 수는 얼마되지 않지만, 역시나 사용하기 편리한 오픈소스입니다. 사용법은 다음과 같습니다.


gradle 세팅

dependencies {
    ...
    implementation 'com.github.andreilisun:circular-layout:1.0'
}


사용법

XML에 레이아웃 설정만해도 사용할 수 있기 때문에 간단합니다.

<com.github.andreilisun.circular_layout.CircularLayout
  android:layout_width="220dp"
  android:layout_height="220dp">

  <android.support.v7.widget.SwitchCompat
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

  <ImageView
    android:layout_width="30dp"
    android:layout_height="30dp"
    android:src="@mipmap/ic_launcher" />

  <Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="ok" />

  <CheckBox
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

  <RadioButton
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

  <Chronometer
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

</com.github.andreilisun.circular_layout.CircularLayout>

또한 다음과 같은 형태로 Java 코드내에서 프로그래밍적으로 사용을 할 수도 있습니다.

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final CircularLayout circularLayout = findViewById(R.id.circular_layout);
        int expectedViewsQuantity = 12;
        circularLayout.setCapacity(expectedViewsQuantity);
        for (int i = 0; i < expectedViewsQuantity; i++) {
            TextView textView = (TextView)
                    LayoutInflater.from(this).inflate(R.layout.number_text_view, null);
            textView.setText(String.valueOf(i));
            circularLayout.addView(textView);
        }
    }
}


Circle Layout

Circle Layout은 여기에서 확인할 수 있습니다. 위에서 다룬 Circular Layout보다 좋아요 개수랑 Fork 횟수가 더 많습니다. 사용성은 동일합니다.

gradle 세팅

dependencies {
    ...
    implementation 'io.github.francoiscampbell:circlelayout:0.3.0'
}


사용법

<io.github.francoiscampbell.circlelayout.CircleLayout 
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  cl:cl_angleOffset="90"
  cl:cl_centerView="@+id/centerView"
  cl:cl_direction="clockwise"&rt;

  <Switch
    android:id="@+id/centerView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/&rt;

  <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="12"
    android:textColor="@color/testTextColor"
    android:textSize="@dimen/clockTestSize"/&rt;

  <Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Button"/&rt;

  <CheckBox
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/&rt;

  <SeekBar
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/&rt;

</io.github.francoiscampbell.circlelayout.CircleLayout&rt;

위의 오픈 소스들을 사용하면 손쉽게 원형 레이아웃을 구현할 수 있습니다. 하지만, 최근에 구글에서 ConstraintLayout에도 원형 레이아웃 기능을 집어넣어서 개인적으로는 ConstraintLayout을 활용하는 것이 좀 더 낫지 않나 생각이 듭니다.

Intent를 이용해서 Image Picker 호출

|

Intent를 이용해서 Image Picker 호출

public class MainActivity extends AppCompatActivity {

  private static final int REQUEST_GALLERY = 200;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    findViewById(R.id.btn_gallery).setOnClickListener(mOnClickListener);
  }

  private View.OnClickListener mOnClickListener = new View.OnClickListener() {

    @Override
    public void onClick(View v) {
      switch (v.getId()) {
        case R.id.btn_gallery:
          openGallery();
          break;
      }
    }
  };

  private void openGallery() {
    Intent intent = new Intent();
    intent.setType("image/*");
    intent.setAction(Intent.ACTION_GET_CONTENT);
    startActivityForResult(Intent.createChooser(intent, "Select Picture"), REQUEST_GALLERY);
  }

  @Override
  protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    if (resultCode != RESULT_OK) {
      return;
    }

    switch (requestCode) {
      case REQUEST_GALLERY:
        Uri uri = data.getData();
        
        try {
          GlobalVariable.bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), uri);
        } catch (Exception e) {
          e.printStackTrace();
        }
        Intent intent = new Intent(MainActivity.this, ImageActivity.class);
        startActivity(intent);
        break;
    }
  }
}

Intent를 이용해서 시스템 카메라(Camera) 요청하기

|

Intent를 이용해서 Camera 사용하기

Intent를 이용해서 Camera 기능을 요청하는 코드입니다.

public class MainActivity extends AppCompatActivity {

  private static final int REQUEST_CAMERA = 100;
  
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    findViewById(R.id.btn_camera).setOnClickListener(mOnClickListener);
  }

  private View.OnClickListener mOnClickListener = new View.OnClickListener() {

    @Override
    public void onClick(View v) {
      switch (v.getId()) {
        case R.id.btn_camera:
          launchCameraActivity();
          break;
      }
    }
  };

  private void launchCameraActivity() {
    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    startActivityForResult(intent, REQUEST_CAMERA);
  }

  @Override
  protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    if (resultCode != RESULT_OK) {
      return;
    }

    switch (requestCode) {
      case REQUEST_CAMERA:
        Log.i("", "[snowdeer] REQUEST_CAMERA !!");
        Bundle extras = data.getExtras();
        GlobalVariable.bitmap = (Bitmap) extras.get("data");

        Intent intent = new Intent(MainActivity.this, ImageActivity.class);
        startActivity(intent);
        break;
      
    }
  }
}

Chrome 브라우저 프록시(Proxy) 설정

|

Proxy Setting for Ubuntu Chrome

크롬 브라우저는 기본적으로 Ubuntu 시스템에 설정된 Proxy 설정을 사용합니다. 즉, 브라우저 메뉴에서 Proxy 설정 항목에 가더라도 시스템 Proxy 설정을 따른다는 설명만 나오고 설정할 수 있는 것이 없습니다.

보통은 큰 문제없이 시스템 프록시 설정값을 따라 크롬이 실행되는 경우가 많지만, 가끔씩 (뭐가 꼬인건지 몰라도) 크롬 브라우저가 시스템 프록시 설정값을 사용하지 않는 경우가 있습니다. 이 경우는 다음과 같은 방법을 통해 수동 설정을 해줄 수 있습니다.


터미널에서 사용하는 경우

터미널에서 사용하는 경우 다음과 같은 명령을 이용할 수 있습니다.

$ google-chrome --proxy-server="proxy_address:port"

alias를 이용하면 좀 더 편리하게 사용할 수도 있습니다. (부팅시마다 리셋되기 때문에 .bashrc.profile에 기록해둡시다.)

$ alias google-chrome='google-chrome --proxy-server="proxy_address:port"'


데스크탑에서 사용하는 경우

하지만, 대부분은 데스크탑에서 크롬을 실행할 가능성이 높기 때문에 데스크탑 바로가기 설정을 바꿔줘야 합니다.

$ sudo nano /usr/share/applications/google-chrome.desktop

여기에서 Exec로 실행하는 부분을 찾아서 전부 --proxy-server="proxy_address:port" 옵션을 달아주면 됩니다.