๊ด€๋ฆฌ ๋ฉ”๋‰ด

Welcome! Everything is fine.

[Android] ๋ ˆ์ด์•„์›ƒ ๊ธฐ์ดˆ ๋ณธ๋ฌธ

Android

[Android] ๋ ˆ์ด์•„์›ƒ ๊ธฐ์ดˆ

๊ฐœ๋ฐœ๊ณฐ๋ฐœ 2022. 2. 17.
728x90

๐Ÿ“Œ ์ œ์•ฝ ์กฐ๊ฑด ์ดํ•ดํ•˜๊ธฐ

์•ˆ๋“œ๋กœ์ด๋“œ ๊ธฐ๋ณธ ๋ ˆ์ด์•„์›ƒ์€ ์ œ์•ฝ ๋ ˆ์ด์•„์›ƒ(Constraint Layout)์ด๋‹ค. ์ œ์•ฝ ๋ ˆ์ด์•„์›ƒ์ด๋ž€ ๋ทฐ์˜ ์œ„์น˜๋ฅผ ๊ฒฐ์ •ํ•  ๋•Œ ์ œ์•ฝ ์กฐ๊ฑด์„ ์‚ฌ์šฉํ•˜๋Š” ๋ ˆ์ด์•„์›ƒ์ด๋‹ค.

  • ์ œ์•ฝ ์กฐ๊ฑด(Constraint) : ๋ทฐ๊ฐ€ ๋ ˆ์ด์•„์›ƒ ์•ˆ์˜ ๋‹ค๋ฅธ ์š”์†Œ์™€ ์–ด๋–ป๊ฒŒ ์—ฐ๊ฒฐ๋˜๋Š”์ง€ ์•Œ๋ ค์ฃผ๋Š” ๊ฒƒ. ๋ทฐ์˜ ์—ฐ๊ฒฐ์ (Anchor Point)๊ณผ ๋Œ€์ƒ(Target) ์—ฐ๊ฒฐ.
  • ๋ถ€๋ชจ ๋ ˆ์ด์•„์›ƒ(Parent LAyout) : ์˜ˆ๋ฅผ ๋“ค๋ฉด, ๋ฒ„ํŠผ์˜ ์ž…์žฅ์—์„œ ์ž์‹ ์„ ๊ฐ์‹ธ๊ณ  ์žˆ๋Š” ๋ ˆ์ด์•„์›ƒ.

๋‹ค์Œ์€ ์ œ์•ฝ ์กฐ๊ฑด์„ ์ ์šฉํ•œ ๋ชจ์Šต์ด๋‹ค. ๋ฒ„ํŠผ ์ƒ/ํ•˜/์ขŒ/์šฐ์— ์žˆ๋Š” ๋™๊ทธ๋ž€ ์—ฐ๊ฒฐ์ (ํ•ธ๋“ค)์„ ๋งˆ์šฐ์Šค๋กœ ์žก์•„๋Œ์–ด ๋ถ€๋ชจ ๋ ˆ์ด์•„์›ƒ๊ณผ ์—ฐ๊ฒฐํ–ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ๋ถ€๋ชจ ๋ ˆ์ด์•„์›ƒ์ด ์—ฐ๊ฒฐ ํƒ€๊นƒ์ด ๋œ ๊ฒƒ์ด๋‹ค. ์ด๋ ‡๊ฒŒ ์—ฐ๊ฒฐ์ ๊ณผ ํƒ€๊นƒ์„ ์—ฐ๊ฒฐํ–ˆ๋‹ค๋ฉด ์—ฐ๊ฒฐ์ ์ด ํŒŒ๋ž€์ƒ‰์œผ๋กœ ๋ฐ”๋€Œ๋ฉฐ ์—ฐ๊ฒฐ์„ ์ด ์ƒ๊ธด๋‹ค. ์—ฌ๊ธฐ์„œ ๊ธฐ์–ตํ•ด์•ผํ•  ์ ์€ ๋ ˆ์ด์•„์›ƒ ์•ˆ์—์„œ ๋ฒ„ํŠผ์˜ ์œ„์น˜๋ฅผ ๊ฒฐ์ •ํ•˜๋ ค๋ฉด ์ ์–ด๋„ ์™ผ์ชฝ๊ณผ ์œ„์ชฝ์— ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์–ด์•ผ ํ•œ๋‹ค๋Š” ์ ์ด๋‹ค. ์ฆ‰, ๊ผญ ํ•„์š”ํ•œ ์ œ์•ฝ ์กฐ๊ฑด์€ ๋‘ ๊ฐœ๋ฉด ๋œ๋‹ค. 

