├── .gitignore ├── .idea ├── codeStyles │ └── Project.xml ├── encodings.xml ├── gradle.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── za │ │ └── co │ │ └── riggaroo │ │ └── constraintlayoutdemo │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── za │ │ │ └── co │ │ │ └── riggaroo │ │ │ └── constraintlayoutdemo │ │ │ ├── CircularConstraintActivity.kt │ │ │ ├── ConstraintLayoutStatesExampleActivity.kt │ │ │ ├── CupcakeActivity.kt │ │ │ ├── FlowActivity.kt │ │ │ ├── ImageFilterViewActivity.kt │ │ │ ├── MovieActivity.kt │ │ │ ├── OptionsActivity.kt │ │ │ ├── RatingView.kt │ │ │ └── RecyclerViewSwipeMotionActivity.kt │ └── res │ │ ├── drawable │ │ ├── header.jpg │ │ ├── ic_bookmark.xml │ │ ├── ic_call.xml │ │ ├── ic_email.xml │ │ ├── ic_family.xml │ │ ├── ic_launcher_background.xml │ │ ├── ic_level.xml │ │ ├── ic_navigation.xml │ │ ├── ic_playlist_add_black_24dp.xml │ │ ├── ic_rate_review.xml │ │ ├── ic_similar.xml │ │ ├── ic_timer_black_24dp.xml │ │ ├── mermaid_cupcake.jpg │ │ ├── pink_cupcake.jpg │ │ ├── pink_glitter_cupcakes.jpg │ │ ├── poster.jpg │ │ ├── rating_polygon_background.xml │ │ ├── singapore.jpg │ │ ├── tomato.png │ │ └── unicorn_cupcake.jpg │ │ ├── layout │ │ ├── activity_cl_states_end.xml │ │ ├── activity_cl_states_loading.xml │ │ ├── activity_cl_states_start.xml │ │ ├── activity_flow.xml │ │ ├── activity_movie_rental.xml │ │ ├── activity_movie_rental_large.xml │ │ ├── activity_options.xml │ │ ├── activity_swipe_recycler_view.xml │ │ ├── animation_example_2.xml │ │ ├── animation_example_2_transition.xml │ │ ├── barrier_example_1.xml │ │ ├── chains_example_1.xml │ │ ├── circular_constraint_example.xml │ │ ├── constraint_example_1.xml │ │ ├── group_example_1.xml │ │ ├── guidelines_example_1.xml │ │ ├── imagefilterview.xml │ │ ├── list_item_email.xml │ │ ├── rating_badge.xml │ │ └── ratio_example_1.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── values │ │ ├── attrs.xml │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ │ └── xml │ │ ├── constraint_layout_states_example.xml │ │ └── motion_scene_swipe.xml │ └── test │ └── java │ └── za │ └── co │ └── riggaroo │ └── constraintlayoutdemo │ └── ExampleUnitTest.kt ├── art └── ConstraintLayoutDemo.png ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | 11 | .idea/misc.xml 12 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | xmlns:android 14 | 15 | ^$ 16 | 17 | 18 | 19 |
20 |
21 | 22 | 23 | 24 | xmlns:.* 25 | 26 | ^$ 27 | 28 | 29 | BY_NAME 30 | 31 |
32 |
33 | 34 | 35 | 36 | .*:id 37 | 38 | http://schemas.android.com/apk/res/android 39 | 40 | 41 | 42 |
43 |
44 | 45 | 46 | 47 | .*:name 48 | 49 | http://schemas.android.com/apk/res/android 50 | 51 | 52 | 53 |
54 |
55 | 56 | 57 | 58 | name 59 | 60 | ^$ 61 | 62 | 63 | 64 |
65 |
66 | 67 | 68 | 69 | style 70 | 71 | ^$ 72 | 73 | 74 | 75 |
76 |
77 | 78 | 79 | 80 | .* 81 | 82 | ^$ 83 | 84 | 85 | BY_NAME 86 | 87 |
88 |
89 | 90 | 91 | 92 | .* 93 | 94 | http://schemas.android.com/apk/res/android 95 | 96 | 97 | ANDROID_ATTRIBUTE_ORDER 98 | 99 |
100 |
101 | 102 | 103 | 104 | .* 105 | 106 | .* 107 | 108 | 109 | BY_NAME 110 | 111 |
112 |
113 |
114 |
115 |
116 |
-------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 20 | 21 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Mastering Constraint Layout 2 | 3 | Different examples of how to use ConstraintLayout for different purposes. 4 | - Covering Circular Constraints 5 | - Barriers, Guidelines, Constraints etc 6 | - ImageFilterView 7 | - ConstraintLayoutStates 8 | 9 | The purpose of these layouts is to showcase how to use ConstraintLayout to solve a complex layout. 10 | 11 | The app has no functionality. 12 | 13 | This is a demo application that is used in conjunction with my "Mastering Android Layouts" workshop. 14 | This was presented with these slides https://speakerdeck.com/riggaroo/mastering-android-layouts-workshop-slides 15 | 16 | ![Constraint Layout](art/ConstraintLayoutDemo.png "Constraint Layout Demo") 17 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | apply plugin: 'kotlin-android' 4 | 5 | apply plugin: 'kotlin-android-extensions' 6 | 7 | apply plugin: 'kotlin-kapt' 8 | android { 9 | compileSdkVersion 29 10 | defaultConfig { 11 | applicationId "za.co.riggaroo.constraintlayoutdemo" 12 | minSdkVersion 21 13 | targetSdkVersion 29 14 | versionCode 1 15 | versionName "1.0" 16 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 17 | vectorDrawables.useSupportLibrary = true 18 | } 19 | lintOptions { 20 | abortOnError false 21 | } 22 | buildTypes { 23 | release { 24 | minifyEnabled false 25 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 26 | } 27 | } 28 | } 29 | 30 | dependencies { 31 | implementation fileTree(dir: 'libs', include: ['*.jar']) 32 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 33 | implementation 'androidx.appcompat:appcompat:1.1.0' 34 | implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta4' 35 | implementation 'com.github.bumptech.glide:glide:4.10.0' 36 | kapt 'com.github.bumptech.glide:compiler:4.10.0' 37 | testImplementation 'junit:junit:4.12' 38 | androidTestImplementation 'androidx.test:runner:1.2.0' 39 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' 40 | implementation 'com.google.android.material:material:1.0.0' 41 | 42 | implementation 'androidx.cardview:cardview:1.0.0' 43 | implementation 'androidx.recyclerview:recyclerview:1.1.0' 44 | } 45 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/rebeccafranks/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /app/src/androidTest/java/za/co/riggaroo/constraintlayoutdemo/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package za.co.riggaroo.constraintlayoutdemo 2 | 3 | import androidx.test.InstrumentationRegistry 4 | import androidx.test.runner.AndroidJUnit4 5 | 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | @RunWith(AndroidJUnit4::class) 17 | class ExampleInstrumentedTest { 18 | @Test 19 | fun useAppContext() { 20 | // Context of the app under test. 21 | val appContext = InstrumentationRegistry.getTargetContext() 22 | assertEquals("za.co.riggaroo.constraintlayoutdemo", appContext.packageName) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 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 | -------------------------------------------------------------------------------- /app/src/main/java/za/co/riggaroo/constraintlayoutdemo/CircularConstraintActivity.kt: -------------------------------------------------------------------------------- 1 | package za.co.riggaroo.constraintlayoutdemo 2 | 3 | import android.os.Bundle 4 | import androidx.appcompat.app.AppCompatActivity 5 | 6 | 7 | /** 8 | * @author rebeccafranks 9 | * @since 2017/10/13. 10 | */ 11 | class CircularConstraintActivity : AppCompatActivity() { 12 | 13 | override fun onCreate(savedInstanceState: Bundle?) { 14 | super.onCreate(savedInstanceState) 15 | setContentView(R.layout.circular_constraint_example) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/za/co/riggaroo/constraintlayoutdemo/ConstraintLayoutStatesExampleActivity.kt: -------------------------------------------------------------------------------- 1 | package za.co.riggaroo.constraintlayoutdemo 2 | 3 | import android.os.Bundle 4 | import android.os.Handler 5 | import androidx.appcompat.app.AppCompatActivity 6 | import androidx.core.os.HandlerCompat.postDelayed 7 | import kotlinx.android.synthetic.main.activity_cl_states_end.* 8 | 9 | class ConstraintLayoutStatesExampleActivity : AppCompatActivity() { 10 | 11 | private val handler = Handler() 12 | 13 | override fun onCreate(savedInstanceState: Bundle?) { 14 | super.onCreate(savedInstanceState) 15 | setContentView(R.layout.activity_cl_states_start) 16 | stateConstraintLayout.loadLayoutDescription(R.xml.constraint_layout_states_example) 17 | var changed = false 18 | buttonBakeCake.setOnClickListener { 19 | stateConstraintLayout.setState(R.id.loading, 0, 0) 20 | postDelayed(handler, { 21 | stateConstraintLayout.setState(if (changed) R.id.start else R.id.end,0, 0) 22 | changed = !changed 23 | },null ,3000L) 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /app/src/main/java/za/co/riggaroo/constraintlayoutdemo/CupcakeActivity.kt: -------------------------------------------------------------------------------- 1 | package za.co.riggaroo.constraintlayoutdemo 2 | 3 | import android.os.Bundle 4 | import androidx.constraintlayout.widget.ConstraintLayout 5 | import androidx.constraintlayout.widget.ConstraintSet 6 | import androidx.appcompat.app.AppCompatActivity 7 | import android.transition.TransitionManager 8 | import android.widget.Button 9 | 10 | /** 11 | * @author rebeccafranks 12 | * @since 2017/09/30. 13 | */ 14 | class CupcakeActivity : AppCompatActivity() { 15 | 16 | private var isLargeLayout = false 17 | 18 | override fun onCreate(savedInstanceState: Bundle?) { 19 | super.onCreate(savedInstanceState) 20 | 21 | val constraintSet1 = ConstraintSet() 22 | val constraintSet2 = ConstraintSet() 23 | 24 | constraintSet2.clone(this, R.layout.animation_example_2_transition) 25 | setContentView(R.layout.animation_example_2) 26 | 27 | val constraintLayout = findViewById(R.id.constraint_layout) 28 | constraintSet1.clone(constraintLayout) 29 | 30 | val bakeButton = findViewById