├── .gitignore ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── example │ │ └── dynamicviewpager │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── dynamicviewpager │ │ │ ├── App.java │ │ │ ├── Image.kt │ │ │ ├── ScrollingActivity.kt │ │ │ ├── SimpleImageFragment.kt │ │ │ └── TransformViewPagerAdapter.kt │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ └── ic_launcher_background.xml │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── activity_review_detail_header.xml │ │ ├── activity_scrolling.xml │ │ ├── content_scrolling.xml │ │ └── fragment_simple_image.xml │ │ ├── menu │ │ └── menu_scrolling.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── example │ └── dynamicviewpager │ └── ExampleUnitTest.kt ├── build.gradle ├── demo.gif ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── transformviewpager ├── .gitignore ├── build.gradle ├── consumer-rules.pro ├── proguard-rules.pro └── src ├── androidTest └── java │ └── com │ └── danteandroid │ └── transformviewpager │ └── ExampleInstrumentedTest.kt ├── main ├── AndroidManifest.xml ├── java │ └── com │ │ └── danteandroid │ │ └── transformviewpager │ │ ├── TransformViewPager.kt │ │ ├── Transformable.kt │ │ └── UiUtils.kt └── res │ └── values │ └── strings.xml └── test └── java └── com └── danteandroid └── transformviewpager └── ExampleUnitTest.kt /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | /.idea/ 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TransformViewPager 2 | A dynamic-height viewpager which can transform its pages. 3 | 4 | [![](https://jitpack.io/v/DanteAndroid/TransformViewPager.svg)](https://jitpack.io/#DanteAndroid/TransformViewPager) 5 | 6 | ## Demonstration 7 | 8 | 9 | 10 | ## Dependency 11 | ``` 12 | implementation 'com.github.DanteAndroid:TransformViewPager:v0.1' 13 | ``` 14 | 15 | ## Usage 16 | 0. Use `TransformViewPager` which extends ViewPager 17 | 1. Make your data item implement `Transformable` 18 | 2. Make your ViewPager's adapter implement `TransformableAdapter` 19 | 3. Of course set your TransformableAdapter for the TransformViewPager 20 | -------------------------------------------------------------------------------- /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 | android { 8 | compileSdkVersion 29 9 | buildToolsVersion "28.0.3" 10 | defaultConfig { 11 | applicationId "com.danteandroid.transformviewpager" 12 | minSdkVersion 19 13 | targetSdkVersion 29 14 | versionCode 1 15 | versionName "1.0" 16 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 17 | } 18 | buildTypes { 19 | release { 20 | minifyEnabled false 21 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 22 | } 23 | } 24 | } 25 | 26 | dependencies { 27 | implementation fileTree(dir: 'libs', include: ['*.jar']) 28 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 29 | 30 | implementation 'com.github.bumptech.glide:glide:4.9.0' 31 | implementation 'com.google.code.gson:gson:2.8.6' 32 | 33 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3' 34 | implementation 'androidx.legacy:legacy-support-v4:1.0.0' 35 | implementation 'androidx.appcompat:appcompat:1.1.0' 36 | implementation 'com.google.android.material:material:1.0.0' 37 | implementation project(path: ':transformviewpager') 38 | // implementation 'com.github.DanteAndroid:TransformViewPager:v0.1' 39 | } 40 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/example/dynamicviewpager/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.example.dynamicviewpager 2 | 3 | import androidx.test.platform.app.InstrumentationRegistry 4 | import androidx.test.ext.junit.runners.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.getInstrumentation().targetContext 22 | assertEquals("com.example.dynamicviewpager", appContext.packageName) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 17 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/dynamicviewpager/App.java: -------------------------------------------------------------------------------- 1 | package com.example.dynamicviewpager; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.app.Application; 5 | import android.content.Context; 6 | 7 | /** 8 | * @author Dante 9 | * 2019-11-07 10 | */ 11 | public class App extends Application { 12 | 13 | @SuppressLint("StaticFieldLeak") 14 | public static Context context; 15 | 16 | @Override 17 | public void onCreate() { 18 | super.onCreate(); 19 | context = this; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/dynamicviewpager/Image.kt: -------------------------------------------------------------------------------- 1 | package com.example.dynamicviewpager 2 | 3 | import com.danteandroid.transformviewpager.Transformable 4 | import java.io.Serializable 5 | 6 | /** 7 | * @author Dante 8 | * 2019-11-07 9 | */ 10 | data class Image( 11 | val width: Int, 12 | val height: Int, 13 | val format: String, 14 | val size: Int, 15 | val url: String 16 | ) : Serializable, Transformable { 17 | override fun getOriginalWidth(): Float { 18 | return width.toFloat() 19 | } 20 | 21 | override fun getOrignalHeight(): Float { 22 | return height.toFloat() 23 | } 24 | } 25 | 26 | const val JSON_DATA: String = "[\n" + 27 | "{\n" + 28 | " \"width\": 1000,\n" + 29 | " \"height\": 700,\n" + 30 | " \"format\": \"jpeg\",\n" + 31 | " \"size\": 28340,\n" + 32 | " \"url\": \"https://picsum.photos/id/100/1000/700\"\n" + 33 | "},\n" + 34 | "{\n" + 35 | " \"width\": 1920,\n" + 36 | " \"height\": 1080,\n" + 37 | " \"format\": \"jpeg\",\n" + 38 | " \"size\": 33663,\n" + 39 | " \"url\": \"https://picsum.photos/id/99/1920/1080\"\n" + 40 | "},\n" + 41 | "{\n" + 42 | " \"width\": 720,\n" + 43 | " \"height\": 1080,\n" + 44 | " \"format\": \"jpeg\",\n" + 45 | " \"size\": 704200,\n" + 46 | " \"url\": \"https://picsum.photos/id/199/720/1080\"\n" + 47 | "},\n" + 48 | "{\n" + 49 | " \"width\": 1080,\n" + 50 | " \"height\": 1080,\n" + 51 | " \"format\": \"jpeg\",\n" + 52 | " \"size\": 30155,\n" + 53 | " \"url\": \"https://picsum.photos/id/191/1080/1080\"\n" + 54 | "}\n" + 55 | "]" -------------------------------------------------------------------------------- /app/src/main/java/com/example/dynamicviewpager/ScrollingActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.dynamicviewpager 2 | 3 | import android.os.Bundle 4 | import androidx.appcompat.app.AppCompatActivity 5 | import com.google.gson.Gson 6 | import kotlinx.android.synthetic.main.activity_review_detail_header.* 7 | import kotlinx.android.synthetic.main.activity_scrolling.* 8 | 9 | 10 | class ScrollingActivity : AppCompatActivity() { 11 | 12 | override fun onCreate(savedInstanceState: Bundle?) { 13 | super.onCreate(savedInstanceState) 14 | setContentView(R.layout.activity_scrolling) 15 | setSupportActionBar(toolbar) 16 | // fab.setOnClickListener { view -> 17 | // Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG) 18 | // .setAction("Action", null).show() 19 | // } 20 | 21 | // 布局里使用 fitSystemWindows 导致有一个状态栏高度的 padding 存在 22 | // 暂时没找到好的解决方案。有的话请告诉我 23 | // https://stackoverflow.com/questions/48137666/viewgroup-inside-collapsingtoolbarlayout-show-extra-bottom-padding-when-set-fits 24 | 25 | init() 26 | } 27 | 28 | private fun init() { 29 | val images = Gson().fromJson(JSON_DATA, Array::class.java).asList() 30 | viewPager.adapter = TransformViewPagerAdapter(supportFragmentManager, images) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/dynamicviewpager/SimpleImageFragment.kt: -------------------------------------------------------------------------------- 1 | package com.example.dynamicviewpager 2 | 3 | 4 | import android.os.Bundle 5 | import android.view.LayoutInflater 6 | import android.view.View 7 | import android.view.ViewGroup 8 | import androidx.fragment.app.Fragment 9 | import com.bumptech.glide.Glide 10 | import kotlinx.android.synthetic.main.fragment_simple_image.* 11 | 12 | /** 13 | * A simple [Fragment] subclass. 14 | */ 15 | class SimpleImageFragment : Fragment() { 16 | 17 | companion object { 18 | const val ARG_IMAGE = "image" 19 | fun newInstance(image: Image): SimpleImageFragment { 20 | return SimpleImageFragment().apply { 21 | arguments = Bundle().apply { 22 | putSerializable(ARG_IMAGE, image) 23 | } 24 | } 25 | } 26 | } 27 | 28 | override fun onCreateView( 29 | inflater: LayoutInflater, container: ViewGroup?, 30 | savedInstanceState: Bundle? 31 | ): View? { 32 | return inflater.inflate(R.layout.fragment_simple_image, container, false) 33 | } 34 | 35 | 36 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 37 | super.onViewCreated(view, savedInstanceState) 38 | val image = arguments!!.getSerializable(ARG_IMAGE) as Image 39 | Glide.with(this).load(image.url).fitCenter().into(imageView) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/dynamicviewpager/TransformViewPagerAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.example.dynamicviewpager 2 | 3 | import android.view.ViewGroup 4 | import androidx.fragment.app.Fragment 5 | import androidx.fragment.app.FragmentManager 6 | import androidx.fragment.app.FragmentPagerAdapter 7 | import com.danteandroid.transformviewpager.Transformable 8 | import com.danteandroid.transformviewpager.TransformableAdapter 9 | 10 | /** 11 | * @author Dante 12 | * 2019-11-11 13 | */ 14 | 15 | class TransformViewPagerAdapter(fragmentManager: FragmentManager, val images: List) : 16 | FragmentPagerAdapter(fragmentManager), TransformableAdapter { 17 | 18 | override fun getTransformableItems(): List { 19 | return images 20 | } 21 | 22 | private val fragments: ArrayList = arrayListOf() 23 | 24 | init { 25 | for (image in images) { 26 | fragments.add(SimpleImageFragment.newInstance(image)) 27 | } 28 | } 29 | 30 | override fun getItem(index: Int): Fragment = fragments[index] 31 | 32 | override fun getCount(): Int = images.size 33 | 34 | override fun setPrimaryItem(container: ViewGroup, position: Int, `object`: Any) { 35 | super.setPrimaryItem(container, position, `object`) 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 9 | 10 | 15 | 16 | 24 | 25 | 26 | 27 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 48 | 49 | 53 | 54 | 61 | 62 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_review_detail_header.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_scrolling.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 16 | 17 | 26 | 27 | 28 | 29 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /app/src/main/res/layout/content_scrolling.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_simple_image.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_scrolling.xml: -------------------------------------------------------------------------------- 1 | 5 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanteAndroid/TransformViewPager/011dadb2c83104b9fe5d047cf37e117c637647e9/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanteAndroid/TransformViewPager/011dadb2c83104b9fe5d047cf37e117c637647e9/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanteAndroid/TransformViewPager/011dadb2c83104b9fe5d047cf37e117c637647e9/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanteAndroid/TransformViewPager/011dadb2c83104b9fe5d047cf37e117c637647e9/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanteAndroid/TransformViewPager/011dadb2c83104b9fe5d047cf37e117c637647e9/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanteAndroid/TransformViewPager/011dadb2c83104b9fe5d047cf37e117c637647e9/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanteAndroid/TransformViewPager/011dadb2c83104b9fe5d047cf37e117c637647e9/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanteAndroid/TransformViewPager/011dadb2c83104b9fe5d047cf37e117c637647e9/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanteAndroid/TransformViewPager/011dadb2c83104b9fe5d047cf37e117c637647e9/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanteAndroid/TransformViewPager/011dadb2c83104b9fe5d047cf37e117c637647e9/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #008577 4 | #00574B 5 | #D81B60 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 180dp 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | DynamicViewPager 3 | ScrollingActivity 4 | 5 | "Material is the metaphor.\n\n" 6 | 7 | "A material metaphor is the unifying theory of a rationalized space and a system of motion." 8 | "The material is grounded in tactile reality, inspired by the study of paper and ink, yet " 9 | "technologically advanced and open to imagination and magic.\n" 10 | "Surfaces and edges of the material provide visual cues that are grounded in reality. The " 11 | "use of familiar tactile attributes helps users quickly understand affordances. Yet the " 12 | "flexibility of the material creates new affordances that supercede those in the physical " 13 | "world, without breaking the rules of physics.\n" 14 | "The fundamentals of light, surface, and movement are key to conveying how objects move, " 15 | "interact, and exist in space and in relation to each other. Realistic lighting shows " 16 | "seams, divides space, and indicates moving parts.\n\n" 17 | 18 | "Bold, graphic, intentional.\n\n" 19 | 20 | "The foundational elements of print based design typography, grids, space, scale, color, " 21 | "and use of imagery guide visual treatments. These elements do far more than please the " 22 | "eye. They create hierarchy, meaning, and focus. Deliberate color choices, edge to edge " 23 | "imagery, large scale typography, and intentional white space create a bold and graphic " 24 | "interface that immerse the user in the experience.\n" 25 | "An emphasis on user actions makes core functionality immediately apparent and provides " 26 | "waypoints for the user.\n\n" 27 | 28 | "Motion provides meaning.\n\n" 29 | 30 | "Motion respects and reinforces the user as the prime mover. Primary user actions are " 31 | "inflection points that initiate motion, transforming the whole design.\n" 32 | "All action takes place in a single environment. Objects are presented to the user without " 33 | "breaking the continuity of experience even as they transform and reorganize.\n" 34 | "Motion is meaningful and appropriate, serving to focus attention and maintain continuity. " 35 | "Feedback is subtle yet clear. Transitions are efficient yet coherent.\n\n" 36 | 37 | "3D world.\n\n" 38 | 39 | "The material environment is a 3D space, which means all objects have x, y, and z " 40 | "dimensions. The z-axis is perpendicularly aligned to the plane of the display, with the " 41 | "positive z-axis extending towards the viewer. Every sheet of material occupies a single " 42 | "position along the z-axis and has a standard 1dp thickness.\n" 43 | "On the web, the z-axis is used for layering and not for perspective. The 3D world is " 44 | "emulated by manipulating the y-axis.\n\n" 45 | 46 | "Light and shadow.\n\n" 47 | 48 | "Within the material environment, virtual lights illuminate the scene. Key lights create " 49 | "directional shadows, while ambient light creates soft shadows from all angles.\n" 50 | "Shadows in the material environment are cast by these two light sources. In Android " 51 | "development, shadows occur when light sources are blocked by sheets of material at " 52 | "various positions along the z-axis. On the web, shadows are depicted by manipulating the " 53 | "y-axis only. The following example shows the card with a height of 6dp.\n\n" 54 | 55 | "Resting elevation.\n\n" 56 | 57 | "All material objects, regardless of size, have a resting elevation, or default elevation " 58 | "that does not change. If an object changes elevation, it should return to its resting " 59 | "elevation as soon as possible.\n\n" 60 | 61 | "Component elevations.\n\n" 62 | 63 | "The resting elevation for a component type is consistent across apps (e.g., FAB elevation " 64 | "does not vary from 6dp in one app to 16dp in another app).\n" 65 | "Components may have different resting elevations across platforms, depending on the depth " 66 | "of the environment (e.g., TV has a greater depth than mobile or desktop).\n\n" 67 | 68 | "Responsive elevation and dynamic elevation offsets.\n\n" 69 | 70 | "Some component types have responsive elevation, meaning they change elevation in response " 71 | "to user input (e.g., normal, focused, and pressed) or system events. These elevation " 72 | "changes are consistently implemented using dynamic elevation offsets.\n" 73 | "Dynamic elevation offsets are the goal elevation that a component moves towards, relative " 74 | "to the component’s resting state. They ensure that elevation changes are consistent " 75 | "across actions and component types. For example, all components that lift on press have " 76 | "the same elevation change relative to their resting elevation.\n" 77 | "Once the input event is completed or cancelled, the component will return to its resting " 78 | "elevation.\n\n" 79 | 80 | "Avoiding elevation interference.\n\n" 81 | 82 | "Components with responsive elevations may encounter other components as they move between " 83 | "their resting elevations and dynamic elevation offsets. Because material cannot pass " 84 | "through other material, components avoid interfering with one another any number of ways, " 85 | "whether on a per component basis or using the entire app layout.\n" 86 | "On a component level, components can move or be removed before they cause interference. " 87 | "For example, a floating action button (FAB) can disappear or move off screen before a " 88 | "user picks up a card, or it can move if a snackbar appears.\n" 89 | "On the layout level, design your app layout to minimize opportunities for interference. " 90 | "For example, position the FAB to one side of stream of a cards so the FAB won’t interfere " 91 | "when a user tries to pick up one of cards.\n\n" 92 | 93 | Settings 94 | 95 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 16 | 17 |