โœ” ํƒ€๊นƒ์ด ๋  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ

  • ๊ฐ™์€ ๋ถ€๋ชจ ๋ ˆ์ด์•„์›ƒ ์•ˆ์— ๋“ค์–ด ์žˆ๋Š” ๋‹ค๋ฅธ ๋ทฐ์˜ ์—ฐ๊ฒฐ์ 
  • ๋ถ€๋ชจ ๋ ˆ์ด์•„์›ƒ์˜ ์—ฐ๊ฒฐ์ 
  • ๊ฐ€์ด๋“œ๋ผ์ธ

โœ” ์—ฐ๊ฒฐ์ ์ด ๋  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ

  • ์œ„์ชฝ(Top), ์•„๋ž˜์ชฝ(Bottom), ์™ผ์ชฝ(Left/Start), ์˜ค๋ฅธ์ชฝ(Right/End)
  • ๊ฐ€๋กœ์ถ•์˜ ๊ฐ€์šด๋ฐ(CenterX), ์„ธ๋กœ์ถ•์˜ ๊ฐ€์šด๋ฐ(CenterY)
  • ๋ฒ ์ด์Šค๋ผ์ธ(ํ…์ŠคํŠธ๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ๋ทฐ์ธ ๊ฒฝ์šฐ์—๋งŒ ์ ์šฉ)

์˜ค๋ฅธ์ชฝ ์†์„ฑ์ฐฝ์— ๋‹ค์Œ๊ณผ ๊ฐ™์ด Constraint Widget์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ์—ฐ๊ฒฐ์„ ์˜ ์ ํ˜€์žˆ๋Š” ๋งˆ์ง„(Margin)์„ ์กฐ์ ˆํ•˜์—ฌ ๊ฑฐ๋ฆฌ๋ฅผ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

  • ๋งˆ์ง„(Margin) : ์—ฐ๊ฒฐ์ ๊ณผ ํƒ€๊นƒ๊ณผ์˜ ๊ฑฐ๋ฆฌ. ์ˆซ์ž๋ฅผ ์ž…๋ ฅํ•˜๊ฑฐ๋‚˜ ๊ฐ์ฒด๋ฅผ ์ง์ ‘ ์›€์ง์—ฌ์„œ ์กฐ์ ˆํ•  ์ˆ˜ ์žˆ์Œ. 

๐Ÿ“Œ ํ™”๋ฉด ๊ฐ€์šด๋ฐ์— ๋ทฐ ๋ฐฐ์น˜ํ•˜๊ธฐ

๋””์ž์ธ ํ™”๋ฉด ์ƒ๋‹จ์— ์žˆ๋Š” ์ž์„ ๋ชจ์–‘์˜ ์•„์ด์ฝ˜(Autoconnection)์„ ํ™œ์„ฑํ™” ์‹œํ‚ค๋ฉด ๋ฒ„ํŠผ์„ ๊ฐ€์šด๋ฐ์— ๋†จ์„ ๋•Œ, ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ฒ„ํŠผ์˜ ๋ชจ๋“  ์—ฐ๊ฒฐ์ ์ด ์ž๋™์œผ๋กœ ์—ฐ๊ฒฐ๋œ๋‹ค.

๋งŒ์•ฝ ์ •ํ™•ํžˆ ํ•œ๊ฐ€์šด๋ฐ๊ฐ€ ์•„๋‹ˆ๋ผ ์–ด๋Š ํ•œ ์ชฝ์œผ๋กœ ์น˜์šฐ์น˜๊ฒŒ ๋งŒ๋“ค๊ณ  ์‹ถ๋‹ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผํ• ๊นŒ? ์˜ค๋ฅธ์ชฝ ์†์„ฑ์ฐฝ์—์„œ ์„ธ๋กœ ๋ฐฉํ–ฅ ๋ฐ”์ด์–ด์Šค(Vertical Bias)์™€ ๊ฐ€๋กœ ๋ฐฉํ–ฅ ๋ฐ”์ด์–ด์Šค(Horizontal Bias)๋ฅผ ์กฐ์ ˆํ•˜๋ฉด ๋œ๋‹ค. ์ฆ‰, ํ™”๋ฉด์„ ๋น„์œจ๋กœ ๋‚˜๋ˆˆ ํ›„ ์–ด๋Š ๊ณณ์— ์œ„์น˜ ์‹œํ‚ฌ์ง€ ๊ฒฐ์ •ํ•˜๋Š” ๊ฐ’์ด๋‹ค.

