├── core ├── .gitignore ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ ├── res │ │ └── values │ │ │ ├── ids.xml │ │ │ ├── public.xml │ │ │ └── attrs.xml │ │ └── kotlin │ │ └── com │ │ └── zedalpha │ │ └── shadowgadgets │ │ └── core │ │ ├── ListUtils.kt │ │ ├── shadow │ │ ├── BaseView.kt │ │ └── CoreShadow.kt │ │ ├── layer │ │ ├── ManagedLayer.kt │ │ ├── LocationTracker.kt │ │ ├── RenderNodeLayer.kt │ │ ├── ViewLayer.kt │ │ └── Layer.kt │ │ ├── rendernode │ │ ├── RenderNodeApi23.kt │ │ ├── RenderNodeWrapper.kt │ │ └── RenderNodeFactory.kt │ │ ├── Shadow.kt │ │ ├── ClippedShadow.kt │ │ └── ColorUtils.kt ├── consumer-rules.pro └── build.gradle.kts ├── demo ├── .gitignore ├── src │ └── main │ │ ├── res │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.webp │ │ │ └── ic_launcher_round.webp │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.webp │ │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.webp │ │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.webp │ │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.webp │ │ │ └── ic_launcher_round.webp │ │ ├── drawable │ │ │ ├── bg_root.xml │ │ │ ├── bg_rounded_rectangle.xml │ │ │ ├── bg_drop_target.xml │ │ │ ├── divider.xml │ │ │ ├── bg_roundish_square.xml │ │ │ ├── ic_clear.xml │ │ │ ├── ic_add.xml │ │ │ ├── ic_arrow_up.xml │ │ │ ├── ic_arrow_back.xml │ │ │ └── ic_arrow_forward.xml │ │ ├── layout │ │ │ ├── compose_view.xml │ │ │ ├── internal_title_switcher.xml │ │ │ ├── dialog_root.xml │ │ │ ├── dialog_description.xml │ │ │ ├── view_root.xml │ │ │ ├── item_description.xml │ │ │ ├── item_colorful.xml │ │ │ ├── fragment_root.xml │ │ │ ├── view_panel.xml │ │ │ ├── fragment_compat_stress_test.xml │ │ │ ├── dialog_welcome.xml │ │ │ ├── activity_main.xml │ │ │ └── fragment_apply.xml │ │ ├── values │ │ │ ├── dimens.xml │ │ │ ├── colors.xml │ │ │ └── themes.xml │ │ ├── mipmap-anydpi-v26 │ │ │ ├── ic_launcher.xml │ │ │ └── ic_launcher_round.xml │ │ ├── anim │ │ │ ├── slide_in_top.xml │ │ │ ├── slide_in_bottom.xml │ │ │ ├── slide_out_bottom.xml │ │ │ └── slide_out_top.xml │ │ ├── drawable-v24 │ │ │ └── ic_launcher_foreground.xml │ │ └── xml │ │ │ └── motions.xml │ │ ├── AndroidManifest.xml │ │ └── kotlin │ │ └── com │ │ └── zedalpha │ │ └── shadowgadgets │ │ └── demo │ │ ├── internal │ │ ├── ContentCardView.kt │ │ ├── TitleSwitcher.kt │ │ ├── SlantGridDrawable.kt │ │ ├── Utils.kt │ │ └── ControlView.kt │ │ └── topic │ │ ├── PlaneTopic.kt │ │ ├── Topic.kt │ │ ├── IrregularTopic.kt │ │ ├── ApplyTopic.kt │ │ └── compat │ │ └── ViewIntroPanel.kt └── build.gradle.kts ├── stubs ├── .gitignore ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── android │ │ └── view │ │ ├── HardwareCanvas.java │ │ └── DisplayListCanvas.java └── build.gradle.kts ├── view ├── .gitignore ├── lint │ ├── .gitignore │ ├── src │ │ ├── main │ │ │ ├── resources │ │ │ │ └── META-INF │ │ │ │ │ └── services │ │ │ │ │ └── com.android.tools.lint.client.api.IssueRegistry │ │ │ └── kotlin │ │ │ │ └── com │ │ │ │ └── zedalpha │ │ │ │ └── shadowgadgets │ │ │ │ └── view │ │ │ │ └── lint │ │ │ │ ├── RelativeOverlapDetectorSG.kt │ │ │ │ ├── MotionLayoutIdDetectorSG.kt │ │ │ │ ├── UseCompoundDrawableDetectorSG.kt │ │ │ │ ├── ChildCountDetectorSG.kt │ │ │ │ ├── internal │ │ │ │ ├── ElementWrapper.kt │ │ │ │ ├── ContextWrappers.kt │ │ │ │ ├── BaseDetector.kt │ │ │ │ ├── LibraryConstants.kt │ │ │ │ └── ConfigurationWrapper.kt │ │ │ │ ├── ConstraintLayoutDetectorSG.kt │ │ │ │ ├── MotionLayoutDetectorSG.kt │ │ │ │ ├── ObjectAnimatorDetectorSG.kt │ │ │ │ ├── ViewIssueRegistry.kt │ │ │ │ ├── InefficientWeightDetectorSG.kt │ │ │ │ ├── NestedScrollingWidgetDetectorSG.kt │ │ │ │ ├── UselessViewDetectorSG.kt │ │ │ │ └── WrongIdDetectorSG.kt │ │ └── test │ │ │ └── kotlin │ │ │ └── com │ │ │ └── zedalpha │ │ │ └── shadowgadgets │ │ │ └── view │ │ │ └── lint │ │ │ ├── RelativeOverlapDetectorSGTest.kt │ │ │ ├── UseCompoundDrawableDetectorSGTest.kt │ │ │ ├── MotionLayoutIdDetectorSGTest.kt │ │ │ ├── InefficientWeightDetectorSGTest.kt │ │ │ ├── ShadowAttributesDetectorTest.kt │ │ │ └── ConstraintLayoutDetectorSGTest.kt │ └── build.gradle.kts ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ ├── kotlin │ │ └── com │ │ │ └── zedalpha │ │ │ └── shadowgadgets │ │ │ └── view │ │ │ ├── shadow │ │ │ ├── DrawPlane.kt │ │ │ ├── NullShadow.kt │ │ │ ├── SingleController.kt │ │ │ ├── SoloController.kt │ │ │ ├── GroupController.kt │ │ │ ├── OverlayController.kt │ │ │ └── GroupShadow.kt │ │ │ ├── internal │ │ │ ├── BaseDrawable.kt │ │ │ ├── ShadowAttributes.kt │ │ │ └── MaterialComponentsUtils.kt │ │ │ ├── drawable │ │ │ └── DrawableController.kt │ │ │ ├── viewgroup │ │ │ ├── RecyclingManager.kt │ │ │ ├── ShadowsRecyclerView.kt │ │ │ ├── ShadowsGridView.kt │ │ │ ├── ShadowsListView.kt │ │ │ ├── ShadowsStackView.kt │ │ │ ├── ShadowsExpandableListView.kt │ │ │ ├── ShadowsRadioGroup.kt │ │ │ ├── ShadowsMotionLayout.kt │ │ │ ├── ShadowsFrameLayout.kt │ │ │ ├── ShadowsCoordinatorLayout.kt │ │ │ ├── ShadowsLinearLayout.kt │ │ │ ├── ShadowsRelativeLayout.kt │ │ │ ├── ShadowsConstraintLayout.kt │ │ │ ├── ShadowsChipGroup.kt │ │ │ └── ShadowsMaterialButtonToggleGroup.kt │ │ │ └── ShadowPlane.kt │ │ └── res │ │ └── values │ │ ├── public.xml │ │ ├── ids.xml │ │ └── attrs.xml ├── build.gradle.kts └── consumer-rules.pro ├── compose ├── .gitignore ├── consumer-rules.pro ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ └── kotlin │ │ └── com │ │ └── zedalpha │ │ └── shadowgadgets │ │ └── compose │ │ └── ExperimentalColorCompat.kt └── build.gradle.kts ├── jitpack.yml ├── gradle ├── build-logic │ ├── gradle.properties │ ├── settings.gradle.kts │ └── convention │ │ ├── build.gradle.kts │ │ └── src │ │ └── main │ │ └── kotlin │ │ ├── AndroidLibraryConventionPlugin.kt │ │ └── PublishConventionPlugin.kt ├── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties └── libs.versions.toml ├── images ├── layout_editor.png ├── plane_inline.png ├── intro_clip_broken.png ├── intro_clip_fixed.png ├── intro_color_compat.png ├── view_path_provider.png ├── parent_matrix_defect.png ├── plane_background_broken.png ├── plane_foreground_broken.png └── logo-icon.svg ├── .gitignore ├── settings.gradle.kts ├── gradle.properties ├── LICENSE.txt └── gradlew.bat /core/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /demo/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /stubs/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /view/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /compose/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /compose/consumer-rules.pro: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /view/lint/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /jitpack.yml: -------------------------------------------------------------------------------- 1 | jdk: 2 | - openjdk17 -------------------------------------------------------------------------------- /core/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /view/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /compose/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /stubs/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /gradle/build-logic/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.caching=true 2 | org.gradle.configuration-cache=true -------------------------------------------------------------------------------- /images/layout_editor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zed-alpha/shadow-gadgets/HEAD/images/layout_editor.png -------------------------------------------------------------------------------- /images/plane_inline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zed-alpha/shadow-gadgets/HEAD/images/plane_inline.png -------------------------------------------------------------------------------- /images/intro_clip_broken.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zed-alpha/shadow-gadgets/HEAD/images/intro_clip_broken.png -------------------------------------------------------------------------------- /images/intro_clip_fixed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zed-alpha/shadow-gadgets/HEAD/images/intro_clip_fixed.png -------------------------------------------------------------------------------- /images/intro_color_compat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zed-alpha/shadow-gadgets/HEAD/images/intro_color_compat.png -------------------------------------------------------------------------------- /images/view_path_provider.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zed-alpha/shadow-gadgets/HEAD/images/view_path_provider.png -------------------------------------------------------------------------------- /images/parent_matrix_defect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zed-alpha/shadow-gadgets/HEAD/images/parent_matrix_defect.png -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zed-alpha/shadow-gadgets/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /images/plane_background_broken.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zed-alpha/shadow-gadgets/HEAD/images/plane_background_broken.png -------------------------------------------------------------------------------- /images/plane_foreground_broken.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zed-alpha/shadow-gadgets/HEAD/images/plane_foreground_broken.png -------------------------------------------------------------------------------- /core/consumer-rules.pro: -------------------------------------------------------------------------------- 1 | -dontwarn android.view.DisplayListCanvas 2 | -dontwarn android.view.HardwareCanvas 3 | -dontwarn android.view.RenderNode -------------------------------------------------------------------------------- /view/lint/src/main/resources/META-INF/services/com.android.tools.lint.client.api.IssueRegistry: -------------------------------------------------------------------------------- 1 | com.zedalpha.shadowgadgets.view.lint.ViewIssueRegistry -------------------------------------------------------------------------------- /core/src/main/res/values/ids.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /demo/src/main/res/mipmap-hdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zed-alpha/shadow-gadgets/HEAD/demo/src/main/res/mipmap-hdpi/ic_launcher.webp -------------------------------------------------------------------------------- /demo/src/main/res/mipmap-mdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zed-alpha/shadow-gadgets/HEAD/demo/src/main/res/mipmap-mdpi/ic_launcher.webp -------------------------------------------------------------------------------- /demo/src/main/res/mipmap-xhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zed-alpha/shadow-gadgets/HEAD/demo/src/main/res/mipmap-xhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /demo/src/main/res/mipmap-xxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zed-alpha/shadow-gadgets/HEAD/demo/src/main/res/mipmap-xxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /demo/src/main/res/mipmap-xxxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zed-alpha/shadow-gadgets/HEAD/demo/src/main/res/mipmap-xxxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /demo/src/main/res/mipmap-hdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zed-alpha/shadow-gadgets/HEAD/demo/src/main/res/mipmap-hdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /demo/src/main/res/mipmap-mdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zed-alpha/shadow-gadgets/HEAD/demo/src/main/res/mipmap-mdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /demo/src/main/res/mipmap-xhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zed-alpha/shadow-gadgets/HEAD/demo/src/main/res/mipmap-xhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /demo/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zed-alpha/shadow-gadgets/HEAD/demo/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /core/src/main/res/values/public.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /demo/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zed-alpha/shadow-gadgets/HEAD/demo/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .idea/ 3 | captures/ 4 | 5 | .gradle/ 6 | build/ 7 | 8 | .kotlin/ 9 | 10 | local.properties 11 | 12 | .DS_Store 13 | 14 | /docs 15 | /previous -------------------------------------------------------------------------------- /demo/src/main/res/drawable/bg_root.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /core/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /demo/src/main/res/drawable/bg_rounded_rectangle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /core/src/main/kotlin/com/zedalpha/shadowgadgets/core/ListUtils.kt: -------------------------------------------------------------------------------- 1 | package com.zedalpha.shadowgadgets.core 2 | 3 | public inline fun List.fastForEach(block: (T) -> Unit) { 4 | for (index in indices) { 5 | val element = get(index) 6 | block(element) 7 | } 8 | } -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Mar 04 17:55:35 EST 2025 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip 5 | zipStoreBase=GRADLE_USER_HOME 6 | zipStorePath=wrapper/dists -------------------------------------------------------------------------------- /demo/src/main/res/drawable/bg_drop_target.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | -------------------------------------------------------------------------------- /demo/src/main/res/drawable/divider.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | -------------------------------------------------------------------------------- /demo/src/main/res/layout/compose_view.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /demo/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 15dp 4 | 5 | 12dp 6 | 6dp 7 | 8 | -------------------------------------------------------------------------------- /view/src/main/kotlin/com/zedalpha/shadowgadgets/view/shadow/DrawPlane.kt: -------------------------------------------------------------------------------- 1 | package com.zedalpha.shadowgadgets.view.shadow 2 | 3 | internal interface DrawPlane { 4 | 5 | fun addShadow(shadow: GroupShadow) {} 6 | 7 | fun removeShadow(shadow: GroupShadow) {} 8 | 9 | fun invalidatePlane() 10 | 11 | fun dispose() {} 12 | } -------------------------------------------------------------------------------- /demo/src/main/res/drawable/bg_roundish_square.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | -------------------------------------------------------------------------------- /core/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | alias(libs.plugins.shadowgadgets.android.library) 3 | alias(libs.plugins.shadowgadgets.publish) 4 | } 5 | 6 | android { 7 | namespace = "com.zedalpha.shadowgadgets.core" 8 | } 9 | 10 | dependencies { 11 | 12 | compileOnly(projects.stubs) 13 | 14 | implementation(libs.androidx.core.ktx) 15 | } -------------------------------------------------------------------------------- /stubs/src/main/java/android/view/HardwareCanvas.java: -------------------------------------------------------------------------------- 1 | package android.view; 2 | 3 | import android.graphics.Canvas; 4 | 5 | import androidx.annotation.NonNull; 6 | 7 | /** 8 | * @noinspection EmptyMethod, unused 9 | */ 10 | public class HardwareCanvas extends Canvas { 11 | 12 | public void drawRenderNode(@NonNull RenderNode renderNode) {} 13 | } -------------------------------------------------------------------------------- /stubs/src/main/java/android/view/DisplayListCanvas.java: -------------------------------------------------------------------------------- 1 | package android.view; 2 | 3 | import android.graphics.Canvas; 4 | 5 | import androidx.annotation.NonNull; 6 | 7 | /** 8 | * @noinspection EmptyMethod, unused 9 | */ 10 | public class DisplayListCanvas extends Canvas { 11 | 12 | public void drawRenderNode(@NonNull RenderNode renderNode) {} 13 | } -------------------------------------------------------------------------------- /demo/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /demo/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /gradle/build-logic/settings.gradle.kts: -------------------------------------------------------------------------------- 1 | dependencyResolutionManagement { 2 | @Suppress("UnstableApiUsage") 3 | repositories { 4 | google() 5 | mavenCentral() 6 | } 7 | versionCatalogs { 8 | create("libs") { 9 | from(files("../libs.versions.toml")) 10 | } 11 | } 12 | } 13 | 14 | rootProject.name = "build-logic" 15 | 16 | include(":convention") -------------------------------------------------------------------------------- /demo/src/main/res/drawable/ic_clear.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /demo/src/main/res/drawable/ic_add.xml: -------------------------------------------------------------------------------- 1 | 8 | 11 | -------------------------------------------------------------------------------- /demo/src/main/res/drawable/ic_arrow_up.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | -------------------------------------------------------------------------------- /demo/src/main/res/anim/slide_in_top.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 11 | -------------------------------------------------------------------------------- /stubs/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | alias(libs.plugins.android.library) 3 | } 4 | 5 | android { 6 | namespace = "com.zedalpha.shadowgadgets.stubs" 7 | compileSdk = 35 8 | 9 | defaultConfig { 10 | minSdk = 21 11 | } 12 | compileOptions { 13 | sourceCompatibility = JavaVersion.VERSION_17 14 | targetCompatibility = JavaVersion.VERSION_17 15 | } 16 | } 17 | 18 | dependencies { 19 | api(libs.androidx.annotation) 20 | } -------------------------------------------------------------------------------- /demo/src/main/res/anim/slide_in_bottom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 11 | -------------------------------------------------------------------------------- /demo/src/main/res/anim/slide_out_bottom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 11 | -------------------------------------------------------------------------------- /demo/src/main/res/anim/slide_out_top.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 11 | -------------------------------------------------------------------------------- /demo/src/main/res/drawable/ic_arrow_back.xml: -------------------------------------------------------------------------------- 1 | 8 | 11 | -------------------------------------------------------------------------------- /demo/src/main/res/drawable/ic_arrow_forward.xml: -------------------------------------------------------------------------------- 1 | 8 | 11 | -------------------------------------------------------------------------------- /compose/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | alias(libs.plugins.shadowgadgets.android.library) 3 | alias(libs.plugins.kotlin.compose) 4 | alias(libs.plugins.shadowgadgets.publish) 5 | } 6 | 7 | android { 8 | namespace = "com.zedalpha.shadowgadgets.compose" 9 | } 10 | 11 | dependencies { 12 | 13 | implementation(projects.core) 14 | 15 | implementation(libs.androidx.core.ktx) 16 | implementation(platform(libs.compose.bom)) 17 | implementation(libs.compose.ui) 18 | } -------------------------------------------------------------------------------- /core/src/main/kotlin/com/zedalpha/shadowgadgets/core/shadow/BaseView.kt: -------------------------------------------------------------------------------- 1 | package com.zedalpha.shadowgadgets.core.shadow 2 | 3 | import android.annotation.SuppressLint 4 | import android.content.Context 5 | import android.view.View 6 | 7 | internal abstract class BaseView(context: Context) : View(context) { 8 | 9 | override fun forceLayout() {} 10 | 11 | @SuppressLint("MissingSuperCall") override fun requestLayout() {} 12 | 13 | override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {} 14 | } -------------------------------------------------------------------------------- /core/src/main/kotlin/com/zedalpha/shadowgadgets/core/layer/ManagedLayer.kt: -------------------------------------------------------------------------------- 1 | package com.zedalpha.shadowgadgets.core.layer 2 | 3 | import android.graphics.Canvas 4 | import android.graphics.Paint 5 | 6 | internal interface ManagedLayer { 7 | 8 | val layerDraw: LayerDraw 9 | 10 | fun setSize(width: Int, height: Int) 11 | 12 | fun setLayerPaint(paint: Paint) 13 | 14 | fun draw(canvas: Canvas) 15 | 16 | fun recreate() 17 | 18 | fun dispose() 19 | 20 | fun invalidate() {} 21 | 22 | fun refresh() {} 23 | } -------------------------------------------------------------------------------- /view/src/main/kotlin/com/zedalpha/shadowgadgets/view/internal/BaseDrawable.kt: -------------------------------------------------------------------------------- 1 | package com.zedalpha.shadowgadgets.view.internal 2 | 3 | import android.graphics.ColorFilter 4 | import android.graphics.PixelFormat 5 | import android.graphics.drawable.Drawable 6 | 7 | internal abstract class BaseDrawable : Drawable() { 8 | 9 | @Suppress("OVERRIDE_DEPRECATION") 10 | override fun getOpacity() = PixelFormat.TRANSLUCENT 11 | 12 | override fun setAlpha(alpha: Int) {} 13 | 14 | override fun setColorFilter(filter: ColorFilter?) {} 15 | } -------------------------------------------------------------------------------- /demo/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #44ff3333 5 | #4433ff33 6 | #443333ff 7 | #33ffffff 8 | 9 | #ffffffff 10 | #fffafafa 11 | #ffdfdfdf 12 | #ffe2e2e2 13 | 14 | -------------------------------------------------------------------------------- /view/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | alias(libs.plugins.shadowgadgets.android.library) 3 | alias(libs.plugins.shadowgadgets.publish) 4 | } 5 | 6 | android { 7 | namespace = "com.zedalpha.shadowgadgets.view" 8 | 9 | buildFeatures { 10 | buildConfig = true 11 | } 12 | } 13 | 14 | dependencies { 15 | 16 | implementation(projects.core) 17 | lintPublish(projects.view.lint) 18 | 19 | implementation(libs.androidx.core.ktx) 20 | implementation(libs.androidx.appcompat) 21 | implementation(libs.material.components) 22 | } -------------------------------------------------------------------------------- /view/lint/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.jetbrains.kotlin.gradle.dsl.JvmTarget 2 | 3 | plugins { 4 | id("java-library") 5 | alias(libs.plugins.kotlin.jvm) 6 | alias(libs.plugins.android.lint) 7 | } 8 | 9 | java { 10 | sourceCompatibility = JavaVersion.VERSION_17 11 | targetCompatibility = JavaVersion.VERSION_17 12 | } 13 | 14 | kotlin { 15 | compilerOptions { 16 | jvmTarget = JvmTarget.JVM_17 17 | } 18 | } 19 | 20 | dependencies { 21 | compileOnly(libs.bundles.lint.api) 22 | testImplementation(libs.bundles.lint.tests) 23 | } -------------------------------------------------------------------------------- /demo/src/main/res/layout/internal_title_switcher.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /view/src/main/kotlin/com/zedalpha/shadowgadgets/view/shadow/NullShadow.kt: -------------------------------------------------------------------------------- 1 | package com.zedalpha.shadowgadgets.view.shadow 2 | 3 | import android.graphics.Outline 4 | import android.view.View 5 | import android.view.ViewOutlineProvider 6 | 7 | internal class NullShadow(targetView: View) : ViewShadow(targetView, null) { 8 | 9 | init { 10 | targetView.outlineProvider = object : ViewOutlineProvider() { 11 | override fun getOutline(view: View, outline: Outline) { 12 | provider.getOutline(view, outline) 13 | outline.alpha = 0F 14 | } 15 | } 16 | } 17 | 18 | override fun invalidate() {} 19 | } -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | includeBuild("gradle/build-logic") 3 | repositories { 4 | google() 5 | mavenCentral() 6 | gradlePluginPortal() 7 | } 8 | } 9 | 10 | @Suppress("UnstableApiUsage") 11 | dependencyResolutionManagement { 12 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) 13 | repositories { 14 | google() 15 | mavenCentral() 16 | } 17 | } 18 | 19 | rootProject.name = "shadow-gadgets" 20 | 21 | enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") 22 | 23 | include(":stubs") 24 | include(":core") 25 | include(":view") 26 | include(":view:lint") 27 | include(":compose") 28 | include(":demo") -------------------------------------------------------------------------------- /view/consumer-rules.pro: -------------------------------------------------------------------------------- 1 | -if class androidx.constraintlayout.motion.widget.KeyFrames 2 | -keep class androidx.constraintlayout.motion.widget.KeyAttributes 3 | 4 | -if class androidx.constraintlayout.motion.widget.KeyFrames 5 | -keep class androidx.constraintlayout.motion.widget.KeyPosition 6 | 7 | -if class androidx.constraintlayout.motion.widget.KeyFrames 8 | -keep class androidx.constraintlayout.motion.widget.KeyCycle 9 | 10 | -if class androidx.constraintlayout.motion.widget.KeyFrames 11 | -keep class androidx.constraintlayout.motion.widget.KeyTimeCycle 12 | 13 | -if class androidx.constraintlayout.motion.widget.KeyFrames 14 | -keep class androidx.constraintlayout.motion.widget.KeyTrigger -------------------------------------------------------------------------------- /view/src/main/kotlin/com/zedalpha/shadowgadgets/view/drawable/DrawableController.kt: -------------------------------------------------------------------------------- 1 | package com.zedalpha.shadowgadgets.view.drawable 2 | 3 | import android.view.View 4 | import com.zedalpha.shadowgadgets.core.layer.Layer 5 | import com.zedalpha.shadowgadgets.view.shadow.SingleController 6 | 7 | internal class DrawableController( 8 | private val drawable: ShadowDrawable, 9 | ownerView: View? 10 | ) : SingleController(ownerView, null) { 11 | 12 | override fun shouldInvalidate(): Boolean = false 13 | 14 | override fun invalidate() = drawable.invalidateSelf() 15 | 16 | override fun onCreateLayer(layer: Layer) { 17 | super.onCreateLayer(layer) 18 | val bounds = drawable.bounds 19 | layer.setSize(bounds.width(), bounds.height()) 20 | } 21 | } -------------------------------------------------------------------------------- /demo/src/main/res/layout/dialog_root.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /compose/src/main/kotlin/com/zedalpha/shadowgadgets/compose/ExperimentalColorCompat.kt: -------------------------------------------------------------------------------- 1 | package com.zedalpha.shadowgadgets.compose 2 | 3 | /** 4 | * Marks declarations that involve color compat as experimental. 5 | * 6 | * This is @OptIn only because the current implementation requires a separate 7 | * color layer for each shadow. The API is frozen, however, and this feature is 8 | * as solid as the clip, so if the overhead is acceptable for a given setup, 9 | * there shouldn't be any other issues. 10 | */ 11 | @Deprecated("Opt-in requirement for color compat has been removed.") 12 | @RequiresOptIn("Color compat requires @OptIn. It is currently experimental.") 13 | @Retention(AnnotationRetention.BINARY) 14 | @Target(AnnotationTarget.FUNCTION) 15 | public annotation class ExperimentalColorCompat -------------------------------------------------------------------------------- /view/src/main/res/values/public.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /demo/src/main/res/layout/dialog_description.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 20 | 21 | -------------------------------------------------------------------------------- /demo/src/main/res/layout/view_root.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /core/src/main/kotlin/com/zedalpha/shadowgadgets/core/shadow/CoreShadow.kt: -------------------------------------------------------------------------------- 1 | package com.zedalpha.shadowgadgets.core.shadow 2 | 3 | import android.graphics.Canvas 4 | import android.graphics.Outline 5 | import androidx.annotation.CallSuper 6 | import com.zedalpha.shadowgadgets.core.Shadow 7 | import com.zedalpha.shadowgadgets.core.disableZ 8 | import com.zedalpha.shadowgadgets.core.enableZ 9 | 10 | internal abstract class CoreShadow : Shadow { 11 | 12 | protected val outline = Outline() 13 | 14 | @CallSuper 15 | override fun setOutline(outline: Outline) = 16 | this.outline.set(outline) 17 | 18 | override fun draw(canvas: Canvas) { 19 | if (!canvas.isHardwareAccelerated) return 20 | 21 | enableZ(canvas) 22 | onDraw(canvas) 23 | disableZ(canvas) 24 | } 25 | 26 | protected abstract fun onDraw(canvas: Canvas) 27 | } -------------------------------------------------------------------------------- /core/src/main/kotlin/com/zedalpha/shadowgadgets/core/layer/LocationTracker.kt: -------------------------------------------------------------------------------- 1 | package com.zedalpha.shadowgadgets.core.layer 2 | 3 | import android.view.View 4 | 5 | public class LocationTracker(private val view: View) { 6 | 7 | private val current = intArrayOf(Int.MAX_VALUE, Int.MAX_VALUE) 8 | 9 | public fun initialize() { 10 | view.getLocationOnScreen(current) 11 | } 12 | 13 | private val tmp = IntArray(2) 14 | 15 | public fun checkLocationChanged(): Boolean = tmp.let { location -> 16 | view.getLocationOnScreen(location) 17 | current.checkUpdate(location) 18 | } 19 | 20 | private fun IntArray.checkUpdate(other: IntArray): Boolean = 21 | if (this[0] != other[0] || this[1] != other[1]) { 22 | this[0] = other[0]; this[1] = other[1] 23 | true 24 | } else { 25 | false 26 | } 27 | } -------------------------------------------------------------------------------- /view/src/main/res/values/ids.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 | -------------------------------------------------------------------------------- /demo/src/main/res/layout/item_description.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 17 | 23 | 24 | -------------------------------------------------------------------------------- /gradle/build-logic/convention/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.jetbrains.kotlin.gradle.dsl.JvmTarget 2 | 3 | plugins { 4 | `kotlin-dsl` 5 | } 6 | 7 | java { 8 | sourceCompatibility = JavaVersion.VERSION_17 9 | targetCompatibility = JavaVersion.VERSION_17 10 | } 11 | 12 | kotlin { 13 | compilerOptions { 14 | jvmTarget = JvmTarget.JVM_17 15 | } 16 | } 17 | 18 | dependencies { 19 | compileOnly(libs.android.gradle.plugin) 20 | compileOnly(libs.kotlin.gradle.plugin) 21 | compileOnly(libs.compose.gradle.plugin) 22 | } 23 | 24 | gradlePlugin { 25 | plugins { 26 | register("androidLibrary") { 27 | id = "shadowgadgets.android.library" 28 | implementationClass = "AndroidLibraryConventionPlugin" 29 | } 30 | register("publish") { 31 | id = "shadowgadgets.publish" 32 | implementationClass = "PublishConventionPlugin" 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Kotlin 2 | kotlin.code.style=official 3 | kotlin.daemon.jvmargs=-Xmx2048M 4 | 5 | # Gradle 6 | org.gradle.caching=true 7 | org.gradle.configuration-cache=true 8 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 9 | org.gradle.warning.mode=all 10 | 11 | # Android 12 | android.useAndroidX=true 13 | android.enableJetifier=false 14 | android.nonFinalResIds=true 15 | android.nonTransitiveRClass=true 16 | 17 | android.defaults.buildfeatures.aidl=false 18 | android.defaults.buildfeatures.renderscript=false 19 | android.defaults.buildfeatures.resvalues=false 20 | android.defaults.buildfeatures.shaders=false 21 | 22 | android.lint.useK2Uast=true 23 | 24 | # Dokka 25 | org.jetbrains.dokka.experimental.gradle.pluginMode=V2Enabled 26 | org.jetbrains.dokka.experimental.gradle.pluginMode.noWarn=true 27 | 28 | # Developer 29 | developer.name=zed-alpha 30 | repository.url=https://github.com/zed-alpha/shadow-gadgets 31 | group.id=com.zedalpha.shadowgadgets 32 | library.version=2.3.2 -------------------------------------------------------------------------------- /demo/src/main/res/layout/item_colorful.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 22 | 23 | -------------------------------------------------------------------------------- /view/lint/src/main/kotlin/com/zedalpha/shadowgadgets/view/lint/RelativeOverlapDetectorSG.kt: -------------------------------------------------------------------------------- 1 | package com.zedalpha.shadowgadgets.view.lint 2 | 3 | import com.android.tools.lint.checks.RelativeOverlapDetector 4 | import com.android.tools.lint.detector.api.Implementation 5 | import com.android.tools.lint.detector.api.Scope 6 | import com.zedalpha.shadowgadgets.view.lint.internal.BaseDetector 7 | import com.zedalpha.shadowgadgets.view.lint.internal.SHADOWS_RELATIVE_LAYOUT 8 | 9 | class RelativeOverlapDetectorSG : BaseDetector() { 10 | 11 | companion object { 12 | 13 | @JvmField 14 | val ISSUE_SG = RelativeOverlapDetector.ISSUE.copy( 15 | Implementation( 16 | RelativeOverlapDetectorSG::class.java, 17 | Scope.RESOURCE_FILE_SCOPE 18 | ) 19 | ) 20 | } 21 | 22 | override val detector = RelativeOverlapDetector() 23 | 24 | override val issues = mapOf( 25 | RelativeOverlapDetector.ISSUE to ISSUE_SG 26 | ) 27 | 28 | override val elements = listOf(SHADOWS_RELATIVE_LAYOUT) 29 | } -------------------------------------------------------------------------------- /view/lint/src/main/kotlin/com/zedalpha/shadowgadgets/view/lint/MotionLayoutIdDetectorSG.kt: -------------------------------------------------------------------------------- 1 | package com.zedalpha.shadowgadgets.view.lint 2 | 3 | import com.android.tools.lint.checks.MotionLayoutIdDetector 4 | import com.android.tools.lint.detector.api.Implementation 5 | import com.android.tools.lint.detector.api.Scope 6 | import com.zedalpha.shadowgadgets.view.lint.internal.BaseDetector 7 | import com.zedalpha.shadowgadgets.view.lint.internal.SHADOWS_MOTION_LAYOUT 8 | 9 | class MotionLayoutIdDetectorSG : BaseDetector() { 10 | 11 | companion object { 12 | 13 | @JvmField 14 | val MISSING_ID_SG = MotionLayoutIdDetector.MISSING_ID.copy( 15 | Implementation( 16 | MotionLayoutIdDetectorSG::class.java, 17 | Scope.RESOURCE_FILE_SCOPE 18 | ) 19 | ) 20 | } 21 | 22 | override val detector = MotionLayoutIdDetector() 23 | 24 | override val issues = mapOf( 25 | MotionLayoutIdDetector.MISSING_ID to MISSING_ID_SG 26 | ) 27 | 28 | override val elements = listOf(SHADOWS_MOTION_LAYOUT) 29 | } -------------------------------------------------------------------------------- /demo/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 13 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /view/lint/src/main/kotlin/com/zedalpha/shadowgadgets/view/lint/UseCompoundDrawableDetectorSG.kt: -------------------------------------------------------------------------------- 1 | package com.zedalpha.shadowgadgets.view.lint 2 | 3 | import com.android.tools.lint.checks.UseCompoundDrawableDetector 4 | import com.android.tools.lint.detector.api.Implementation 5 | import com.android.tools.lint.detector.api.Scope 6 | import com.zedalpha.shadowgadgets.view.lint.internal.BaseDetector 7 | import com.zedalpha.shadowgadgets.view.lint.internal.SHADOWS_LINEAR_LAYOUT 8 | 9 | class UseCompoundDrawableDetectorSG : BaseDetector() { 10 | 11 | companion object { 12 | 13 | @JvmField 14 | val ISSUE_SG = UseCompoundDrawableDetector.ISSUE.copy( 15 | Implementation( 16 | UseCompoundDrawableDetectorSG::class.java, 17 | Scope.RESOURCE_FILE_SCOPE 18 | ) 19 | ) 20 | } 21 | 22 | override val detector = UseCompoundDrawableDetector() 23 | 24 | override val issues = mapOf( 25 | UseCompoundDrawableDetector.ISSUE to ISSUE_SG 26 | ) 27 | 28 | override val elements = listOf(SHADOWS_LINEAR_LAYOUT) 29 | } -------------------------------------------------------------------------------- /demo/src/main/kotlin/com/zedalpha/shadowgadgets/demo/internal/ContentCardView.kt: -------------------------------------------------------------------------------- 1 | package com.zedalpha.shadowgadgets.demo.internal 2 | 3 | import android.content.Context 4 | import android.content.res.ColorStateList 5 | import android.graphics.Canvas 6 | import android.graphics.Color 7 | import android.util.AttributeSet 8 | import com.google.android.material.card.MaterialCardView 9 | import kotlin.math.roundToInt 10 | 11 | class ContentCardView @JvmOverloads constructor( 12 | context: Context, 13 | attrs: AttributeSet? = null 14 | ) : MaterialCardView(context, attrs) { 15 | 16 | private val drawable = SlantGridDrawable() 17 | 18 | init { 19 | setCardBackgroundColor(Color.WHITE) 20 | setStrokeColor(ColorStateList.valueOf(Color.LTGRAY)) 21 | strokeWidth = resources.displayMetrics.density.roundToInt() 22 | } 23 | 24 | override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { 25 | drawable.setBounds(0, 0, w, h) 26 | } 27 | 28 | override fun onDraw(canvas: Canvas) { 29 | drawable.draw(canvas) 30 | super.onDraw(canvas) 31 | } 32 | } -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 zed-alpha 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /view/lint/src/main/kotlin/com/zedalpha/shadowgadgets/view/lint/ChildCountDetectorSG.kt: -------------------------------------------------------------------------------- 1 | package com.zedalpha.shadowgadgets.view.lint 2 | 3 | import com.android.tools.lint.checks.ChildCountDetector 4 | import com.android.tools.lint.detector.api.Implementation 5 | import com.android.tools.lint.detector.api.Scope 6 | import com.zedalpha.shadowgadgets.view.lint.internal.BaseDetector 7 | import com.zedalpha.shadowgadgets.view.lint.internal.SHADOWS_GRID_VIEW 8 | import com.zedalpha.shadowgadgets.view.lint.internal.SHADOWS_LIST_VIEW 9 | 10 | class ChildCountDetectorSG : BaseDetector() { 11 | 12 | companion object { 13 | 14 | @JvmField 15 | val ADAPTER_VIEW_ISSUE_SG = ChildCountDetector.ADAPTER_VIEW_ISSUE.copy( 16 | Implementation( 17 | ChildCountDetectorSG::class.java, 18 | Scope.RESOURCE_FILE_SCOPE 19 | ) 20 | ) 21 | } 22 | 23 | override val detector = ChildCountDetector() 24 | 25 | override val issues = mapOf( 26 | ChildCountDetector.ADAPTER_VIEW_ISSUE to ADAPTER_VIEW_ISSUE_SG 27 | ) 28 | 29 | override val elements = listOf(SHADOWS_GRID_VIEW, SHADOWS_LIST_VIEW) 30 | } -------------------------------------------------------------------------------- /view/lint/src/main/kotlin/com/zedalpha/shadowgadgets/view/lint/internal/ElementWrapper.kt: -------------------------------------------------------------------------------- 1 | package com.zedalpha.shadowgadgets.view.lint.internal 2 | 3 | import com.android.AndroidXConstants 4 | import com.android.SdkConstants 5 | import org.w3c.dom.Element 6 | import org.w3c.dom.Node 7 | 8 | internal class ElementWrapper( 9 | private val wrapped: Element, 10 | ) : Element by wrapped { 11 | 12 | override fun getParentNode(): Node = run { 13 | val node = wrapped.parentNode 14 | if (node is Element) ElementWrapper(node) else node 15 | } 16 | 17 | override fun getTagName(): String = 18 | when (val actual = wrapped.tagName) { 19 | // NestedScrollingWidgetDetector 20 | SHADOWS_LIST_VIEW -> SdkConstants.LIST_VIEW 21 | SHADOWS_GRID_VIEW -> SdkConstants.GRID_VIEW 22 | // WrongIdDetector 23 | SHADOWS_RELATIVE_LAYOUT -> SdkConstants.RELATIVE_LAYOUT 24 | SHADOWS_CONSTRAINT_LAYOUT -> AndroidXConstants.CONSTRAINT_LAYOUT.newName() 25 | else -> actual 26 | } 27 | 28 | override fun toString(): String { 29 | return wrapped.toString() 30 | } 31 | } -------------------------------------------------------------------------------- /view/lint/src/main/kotlin/com/zedalpha/shadowgadgets/view/lint/ConstraintLayoutDetectorSG.kt: -------------------------------------------------------------------------------- 1 | package com.zedalpha.shadowgadgets.view.lint 2 | 3 | import com.android.tools.lint.checks.ConstraintLayoutDetector 4 | import com.android.tools.lint.detector.api.Implementation 5 | import com.android.tools.lint.detector.api.Scope 6 | import com.zedalpha.shadowgadgets.view.lint.internal.BaseDetector 7 | import com.zedalpha.shadowgadgets.view.lint.internal.SHADOWS_CONSTRAINT_LAYOUT 8 | import com.zedalpha.shadowgadgets.view.lint.internal.SHADOWS_MOTION_LAYOUT 9 | 10 | class ConstraintLayoutDetectorSG : BaseDetector() { 11 | 12 | companion object { 13 | 14 | @JvmField 15 | val ISSUE_SG = ConstraintLayoutDetector.ISSUE.copy( 16 | Implementation( 17 | ConstraintLayoutDetectorSG::class.java, 18 | Scope.RESOURCE_FILE_SCOPE 19 | ) 20 | ) 21 | } 22 | 23 | override val detector = ConstraintLayoutDetector() 24 | 25 | override val issues = mapOf( 26 | ConstraintLayoutDetector.ISSUE to ISSUE_SG 27 | ) 28 | 29 | override val elements = listOf( 30 | SHADOWS_CONSTRAINT_LAYOUT, 31 | SHADOWS_MOTION_LAYOUT 32 | ) 33 | } -------------------------------------------------------------------------------- /demo/src/main/res/layout/fragment_root.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 |