반응형
공감 및 댓글은 포스팅 하는데 아주아주 큰 힘이 됩니다!! 포스팅 내용이 찾아주신 분들께 도움이 되길 바라며 더 깔끔하고 좋은 포스팅을 만들어 나가겠습니다^^
|
지난 포스팅에서
간단히 유튜브 스타일 모션 레이아웃 예제 동영상을 올렸었는데요.
2020/03/17 - [안드로이드] - 안드로이드 유튜브 스타일 레이아웃 만들기(2) - 실행 예제
이번 포스팅부터 하나씩 차근차근 만들어보겠습니다.
#1. 프로젝트 생성
프로젝트를 생성해주시고, 필요한 의존성을 추가해줍니다.
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'com.google.android.material:material:1.2.0-alpha05'
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta4'
implementation 'androidx.core:core-ktx:1.2.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
implementation 'com.github.bumptech.glide:glide:3.7.0'
}
#2. 레이아웃 만들기
bottom_nav_menu.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | <?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/navigation_home" android:icon="@drawable/ic_home_gray_24dp" android:title="@string/title_home" android:checkable="true"/> <item android:id="@+id/navigation_hot" android:icon="@drawable/ic_whatshot_gray_24dp" android:title="@string/title_hot" /> <item android:id="@+id/navigation_subscribe" android:icon="@drawable/ic_share_gray_24dp" android:title="@string/title_subscribe" /> <item android:id="@+id/navigation_letter_box" android:icon="@drawable/ic_dashboard_black_24dp" android:title="@string/title_letter_box" /> <item android:id="@+id/navigation_cubby_hole" android:icon="@drawable/ic_notifications_black_24dp" android:title="@string/title_cubby_hole" /> </menu> | cs |
header_nav_menu.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | <?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/header_thumb_up" android:checked="false" android:icon="@drawable/ic_thumb_up_gray" android:title="@string/text_header_thumb_up"/> <item android:id="@+id/header_thumb_down" android:checked="false" android:icon="@drawable/ic_thumb_down_gray" android:title="@string/text_header_thumb_down"/> <item android:id="@+id/header_share" android:checked="false" android:icon="@drawable/ic_share_gray" android:title="@string/text_header_share"/> <item android:id="@+id/header_file_download" android:checked="false" android:icon="@drawable/ic_file_download_gray" android:title="@string/text_header_file_download"/> <item android:id="@+id/header_file_download2" android:checked="false" android:icon="@drawable/ic_file_download_gray" android:title="@string/text_header_file_download"/> </menu> | cs |
activity_main.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | <?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:id="@+id/mainLayout" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/white" tools:ignore="contentDescription"> <FrameLayout android:id="@+id/page_container" android:layout_width="match_parent" android:layout_height="0dp" app:layout_constraintBottom_toTopOf="@id/bottom_nav" app:layout_constraintTop_toTopOf="parent"> </FrameLayout> <FrameLayout android:id="@+id/detailVideoContainer" android:layout_width="match_parent" android:layout_height="match_parent" android:alpha="0" android:background="#000000" /> <androidx.constraintlayout.widget.ConstraintLayout android:id="@+id/videoDetailLayout" android:layout_width="match_parent" android:layout_height="54dp" android:background="@drawable/border_lgtgray" app:layout_constraintTop_toBottomOf="@id/bottom_nav"> <Space android:id="@+id/emptySpace" android:layout_width="0dp" android:layout_height="0dp" android:layout_marginTop="-5dp" android:layout_marginBottom="-5dp" android:background="?android:windowBackground" android:scaleType="fitXY" android:src="@drawable/video_01_moment" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintDimensionRatio="H,1:2.5" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/videoTitle" app:layout_constraintStart_toEndOf="@id/emptySpace" app:layout_constraintEnd_toStartOf="@id/playImage" app:layout_constraintTop_toTopOf="parent" android:ellipsize="end" android:maxLines="1" android:layout_width="0dp" android:layout_height="wrap_content"/> <TextView android:id="@+id/videoUploaderName" app:layout_constraintTop_toBottomOf="@id/videoTitle" app:layout_constraintStart_toEndOf="@id/emptySpace" app:layout_constraintEnd_toStartOf="@id/playImage" android:ellipsize="end" android:maxLines="1" android:layout_width="0dp" android:layout_height="wrap_content"/> <ImageButton android:id="@+id/playImage" android:layout_width="42dp" android:layout_height="42dp" android:alpha="0" android:background="@drawable/ripple_rect" android:src="@drawable/ic_pause_black" android:visibility="invisible" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@id/clearImage" app:layout_constraintTop_toTopOf="parent" /> <ImageButton android:id="@+id/clearImage" android:layout_width="42dp" android:layout_height="42dp" android:alpha="0" android:background="@drawable/ripple_rect" android:src="@drawable/ic_clear_black" android:visibility="invisible" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout> <SurfaceView android:id="@+id/videoImage" android:layout_width="0dp" android:layout_height="0dp" android:layout_marginTop="2dp" android:layout_marginBottom="2dp" app:layout_constraintBottom_toBottomOf="@id/videoDetailLayout" app:layout_constraintDimensionRatio="H,1:2.5" app:layout_constraintStart_toStartOf="@id/videoDetailLayout" app:layout_constraintTop_toTopOf="@id/videoDetailLayout" /> <FrameLayout android:id="@+id/recyclerview_container" android:layout_width="0dp" android:layout_height="0dp" android:background="?android:attr/windowBackground" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="@id/videoDetailLayout" /> <androidx.recyclerview.widget.RecyclerView android:id="@+id/recommendListView" android:layout_width="0dp" android:layout_height="0dp" android:alpha="0" android:background="@color/colorGray" android:overScrollMode="never" app:layout_constraintBottom_toBottomOf="@id/videoDetailLayout" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/videoDetailLayout" /> <com.google.android.material.bottomnavigation.BottomNavigationView android:id="@+id/bottom_nav" android:layout_width="0dp" android:layout_height="48dp" android:background="@drawable/border_lgtgray" app:itemIconTint="@color/colorGray" app:itemTextAppearance="@style/TextAppearance.AppCompat.Caption" app:itemTextAppearanceActive="@style/TextAppearance.AppCompat.Caption" app:itemTextAppearanceInactive="@style/TextAppearance.AppCompat.Caption" app:labelVisibilityMode="labeled" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:menu="@menu/bottom_nav_menu" /> </androidx.constraintlayout.widget.ConstraintLayout> | cs |
fragment_home.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 | <?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" xmlns:app="http://schemas.android.com/apk/res-auto"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/homeRecyclerView" app:layout_constraintTop_toTopOf="parent" android:layout_width="match_parent" android:layout_height="wrap_content"/> </androidx.constraintlayout.widget.ConstraintLayout> | cs |
#3. item.xml 만들기
activity_main의 recyclerView에 사용될 items
1. item_header.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | <?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:id="@+id/headerLayout" android:layout_width="match_parent" android:layout_height="wrap_content"> <androidx.constraintlayout.widget.ConstraintLayout android:id="@+id/layout_description" android:layout_width="match_parent" android:layout_height="wrap_content" app:layout_constrainedWidth="true" android:background="?attr/selectableItemBackground" android:paddingStart="16dp" android:paddingEnd="16dp" android:paddingTop="4dp" android:paddingBottom="4dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"> <androidx.appcompat.widget.AppCompatTextView android:id="@+id/text_description" style="@style/TextAppearance.AppCompat" android:gravity="center|start" android:layout_width="0dp" android:layout_height="wrap_content" android:text="@string/cat" app:layout_constraintStart_toStartOf="parent" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@id/image_description" app:layout_constraintTop_toTopOf="parent" /> <androidx.appcompat.widget.AppCompatImageView android:id="@+id/image_description" app:layout_constraintEnd_toEndOf="parent" android:scaleType="centerInside" android:src="@drawable/ic_arrow_drop_down_gray" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" android:layout_width="wrap_content" android:layout_height="wrap_content"/> </androidx.constraintlayout.widget.ConstraintLayout> <com.google.android.material.bottomnavigation.BottomNavigationView android:id="@+id/header_nav" app:elevation="0dp" android:layout_width="0dp" android:layout_height="96dp" android:paddingStart="16dp" android:paddingEnd="16dp" android:background="@android:color/white" app:itemTextAppearance="@style/TextAppearance.AppCompat.Caption" app:itemTextAppearanceActive="@style/TextAppearance.AppCompat.Caption" app:itemTextAppearanceInactive="@style/TextAppearance.AppCompat.Caption" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toBottomOf="@id/layout_description" app:labelVisibilityMode="labeled" app:itemIconTint="@color/colorGray" app:menu="@menu/header_nav_menu" /> <androidx.constraintlayout.widget.ConstraintLayout android:id="@+id/uploaderLayout" app:layout_constraintTop_toBottomOf="@id/header_nav" android:layout_width="match_parent" android:layout_height="48dp"> <androidx.appcompat.widget.AppCompatImageView android:id="@+id/uploaderThumbnail" android:layout_width="0dp" android:layout_height="match_parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintDimensionRatio="1:1" android:scaleType="fitXY" android:src="@drawable/ic_keyboard_arrow_up_red"/> <androidx.appcompat.widget.AppCompatTextView android:id="@+id/uploaderName" android:layout_width="wrap_content" android:layout_height="match_parent" app:layout_constraintStart_toEndOf="@id/uploaderThumbnail" android:gravity="center|start" android:paddingStart="4dp" android:paddingEnd="4dp" tools:text="1234" android:scaleType="centerInside" android:src="@drawable/ic_keyboard_arrow_up_red"/> </androidx.constraintlayout.widget.ConstraintLayout> <androidx.constraintlayout.widget.ConstraintLayout android:id="@+id/content_description" android:animateLayoutChanges="true" app:layout_constraintTop_toBottomOf="@id/uploaderLayout" android:background="@color/colorAccent" android:layout_width="match_parent" android:layout_height="wrap_content"> <androidx.appcompat.widget.AppCompatTextView android:id="@+id/content_description_textview" app:layout_constraintTop_toTopOf="parent" android:padding="8dp" android:text="@string/lorem" android:layout_width="match_parent" android:layout_height="wrap_content"/> </androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout> | cs |
2. item_description.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <?xml version="1.0" encoding="utf-8"?> <TextView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/text_description" style="@style/TextAppearance.AppCompat" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginEnd="8dp" android:layout_marginStart="8dp" android:layout_marginTop="12dp" android:text="@string/lorem" app:layout_constrainedWidth="true" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" /> | cs |
3. item_row.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | <?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_marginTop="4dp" android:layout_marginStart="4dp" android:layout_marginBottom="4dp" tools:ignore="contentDescription"> <ImageView android:id="@+id/image_row" android:layout_width="200dp" android:layout_height="0dp" android:scaleType="centerCrop" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintDimensionRatio="4:3" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"/> <TextView android:id="@+id/text_row" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.12" app:layout_constraintStart_toEndOf="@id/image_row" app:layout_constraintTop_toTopOf="@id/image_row" tools:text="This is a text in an item"/> </androidx.constraintlayout.widget.ConstraintLayout> | cs |
fragment_home의 recyclerView에 사용될 items
1. item_toolbar.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | <?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="48dp" android:background="@android:color/white" android:elevation="4dp" xmlns:app="http://schemas.android.com/apk/res-auto"> <androidx.appcompat.widget.AppCompatImageView android:id="@+id/appLogoImageView" app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent" android:src="@drawable/ic_logo_red" android:adjustViewBounds="true" android:scaleType="centerInside" android:layout_width="wrap_content" android:layout_height="match_parent"/> </androidx.constraintlayout.widget.ConstraintLayout> | cs |
2. item_video.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | <?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:clickable="true" android:focusable="true" android:background="@drawable/ripple_rect" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools"> <androidx.appcompat.widget.AppCompatImageView android:background="@drawable/ripple_rect_gray" android:id="@+id/videoThumbnailImageView" app:layout_constraintTop_toTopOf="parent" app:layout_constraintDimensionRatio="2:1" android:scaleType="centerCrop" android:layout_width="match_parent" android:layout_height="0dp"/> <androidx.constraintlayout.widget.ConstraintLayout app:layout_constraintTop_toBottomOf="@id/videoThumbnailImageView" android:paddingBottom="24dp" android:layout_width="match_parent" android:layout_height="wrap_content"> <androidx.appcompat.widget.AppCompatImageView android:id="@+id/uploaderImgView" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintEnd_toStartOf="@id/videoDescriptionTxtView" android:layout_width="0dp" android:layout_height="48dp" android:layout_margin="12dp" app:layout_constraintDimensionRatio="1:1" android:scaleType="fitXY"/> <androidx.appcompat.widget.AppCompatTextView android:id="@+id/videoDescriptionTxtView" android:padding="4dp" android:textColor="@color/colorGray" app:layout_constraintEnd_toStartOf="@id/menuImgView" app:layout_constraintStart_toEndOf="@id/uploaderImgView" app:layout_constraintTop_toTopOf="@id/uploaderImgView" tools:text="asddjdsfmkjwekljflwijfdkjfwlkejf;lakjsd;flkj;lkj;ajsd;fjkjl;" android:ellipsize="end" android:maxLines="2" android:layout_width="0dp" android:layout_height="wrap_content"/> <androidx.appcompat.widget.AppCompatTextView android:id="@+id/videoUploaderTxtView" android:padding="4dp" android:textColor="@color/colorGray" app:layout_constraintEnd_toStartOf="@id/menuImgView" app:layout_constraintStart_toStartOf="@id/videoDescriptionTxtView" app:layout_constraintTop_toBottomOf="@id/videoDescriptionTxtView" tools:text="asddjdsfmkjwekljflwijfdkjfwlkejf;lakjsd;flkj;lkj;ajsd;fjkjl;" android:ellipsize="end" android:maxLines="1" android:layout_width="0dp" android:layout_height="wrap_content"/> <androidx.appcompat.widget.AppCompatImageView android:id="@+id/menuImgView" android:layout_width="42dp" android:layout_height="42dp" android:src="@drawable/ic_more_vert_gray" android:scaleType="centerInside" app:layout_constraintStart_toEndOf="@id/videoDescriptionTxtView" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="@id/uploaderImgView"/> </androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout> | cs |
여기까지 필요한 레이아웃을 모두 만들었습니다.
아래 깃허브에 가시면 필요한 리소스까지 다 추가해서 올려놓았습니다.
https://github.com/Parksunggyun/MirrorYoutube
반응형
'안드로이드' 카테고리의 다른 글
안드로이드 유튜브 스타일 모션레이아웃(3) - 모션레이아웃 적용하기[1] (0) | 2020.03.18 |
---|---|
안드로이드 유튜브 스타일 모션레이아웃(2) - 메인화면 구성 (0) | 2020.03.18 |
안드로이드 유튜브 스타일 레이아웃 만들기(2) - 실행 예제 (0) | 2020.03.17 |
안드로이드 View의 스크린 상의 절대좌표 구하기 getLocationOnScreen() (0) | 2020.03.17 |
안드로이드 유튜브 스타일 레이아웃 만들기(1) - 실행 예제 (0) | 2020.03.16 |