์†์„ฑ ์ฐฝ์„ ๋” ์ž์„ธํžˆ ์‚ดํŽด๋ณด์ž๋ฉด, ์ด ์‚ฌ๊ฐํ˜• ์•ˆ์ชฝ์— ์žˆ๋Š” >> ๋ชจ์–‘์˜ ์„ ์€ ๋ทฐ์˜ layout_width์™€ layout_height๊ฐ€ ์–ด๋–ป๊ฒŒ ์„ค์ •๋˜์—ˆ๋Š”์ง€ ํ‘œ์‹œํ•˜๋Š” ์„ ์ด๋‹ค. ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ด ์„ธ ๊ฐ€์ง€์˜ ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋‹ค.

โœ” ๋ถ€๋ชจ ์—ฌ์œ  ๊ณต๊ฐ„ ์ฑ„์šฐ๊ธฐ : layout_width์˜ ๊ฐ’์€ match_constraint๋‚˜ 0dp๋กœ ์„ค์ •, ๊ตฌ๋ถˆ๊ตฌ๋ถˆํ•œ ์„ ์œผ๋กœ ํ‘œ์‹œ

โœ” ๋ทฐ์˜ ๋‚ด์šฉ๋ฌผ ์ฑ„์šฐ๊ธฐ : layout_width์˜ ๊ฐ’์€ wrap_content๋กœ ์„ค์ •, ์ค‘์•™์„ ํ–ฅํ•˜๋Š” ํ™”์‚ดํ‘œ(>>)๋กœ ํ‘œ์‹œ

โœ” ๊ณ ์ • ํฌ๊ธฐ : layout_width์™€ layout_height์˜ ๊ฐ’์€ ์ง€์ •ํ•œ ๊ฐ’์œผ๋กœ ์„ค์ •, ์ง์„ ์œผ๋กœ ํ‘œ์‹œ

๐Ÿ“Œ ๊ฐ€์ด๋“œ๋ผ์ธ ์‚ฌ์šฉํ•˜๊ธฐ

  • ๊ฐ€์ด๋“œ๋ผ์ธ(Guideline) : ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๋ทฐ๋ฅผ ์ผ์ •ํ•œ ๊ธฐ์ค€ ์„ ์— ์ •๋ ฌํ•  ๋•Œ ์‚ฌ์šฉ. ํ™”๋ฉด์— ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋Š” ์š”์†Œ์ด์ง€๋งŒ, ๊ทธ ํฌ๊ธฐ๊ฐ€ 0์ด๊ณ  ํ™”๋ฉด์—์„œ ๋ณด์ด์ง€ ์•Š์•„ ์‹ค์ œ ํ™”๋ฉด์˜ ๊ตฌ์„ฑ ์š”์†Œ๋Š” ์•„๋‹˜.
  • ๊ฐ€์ด๋“œ๋ผ์ธ์€ ๋””์ž์ธ ํ™”๋ฉด ์œ„์ชฝ์—์„œ [Guidelines] ์•„์ด์ฝ˜์„ ๋ˆŒ๋Ÿฌ ์ถ”๊ฐ€ํ•œ๋‹ค.

Vertical Guideline์„ ๋ˆ„๋ฅด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์„ธ๋กœ์ค„์˜ ๊ฐ€์ด๋“œ๋ผ์ธ์ด ์ƒ๊ธฐ๊ณ , ์ ์„ ์„ ์›€์ง์—ฌ ์œ„์น˜๋ฅผ ์กฐ์ ˆํ•  ์ˆ˜ ์žˆ๋‹ค.

๐Ÿ“Œ XML ์›๋ณธ์— ์ถ”๊ฐ€๋œ ์†์„ฑ ํ™•์ธํ•˜๊ธฐ

์‹ค์ œ ์•ฑ์„ ๋งŒ๋“ค ๋•Œ๋Š” ๋””์ž์ด๋„ˆ ๋„๊ตฌ๋ฟ๋งŒ์•„๋‹ˆ๋ผ XML ์›๋ณธ ์ฝ”๋“œ๋ฅผ ์ด์šฉํ•˜์—ฌ ๋” ์„ธ์„ธํ•˜๊ฒŒ ์ˆ˜์ •ํ•œ๋‹ค. [Code]๋ฅผ ๋ˆŒ๋Ÿฌ ์›๋ณธ 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"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

๊ฐ€์žฅ ์œ„์ชฝ์˜ ์ค„์€ ์ด ํŒŒ์ผ์ด XML ํ˜•์‹์œผ๋กœ ๋œ ๊ฒƒ์ž„์„ ์•Œ๋ ค์ฃผ๋Š” ์ค„์ด๋‹ค.

<?xml version="1.0" encoding="utf-8"?>

๊ทธ ๋‹ค์Œ ์ž…๋ ฅ๋œ ํƒœ๊ทธ๊ฐ€ ํ™”๋ฉด ์ „์ฒด๋ฅผ ๊ฐ์‹ธ๊ณ  ์žˆ๋Š” ๋ ˆ์ด์•„์›ƒ์ด๊ณ , ์•ž์— ํŒจํ‚ค์ง€ ์ด๋ฆ„์ด ๋ถ™์–ด์žˆ๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ConstraintLayout์ด ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ๋ถ„๋ฅ˜๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์•ž์— ํŒจํ‚ค์ง€ ์ด๋ฆ„๋„ ํ•จ๊ป˜ ๊ธฐ๋กํ•œ ๊ฒƒ์ด๋‹ค. ๋˜, ๋‹ค์Œ๊ณผ ๊ฐ™์€ xmlns:android ์†์„ฑ์€ XML ๋ ˆ์ด์•„์›ƒ ํŒŒ์ผ์ด๋ผ๋ฉด ํ•œ ๋ฒˆ์”ฉ ๋„ฃ์–ด์ค˜์•ผํ•˜๋Š” ์†์„ฑ์œผ๋กœ, ํ•˜๋‚˜์˜ ํŒŒ์ผ์— ํ•œ ๋ฒˆ๋งŒ ์‚ฌ์šฉ๋˜๋ฉด ๋œ๋‹ค. ์ด  xmlns๋’ค์— ์žˆ๋Š” android๋ผ๋Š” ์ด๋ฆ„์ด ๋‚˜๋จธ์ง€ ์†์„ฑ์„ ์ ‘๋‘์–ด๋กœ ์“ฐ์ธ๋‹ค.

xmlns:android="http://schemas.android.com/apk/res/android"

โœ” xmlns๋’ค์— ์žˆ๋Š” ์ ‘๋‘์–ด์˜ ์˜๋ฏธ

์ ‘๋‘์–ด ์˜๋ฏธ
xmlns:android ์•ˆ๋“œ๋กœ์ด๋“œ ๊ธฐ๋ณธ SDK์— ํฌํ•จ๋˜์–ด์žˆ๋Š” ์†์„ฑ์„ ์‚ฌ์šฉํ•œ๋‹ค.
xmlns:app ํ”„๋กœ์ ํŠธ์—์„œ ์‚ฌ์šฉํ•˜๋Š” ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ํฌํ•จํ•˜๋Š” ์†์„ฑ์„ ์‚ฌ์šฉํ•œ๋‹ค.(app์ด๋ผ๋Š” ๋‹จ์–ด๋Š” ๋‹ค๋ฅธ ๊ฒƒ์œผ๋กœ ๋Œ€์ฒด ๊ฐ€๋Šฅ)
xmlns:tools ์•ˆ๋“œ๋กœ์ด๋“œ ์ŠคํŠœ๋””์˜ค์˜ ๋””์ž์ด๋„ˆ ๋„๊ตฌ ๋“ฑ์—์„œ ํ™”๋ฉด์„ ๋ณด์—ฌ์ค„ ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค. ์•ฑ์ด ์‹คํ–‰๋  ๋•Œ๋Š” ์ ์šฉ๋˜์ง€ ์•Š๊ณ  ์•ˆ๋“œ๋กœ์ด๋“œ ์ŠคํŠœ๋””์˜ค์—์„œ๋งŒ ์ ์šฉ๋œ๋‹ค.

โœ” android:id ์†์„ฑ

  • ๋ทฐ๋ฅผ ๊ตฌ๋ถ„ํ•˜๋Š” ๊ตฌ๋ถ„์ž ์—ญํ• ์„ ํ•œ๋‹ค.
  • ์šฉ๋„
    • XML ๋ ˆ์ด์•„์›ƒ ํŒŒ์ผ ์•ˆ์—์„œ ๋ทฐ๋ฅผ ๊ตฌ๋ถ„ํ•  ๋•Œ
    • XML ๋ ˆ์ด์•„์›ƒ ํŒŒ์ผ์—์„œ ์ •์˜ํ•œ ๋ทฐ๋ฅผ ์ž๋ฐ” ์†Œ์Šค์—์„œ ์ฐพ์„ ๋•Œ
  • ์ œ์•ฝ ๋ ˆ์ด์•„์›ƒ์—์„œํ•˜๋‚˜์˜ ๋ทฐ๋ฅผ ๋‹ค๋ฅธ ๋ทฐ์™€ ์—ฐ๊ฒฐํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” XML ์†์„ฑ์˜ ์ด๋ฆ„ ๊ทœ์น™์—์„œ ์‚ฌ์šฉ๋œ๋‹ค.
layout_constraint[์†Œ์Šค ๋ทฐ์˜ ์—ฐ๊ฒฐ์ ]_[ํƒ€๊นƒ ๋ทฐ์˜ ์—ฐ๊ฒฐ์ ] = "[ํƒ€๊นƒ ๋ทฐ์˜ id]"
  • id ์†์„ฑ ๊ฐ’ ์ •์˜ํ•˜๋Š” ๋ฐฉ๋ฒ•
@+id/์•„์ด๋”” ๊ฐ’

๐Ÿ“Œ ํฌ๊ธฐ๋ฅผ ํ‘œ์‹œํ•˜๋Š” ๋‹จ์œ„์™€ ๋งˆ์ง„

์•ฑ์„ ๋งŒ๋“ค ๋•Œ ์™œ ๊ฑฐ๋ฆฌ ๋‹จ์œ„๋กœ dp๋ฅผ ์‚ฌ์šฉํ•˜๋Š”์ง€ ๊ถ๊ธˆ์ฆ์ด ๋“ค ์ˆ˜ ์žˆ๋‹ค. px์€ ํ•ด์ƒ๋„์— ๋”ฐ๋ผ ๊ทธ ํฌ๊ธฐ๊ฐ€ ๋‹ค๋ฅด๊ฒŒ ๋ณด์ด์ง€๋งŒ dp๋‚˜ sp์™€ ๊ฐ™์€ ๋‹จ์œ„๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ•ด์ƒ๋„๊ฐ€ ๋‹ค๋ฅธ ๋‹จ๋ง์—์„œ๋„ ๋ทฐ์˜ ํฌ๊ธฐ๋ฅผ ๋น„์Šทํ•˜๊ฒŒ ๋ณด์ด๋„๋ก ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค. ๋‹ค์Œ์€ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋‹จ์œ„์™€ ๊ทธ ์˜๋ฏธ์ด๋‹ค.

๋‹จ์œ„ ๋‹จ์œ„ ํ‘œํ˜„ ์„ค๋ช…
px ํ”ฝ์…€ ํ™”๋ฉด์˜ ํ”ฝ์…€ ์ˆ˜
dp ๋˜๋Š” dip ๋ฐ€๋„ ๋…๋ฆฝ์  ํ”ฝ์…€(density independent pixel) 160dpi ํ™”๋ฉด์„ ๊ธฐ์ค€์œผ๋กœ ํ•œ ํ”ฝ์…€
sp ๋˜๋Š” sip ์ถ•์ฒ™ ๋…๋ฆฝ์  ํ”ฝ์…€(scale independent pixel) ํ…์ŠคํŠธ ํฌ๊ธฐ๋ฅผ ์ง€์ •ํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ๋‹จ์œ„. ๊ฐ€๋ณ€ ๊ธ€๊ผด์„ ๊ธฐ์ค€์œผ๋กœ ํ•œ ํ”ฝ์…€๋กœ dp์™€ ์œ ์‚ฌํ•˜๋‚˜ ๊ธ€๊ผด์˜ ์„ค์ •์— ๋”ฐ๋ผ 1sp๋‹น ํ”ฝ์…€ ์ˆ˜๊ฐ€ ๋‹ฌ๋ผ์ง.
in ์ธ์น˜ 1์ธ์น˜๋กœ ๋œ ๋ฌผ๋ฆฌ์  ๊ธธ์ด
mm ๋ฐ€๋ฆฌ๋ฏธํ„ฐ 1๋ฐ€๋ฆฌ๋ฏธํ„ฐ๋กœ ๋œ ๋ฌผ๋ฆฌ์  ๊ธธ์ด
em ํ…์ŠคํŠธ ํฌ๊ธฐ ๊ธ€๊ผด๊ณผ ์ƒ๊ด€์—†์ด ๋™์ผํ•œ ํ…์ŠคํŠธ ํ‚…๊ธฐ ํ‘œ์‹œ