├── app
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── drawable
│ │ │ │ ├── poly.png
│ │ │ │ ├── airbnb.png
│ │ │ │ ├── google.png
│ │ │ │ ├── ic_qa.png
│ │ │ │ ├── quila.png
│ │ │ │ ├── facebook.png
│ │ │ │ ├── fengjing.png
│ │ │ │ ├── ic_design.png
│ │ │ │ ├── ic_logo.png
│ │ │ │ ├── playstore.png
│ │ │ │ ├── google_play.png
│ │ │ │ ├── ic_strategy.png
│ │ │ │ ├── ic_development.png
│ │ │ │ └── drawable_circle.xml
│ │ │ ├── mipmap-hdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-mdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ ├── doctor_male_round.png
│ │ │ │ └── ngr_patient_back_followup_statistics_1.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── values
│ │ │ │ ├── styles.xml
│ │ │ │ └── strings.xml
│ │ │ ├── values-w820dp
│ │ │ │ └── dimens.xml
│ │ │ └── layout
│ │ │ │ ├── activity_simplepath.xml
│ │ │ │ ├── activity_angle_auto.xml
│ │ │ │ ├── activity_simple_zdepth.xml
│ │ │ │ ├── activity_main.xml
│ │ │ │ ├── activity_change_zdepth.xml
│ │ │ │ └── activity_simple_auto.xml
│ │ ├── java
│ │ │ └── app
│ │ │ │ └── mosn
│ │ │ │ └── zdepthshadowsample
│ │ │ │ ├── SimpleZDepthActivity.java
│ │ │ │ ├── SimpleAutoActivity.java
│ │ │ │ ├── SimpleAngleAutoActivity.java
│ │ │ │ ├── BlurMaskFilterActivity.java
│ │ │ │ ├── SimplePathShadowActivity.java
│ │ │ │ ├── DisplayUtil.java
│ │ │ │ ├── BlurMaskFilterView.java
│ │ │ │ ├── ChangeZDepthActivity.java
│ │ │ │ ├── ClipView.java
│ │ │ │ └── MainActivity.java
│ │ └── AndroidManifest.xml
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── ytjojo
│ │ └── shadowlayout
│ │ └── ApplicationTest.java
├── proguard-rules.pro
└── build.gradle
├── library
├── .gitignore
├── src
│ └── main
│ │ ├── res
│ │ └── values
│ │ │ ├── strings.xml
│ │ │ └── attrs.xml
│ │ ├── java
│ │ └── com
│ │ │ └── ytjojo
│ │ │ └── shadowlayout
│ │ │ ├── utils
│ │ │ ├── DisplayUtils.java
│ │ │ └── ColorUtil.java
│ │ │ ├── shadowdelegate
│ │ │ ├── ShadowDelegate.java
│ │ │ ├── PathModel.java
│ │ │ ├── AutoModel.java
│ │ │ └── ExactlyModel.java
│ │ │ ├── shadow
│ │ │ ├── Shadow.java
│ │ │ ├── ShadowOval.java
│ │ │ └── ShadowRect.java
│ │ │ ├── ShadowLayout.java
│ │ │ └── ZDepth.java
│ │ └── AndroidManifest.xml
├── proguard-rules.pro
├── gradle.properties
└── build.gradle
├── settings.gradle
├── blobs
├── 20180318092933.png
├── 20180318093105.png
├── 20180318093925.png
├── 20180318094946.png
├── 20180318112348.png
├── 20180318142047.png
├── shadow_zdepth.png
├── ezgif.com-gif-maker.gif
├── zdepthshadow_zdepth_5.png
├── Screenshot_20171104-170419.jpg
├── Screenshot_20171104-170752.jpg
├── Screenshot_20171104-170818.jpg
├── Screenshot_20171104-170835.jpg
├── Screenshot_20171104-170938.jpg
├── Screenshot_20171105-175052.jpg
├── Screenshot_20171105-175326.jpg
├── Screenshot_20171105-180713.jpg
└── ezgif.com-video-to-gif_zdepth.gif
├── .gitignore
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── git命令.txt
├── gradlew.bat
├── gradlew
├── gradle-mvn-push.gradle
├── README.md
├── LICENSE.txt
└── 强大的剪裁+阴影效果布局ShadowLayout.md
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/library/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':library'
2 |
--------------------------------------------------------------------------------
/blobs/20180318092933.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ytjojo/ShadowLayout/HEAD/blobs/20180318092933.png
--------------------------------------------------------------------------------
/blobs/20180318093105.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ytjojo/ShadowLayout/HEAD/blobs/20180318093105.png
--------------------------------------------------------------------------------
/blobs/20180318093925.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ytjojo/ShadowLayout/HEAD/blobs/20180318093925.png
--------------------------------------------------------------------------------
/blobs/20180318094946.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ytjojo/ShadowLayout/HEAD/blobs/20180318094946.png
--------------------------------------------------------------------------------
/blobs/20180318112348.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ytjojo/ShadowLayout/HEAD/blobs/20180318112348.png
--------------------------------------------------------------------------------
/blobs/20180318142047.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ytjojo/ShadowLayout/HEAD/blobs/20180318142047.png
--------------------------------------------------------------------------------
/blobs/shadow_zdepth.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ytjojo/ShadowLayout/HEAD/blobs/shadow_zdepth.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea
5 | .DS_Store
6 | /build
7 | /captures
8 |
--------------------------------------------------------------------------------
/blobs/ezgif.com-gif-maker.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ytjojo/ShadowLayout/HEAD/blobs/ezgif.com-gif-maker.gif
--------------------------------------------------------------------------------
/blobs/zdepthshadow_zdepth_5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ytjojo/ShadowLayout/HEAD/blobs/zdepthshadow_zdepth_5.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/poly.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ytjojo/ShadowLayout/HEAD/app/src/main/res/drawable/poly.png
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ytjojo/ShadowLayout/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/app/src/main/res/drawable/airbnb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ytjojo/ShadowLayout/HEAD/app/src/main/res/drawable/airbnb.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/google.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ytjojo/ShadowLayout/HEAD/app/src/main/res/drawable/google.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_qa.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ytjojo/ShadowLayout/HEAD/app/src/main/res/drawable/ic_qa.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/quila.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ytjojo/ShadowLayout/HEAD/app/src/main/res/drawable/quila.png
--------------------------------------------------------------------------------
/blobs/Screenshot_20171104-170419.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ytjojo/ShadowLayout/HEAD/blobs/Screenshot_20171104-170419.jpg
--------------------------------------------------------------------------------
/blobs/Screenshot_20171104-170752.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ytjojo/ShadowLayout/HEAD/blobs/Screenshot_20171104-170752.jpg
--------------------------------------------------------------------------------
/blobs/Screenshot_20171104-170818.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ytjojo/ShadowLayout/HEAD/blobs/Screenshot_20171104-170818.jpg
--------------------------------------------------------------------------------
/blobs/Screenshot_20171104-170835.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ytjojo/ShadowLayout/HEAD/blobs/Screenshot_20171104-170835.jpg
--------------------------------------------------------------------------------
/blobs/Screenshot_20171104-170938.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ytjojo/ShadowLayout/HEAD/blobs/Screenshot_20171104-170938.jpg
--------------------------------------------------------------------------------
/blobs/Screenshot_20171105-175052.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ytjojo/ShadowLayout/HEAD/blobs/Screenshot_20171105-175052.jpg
--------------------------------------------------------------------------------
/blobs/Screenshot_20171105-175326.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ytjojo/ShadowLayout/HEAD/blobs/Screenshot_20171105-175326.jpg
--------------------------------------------------------------------------------
/blobs/Screenshot_20171105-180713.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ytjojo/ShadowLayout/HEAD/blobs/Screenshot_20171105-180713.jpg
--------------------------------------------------------------------------------
/library/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | ShadowLayout
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/facebook.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ytjojo/ShadowLayout/HEAD/app/src/main/res/drawable/facebook.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/fengjing.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ytjojo/ShadowLayout/HEAD/app/src/main/res/drawable/fengjing.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_design.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ytjojo/ShadowLayout/HEAD/app/src/main/res/drawable/ic_design.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ytjojo/ShadowLayout/HEAD/app/src/main/res/drawable/ic_logo.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ytjojo/ShadowLayout/HEAD/app/src/main/res/drawable/playstore.png
--------------------------------------------------------------------------------
/blobs/ezgif.com-video-to-gif_zdepth.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ytjojo/ShadowLayout/HEAD/blobs/ezgif.com-video-to-gif_zdepth.gif
--------------------------------------------------------------------------------
/app/src/main/res/drawable/google_play.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ytjojo/ShadowLayout/HEAD/app/src/main/res/drawable/google_play.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_strategy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ytjojo/ShadowLayout/HEAD/app/src/main/res/drawable/ic_strategy.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_development.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ytjojo/ShadowLayout/HEAD/app/src/main/res/drawable/ic_development.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ytjojo/ShadowLayout/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ytjojo/ShadowLayout/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ytjojo/ShadowLayout/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ytjojo/ShadowLayout/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ytjojo/ShadowLayout/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/doctor_male_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ytjojo/ShadowLayout/HEAD/app/src/main/res/mipmap-xxhdpi/doctor_male_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ngr_patient_back_followup_statistics_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ytjojo/ShadowLayout/HEAD/app/src/main/res/mipmap-xxhdpi/ngr_patient_back_followup_statistics_1.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/drawable_circle.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Nov 01 09:49:13 GMT+08:00 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
7 |
--------------------------------------------------------------------------------
/library/src/main/java/com/ytjojo/shadowlayout/utils/DisplayUtils.java:
--------------------------------------------------------------------------------
1 | package com.ytjojo.shadowlayout.utils;
2 |
3 | import android.content.Context;
4 |
5 | public class DisplayUtils {
6 |
7 | public static int convertDpToPx(Context context, float dp) {
8 | float scale = context.getResources().getDisplayMetrics().density;
9 | return (int) (dp * scale + 0.5f);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/git命令.txt:
--------------------------------------------------------------------------------
1 |
2 | http://www.cnblogs.com/shines77/p/3460274.html
3 |
4 | $ git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch gradle.properties' --prune-empty --tag-name-filter cat -- --all
5 |
6 | $ git push origin master --force
7 |
8 | $ git push origin master --force --tags
9 |
10 | $ rm -rf .git/refs/original/
11 |
12 | $ git reflog expire --expire=now --all
13 |
14 | $ git gc --prune=now
15 |
16 | $ git gc --aggressive --prune=now
17 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/ytjojo/shadowlayout/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.ytjojo.shadowlayout;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/app/src/main/java/app/mosn/zdepthshadowsample/SimpleZDepthActivity.java:
--------------------------------------------------------------------------------
1 | package app.mosn.zdepthshadowsample;
2 |
3 | import android.os.Bundle;
4 | import android.support.v7.app.AppCompatActivity;
5 |
6 | import com.ytjojo.shadowlayout.demo.R;
7 |
8 | public class SimpleZDepthActivity extends AppCompatActivity {
9 |
10 | @Override
11 | protected void onCreate(Bundle savedInstanceState) {
12 | super.onCreate(savedInstanceState);
13 | setContentView(R.layout.activity_simple_zdepth);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/library/src/main/java/com/ytjojo/shadowlayout/utils/ColorUtil.java:
--------------------------------------------------------------------------------
1 | package com.ytjojo.shadowlayout.utils;
2 |
3 | import android.graphics.Color;
4 |
5 | /**
6 | * Created by Administrator on 2017/11/3 0003.
7 | */
8 |
9 | public class ColorUtil {
10 | public final static int MAX_ALPHA = 255;
11 | public static int adjustAlpha(int shadowAlpha,int shadowColor) {
12 | return Color.argb(
13 | shadowAlpha,
14 | Color.red(shadowColor),
15 | Color.green(shadowColor),
16 | Color.blue(shadowColor)
17 | );
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/app/src/main/java/app/mosn/zdepthshadowsample/SimpleAutoActivity.java:
--------------------------------------------------------------------------------
1 | package app.mosn.zdepthshadowsample;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 | import android.support.v7.app.AppCompatActivity;
6 |
7 | import com.ytjojo.shadowlayout.demo.R;
8 |
9 | /**
10 | * Created by Administrator on 2017/11/3 0003.
11 | */
12 |
13 | public class SimpleAutoActivity extends AppCompatActivity {
14 | @Override
15 | protected void onCreate(@Nullable Bundle savedInstanceState) {
16 | super.onCreate(savedInstanceState);
17 | setContentView(R.layout.activity_simple_auto);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/app/src/main/java/app/mosn/zdepthshadowsample/SimpleAngleAutoActivity.java:
--------------------------------------------------------------------------------
1 | package app.mosn.zdepthshadowsample;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 | import android.support.v7.app.AppCompatActivity;
6 |
7 | import com.ytjojo.shadowlayout.demo.R;
8 |
9 | /**
10 | * Created by Administrator on 2017/11/3 0003.
11 | */
12 |
13 | public class SimpleAngleAutoActivity extends AppCompatActivity {
14 |
15 | @Override
16 | protected void onCreate(@Nullable Bundle savedInstanceState) {
17 | super.onCreate(savedInstanceState);
18 | setContentView(R.layout.activity_angle_auto);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/app/src/main/java/app/mosn/zdepthshadowsample/BlurMaskFilterActivity.java:
--------------------------------------------------------------------------------
1 | package app.mosn.zdepthshadowsample;
2 |
3 | import android.content.Context;
4 | import android.os.Bundle;
5 | import android.support.annotation.Nullable;
6 | import android.support.v7.app.AppCompatActivity;
7 | import android.util.AttributeSet;
8 | import android.view.View;
9 |
10 | /**
11 | * Created by Administrator on 2018/3/18 0018.
12 | */
13 |
14 | public class BlurMaskFilterActivity extends AppCompatActivity {
15 | @Override
16 | protected void onCreate(@Nullable Bundle savedInstanceState) {
17 | super.onCreate(savedInstanceState);
18 | setContentView(new ClipView(this));
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/library/src/main/java/com/ytjojo/shadowlayout/shadowdelegate/ShadowDelegate.java:
--------------------------------------------------------------------------------
1 | package com.ytjojo.shadowlayout.shadowdelegate;
2 |
3 | import android.graphics.Canvas;
4 | import android.support.annotation.ColorInt;
5 | import android.view.View;
6 |
7 | /**
8 | * Created by Administrator on 2017/11/1 0001.
9 | */
10 |
11 | public interface ShadowDelegate {
12 |
13 | void onLayout(boolean changed, int left, int top, int right, int bottom);
14 | void onAttachToWindow();
15 | void onDetachedFromWindow();
16 | void onDraw(Canvas canvas) ;
17 | void onDrawOver(Canvas canvas) ;
18 | boolean onClipCanvas(Canvas canvas,View child);
19 | void invalidateShadow();
20 | void setShadowColor(@ColorInt int color);
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/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 D:\Programs\Programming\AndroidStudio\AS_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 |
--------------------------------------------------------------------------------
/library/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 D:\Programs\Programming\AndroidStudio\AS_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 |
--------------------------------------------------------------------------------
/library/src/main/java/com/ytjojo/shadowlayout/shadow/Shadow.java:
--------------------------------------------------------------------------------
1 | package com.ytjojo.shadowlayout.shadow;
2 |
3 | import android.graphics.Canvas;
4 | import android.graphics.Rect;
5 | import android.view.View;
6 |
7 |
8 | public interface Shadow {
9 | public void setParameter(int colorTopShadow, int colorBottomShadow, float offsetTopShadow, float offsetBottomShadow,
10 | float blurTopShadow,
11 | float blurBottomShadow,
12 | Rect rect);
13 |
14 | public void onDraw(Canvas canvas);
15 | public void onDrawOver(Canvas canvas);
16 | boolean onClipChildCanvas(Canvas canvas,View child);
17 | void onLayout(View parent,int left,int top,int right,int bottom);
18 | }
19 |
--------------------------------------------------------------------------------
/library/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
13 |
14 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/library/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_ARTIFACT_ID=ShadowLayout
2 | POM_NAME=ShadowLayout
3 | POM_DESCRIPTION=Android powerful library- draw any shape of z-depth shadow of MaterialDesign,auto fit shape ,roundRect , Circle, clipe Path shape all be supported
4 | POM_PACKAGING=aar
5 |
6 |
7 |
8 |
9 |
10 | GROUP=com.github.ytjojo
11 | #VERSION_NAME=0.9.2-SNAPSHOT
12 | VERSION_NAME=1.0.1
13 |
14 | POM_URL=https://github.com/ytjojo/ShadowLayout
15 | POM_SCM_URL=https://github.com/ytjojo/ShadowLayout.git
16 | POM_SCM_CONNECTION=scm:git:git://github.com/ytjojo/ShadowLayout.git
17 | POM_SCM_DEV_CONNECTION=scm:git:ssh://git@github.com/ytjojo/ShadowLayout.git
18 |
19 | POM_LICENCE_NAME=The Apache Software License, Version 2.0
20 | POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt
21 | POM_LICENCE_DIST=repo
22 |
23 | POM_DEVELOPER_ID=ytjojo@163.com
24 | POM_DEVELOPER_NAME=ytjojo@163.com
25 | POM_DEVELOPER_EMAIL=ytjojo@163.com
--------------------------------------------------------------------------------
/app/src/main/java/app/mosn/zdepthshadowsample/SimplePathShadowActivity.java:
--------------------------------------------------------------------------------
1 | package app.mosn.zdepthshadowsample;
2 |
3 | import android.graphics.Path;
4 | import android.os.Bundle;
5 | import android.support.annotation.Nullable;
6 | import android.support.v7.app.AppCompatActivity;
7 |
8 | import com.ytjojo.shadowlayout.ShadowLayout;
9 | import com.ytjojo.shadowlayout.demo.R;
10 | import com.ytjojo.shadowlayout.shadowdelegate.PathModel;
11 |
12 | /**
13 | * Created by Administrator on 2017/11/4 0004.
14 | */
15 |
16 | public class SimplePathShadowActivity extends AppCompatActivity {
17 | Path mCustomPath;
18 | @Override
19 | protected void onCreate(@Nullable Bundle savedInstanceState) {
20 | super.onCreate(savedInstanceState);
21 | setContentView(R.layout.activity_simplepath);
22 | // ShadowLayout shadowLayout = (ShadowLayout) findViewById(R.id.ShadowLayout);
23 | // PathModel pathModel= (PathModel) shadowLayout.getShadowDeltegate();
24 | // pathModel.setPath(mCustomPath);
25 |
26 |
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'com.jakewharton.butterknife'
3 | android {
4 | compileSdkVersion 25
5 | buildToolsVersion "25.0.3"
6 |
7 | defaultConfig {
8 | applicationId "com.gigamole.shadowlayout"
9 | minSdkVersion 14
10 | targetSdkVersion 23
11 | versionCode 1
12 | versionName "1.0"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | compile fileTree(dir: 'libs', include: ['*.jar'])
24 | compile project(':library')
25 | compile 'com.android.support:appcompat-v7:25.3.1'
26 | compile 'com.github.bumptech.glide:glide:4.3.0'
27 | compile 'jp.wasabeef:glide-transformations:3.0.1'
28 | compile 'com.orhanobut:logger:2.1.1'
29 | annotationProcessor 'com.github.bumptech.glide:compiler:4.3.0'
30 |
31 | compile 'com.jakewharton:butterknife:8.8.1'
32 | annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
33 | // compile 'com.github.skydoves:colorpickerview:1.0.7'
34 | compile 'com.jaredrummler:colorpicker:1.0.1'
35 | // compile 'com.github.ytjojo:ShadowLayout:1.0.1'
36 | }
37 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_simplepath.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
25 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/library/build.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Basil Miller
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | apply plugin: 'com.android.library'
18 |
19 | apply from: rootProject.file('./gradle-mvn-push.gradle')
20 |
21 | version = "1.0.2"
22 |
23 | android {
24 | compileSdkVersion 25
25 | buildToolsVersion "25.0.3"
26 |
27 | defaultConfig {
28 | minSdkVersion 11
29 | targetSdkVersion 23
30 | versionCode 1
31 | versionName "1.0.0"
32 | }
33 | buildTypes {
34 | release {
35 | minifyEnabled false
36 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
37 | }
38 | }
39 | }
40 |
41 | dependencies {
42 | compile fileTree(dir: 'libs', include: ['*.jar'])
43 | compile 'com.android.support:appcompat-v7:25.3.1'
44 | }
45 |
46 | tasks.withType(Javadoc) {
47 | options.encoding = 'UTF-8'
48 | options.addStringOption('charSet', 'UTF-8')
49 | options.addStringOption('Xdoclint:none', '-quiet')
50 | }
51 | afterEvaluate{
52 | tasks.getByName('androidJavadocs').enabled = false
53 | }
54 |
55 |
--------------------------------------------------------------------------------
/app/src/main/java/app/mosn/zdepthshadowsample/DisplayUtil.java:
--------------------------------------------------------------------------------
1 | package app.mosn.zdepthshadowsample;
2 |
3 | import android.content.Context;
4 |
5 | /**
6 | * Android大小单位转换工具类
7 | *
8 | * float scale = context.getResources().getDisplayMetrics().density;
9 | */
10 | public class DisplayUtil {
11 | /**
12 | * 将px值转换为dip或dp值,保证尺寸大小不变
13 | *
14 | * @param pxValue
15 | * @param scale(DisplayMetrics类中属性density)
16 | * @return
17 | */
18 | public static float px2dip(float pxValue, float scale) {
19 | return (pxValue / scale + 0.5f);
20 | }
21 |
22 | /**
23 | * 将px值转换为dip或dp值,保证尺寸大小不变
24 | *
25 | * @param pxValue
26 | * @param context
27 | * @return
28 | */
29 | public static float px2dip(float pxValue,Context context) {
30 | float scale = context.getResources().getDisplayMetrics().density;
31 | return px2dip( pxValue, scale);
32 | }
33 |
34 | /**
35 | * 将dip或dp值转换为px值,保证尺寸大小不变
36 | *
37 | * @param dipValue
38 | * @param scale(DisplayMetrics类中属性density)
39 | * @return
40 | */
41 | public static float dip2px(float dipValue, float scale) {
42 | return (dipValue * scale + 0.5f);
43 | }
44 |
45 | /**
46 | * 将dip或dp值转换为px值,保证尺寸大小不变
47 | *
48 | * @param dipValue
49 | * @param context
50 | * @return
51 | */
52 | public static float dip2px(float dipValue, Context context) {
53 | float scale = context.getResources().getDisplayMetrics().density;
54 | return dip2px(dipValue, scale);
55 | }
56 |
57 | /**
58 | * 将px值转换为sp值,保证文字大小不变
59 | *
60 | * @param pxValue
61 | * @param fontScale(DisplayMetrics类中属性scaledDensity)
62 | * @return
63 | */
64 | public static float px2sp(float pxValue, float fontScale) {
65 | return (pxValue / fontScale + 0.5f);
66 | }
67 |
68 | /**
69 | * 将sp值转换为px值,保证文字大小不变
70 | *
71 | * @param spValue
72 | * @param fontScale(DisplayMetrics类中属性scaledDensity)
73 | * @return
74 | */
75 | public static float sp2px(float spValue, float fontScale) {
76 | return (spValue * fontScale + 0.5f);
77 | }
78 | /**
79 | * 将sp值转换为px值,保证文字大小不变
80 | *
81 | * @param spValue
82 | * @param Context
83 | * @return
84 | */
85 | public static float sp2px(float spValue,Context context) {
86 | float scale = context.getResources().getDisplayMetrics().density;
87 | return sp2px( spValue, scale);
88 | }
89 | }
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/app/src/main/java/app/mosn/zdepthshadowsample/BlurMaskFilterView.java:
--------------------------------------------------------------------------------
1 | package app.mosn.zdepthshadowsample;
2 |
3 | import android.content.Context;
4 | import android.graphics.BlurMaskFilter;
5 | import android.graphics.Canvas;
6 | import android.graphics.Color;
7 | import android.graphics.Paint;
8 | import android.support.annotation.Nullable;
9 | import android.text.TextPaint;
10 | import android.util.AttributeSet;
11 | import android.view.View;
12 |
13 | /**
14 | * Created by Administrator on 2018/3/18 0018.
15 | */
16 |
17 | public class BlurMaskFilterView extends View {
18 | public BlurMaskFilterView(Context context) {
19 | this(context,null);
20 | }
21 |
22 | public BlurMaskFilterView(Context context, @Nullable AttributeSet attrs) {
23 | this(context, attrs,0);
24 | }
25 |
26 | public BlurMaskFilterView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
27 | super(context, attrs, defStyleAttr);
28 | init();
29 |
30 |
31 | }
32 | Paint mPaint ;
33 | TextPaint mTextPaint;
34 | private void init(){
35 | mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
36 | mPaint.setDither(true);
37 | mPaint.setStyle(Paint.Style.FILL);
38 | mPaint.setColor(Color.YELLOW);
39 | setLayerType(LAYER_TYPE_SOFTWARE, null);
40 | mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
41 | mTextPaint.setColor(Color.BLACK);
42 | mTextPaint.setTextSize(40);
43 |
44 | }
45 | int mCircleRadus = 100;
46 | int mBlurRadus =50;
47 | @Override
48 | protected void onDraw(Canvas canvas) {
49 | super.onDraw(canvas);
50 | canvas.save();
51 | int x = getWidth()/2;
52 | int y = mBlurRadus*2 + mCircleRadus + 80;
53 | canvas.translate(x,y);
54 | drawCicle(canvas, BlurMaskFilter.Blur.INNER);
55 | canvas.translate(0, mBlurRadus*2+ 2 * mCircleRadus +80);
56 | drawCicle(canvas, BlurMaskFilter.Blur.NORMAL);
57 | canvas.translate(0, mBlurRadus*2+2 * mCircleRadus +80);
58 | drawCicle(canvas, BlurMaskFilter.Blur.SOLID);
59 | canvas.translate(0, mBlurRadus*2+ 2 *mCircleRadus + 80);
60 | drawCicle(canvas, BlurMaskFilter.Blur.OUTER);
61 | mPaint.setMaskFilter(new BlurMaskFilter(mBlurRadus, BlurMaskFilter.Blur.SOLID));
62 | canvas.translate(0, mBlurRadus + mCircleRadus );
63 | canvas.drawRect(-100,50,100,250,mPaint);
64 | canvas.restore();
65 |
66 | }
67 | private void drawCicle(Canvas canvas, BlurMaskFilter.Blur style){
68 | canvas.drawText(style.toString(),-60,-mCircleRadus - mBlurRadus-60,mTextPaint);
69 | mPaint.setMaskFilter(new BlurMaskFilter(mBlurRadus,style));
70 | canvas.drawCircle(0,0,mCircleRadus,mPaint);
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/library/src/main/java/com/ytjojo/shadowlayout/shadow/ShadowOval.java:
--------------------------------------------------------------------------------
1 | package com.ytjojo.shadowlayout.shadow;
2 |
3 | import android.graphics.BlurMaskFilter;
4 | import android.graphics.Canvas;
5 | import android.graphics.Path;
6 | import android.graphics.Rect;
7 | import android.graphics.RectF;
8 | import android.graphics.Region;
9 | import android.graphics.drawable.ShapeDrawable;
10 | import android.graphics.drawable.shapes.OvalShape;
11 | import android.view.View;
12 | import android.view.ViewGroup;
13 |
14 |
15 | public class ShadowOval implements Shadow {
16 |
17 | private ShapeDrawable mTopShadow;
18 | private ShapeDrawable mBottomShadow;
19 |
20 | private RectF mRectTopShadow;
21 | private RectF mRectBottomShadow;
22 | Path mPath;
23 | RectF mClipRect;
24 | public ShadowOval() {
25 | mRectTopShadow = new RectF();
26 | mRectBottomShadow = new RectF();
27 | mTopShadow = new ShapeDrawable(new OvalShape());
28 | mBottomShadow = new ShapeDrawable(new OvalShape());
29 | mPath = new Path();
30 | mClipRect = new RectF();
31 | }
32 |
33 | @Override
34 | public void setParameter(int colorTopShadow, int colorBottomShadow, float offsetTopShadow, float offsetBottomShadow,
35 | float blurTopShadow,
36 | float blurBottomShadow,
37 | Rect rect) {
38 | mRectTopShadow.left = rect.left;
39 | mRectTopShadow.top = rect.top + offsetTopShadow;
40 | mRectTopShadow.right = rect.right;
41 | mRectTopShadow.bottom = rect.bottom + offsetTopShadow;
42 |
43 | mRectBottomShadow.left = rect.left;
44 | mRectBottomShadow.top = rect.top + offsetBottomShadow;
45 | mRectBottomShadow.right = rect.right;
46 | mRectBottomShadow.bottom = rect.bottom + offsetBottomShadow;
47 |
48 | mTopShadow.getPaint().setColor(colorTopShadow);
49 | if (0 < blurTopShadow) {
50 | mTopShadow.getPaint().setMaskFilter(new BlurMaskFilter(blurTopShadow, BlurMaskFilter.Blur.NORMAL));
51 | } else {
52 | mTopShadow.getPaint().setMaskFilter(null);
53 | }
54 |
55 | mBottomShadow.getPaint().setColor(colorBottomShadow);
56 | if (0 < blurBottomShadow) {
57 | mBottomShadow.getPaint().setMaskFilter(new BlurMaskFilter(blurBottomShadow, BlurMaskFilter.Blur.NORMAL));
58 | } else {
59 | mBottomShadow.getPaint().setMaskFilter(null);
60 | }
61 | }
62 |
63 | @Override
64 | public void onDraw(Canvas canvas) {
65 | canvas.drawOval(mRectBottomShadow, mBottomShadow.getPaint());
66 | canvas.drawOval(mRectTopShadow, mTopShadow.getPaint());
67 | }
68 |
69 | @Override
70 | public void onDrawOver(Canvas canvas) {
71 |
72 | }
73 |
74 | @Override
75 | public boolean onClipChildCanvas(Canvas canvas,View child) {
76 | mPath.reset();
77 | int width = Math.min(child.getHeight(),child.getWidth());
78 | int x = child.getLeft()+child.getWidth()/2;
79 | int y = child.getTop()+child.getHeight()/2;
80 | mPath.addCircle(x,y,width/2,Path.Direction.CW);
81 | canvas.clipPath(mPath, Region.Op.REPLACE);
82 | return false;
83 | }
84 |
85 | @Override
86 | public void onLayout(View parent, int left, int top, int right, int bottom) {
87 | ViewGroup viewGroup = (ViewGroup) parent;
88 |
89 | mPath.addRoundRect(mClipRect,mClipRect.width(),mClipRect.width(),Path.Direction.CW);
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/library/src/main/java/com/ytjojo/shadowlayout/ShadowLayout.java:
--------------------------------------------------------------------------------
1 | package com.ytjojo.shadowlayout;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.graphics.Canvas;
6 | import android.support.annotation.ColorInt;
7 | import android.util.AttributeSet;
8 | import android.view.View;
9 | import android.widget.FrameLayout;
10 |
11 | import com.ytjojo.shadowlayout.shadowdelegate.AutoModel;
12 | import com.ytjojo.shadowlayout.shadowdelegate.ExactlyModel;
13 | import com.ytjojo.shadowlayout.shadowdelegate.PathModel;
14 | import com.ytjojo.shadowlayout.shadowdelegate.ShadowDelegate;
15 |
16 | /**
17 | * Created by Administrator on 2017/11/1 0001.
18 | */
19 |
20 | public class ShadowLayout extends FrameLayout {
21 | public static final int SHADOW_MODEL_AUTO = 0;
22 | public static final int SHADOW_MODEL_SHAP = 1;
23 | public static final int SHADOW_MODEL_PATH = 2;
24 |
25 | ShadowDelegate mShadowDeltegate;
26 |
27 | public ShadowLayout(final Context context) {
28 | this(context, null);
29 | }
30 |
31 | public ShadowLayout(final Context context, final AttributeSet attrs) {
32 | this(context, attrs, 0);
33 | }
34 |
35 | public ShadowLayout(final Context context, final AttributeSet attrs, final int defStyleAttr) {
36 | super(context, attrs, defStyleAttr);
37 | setWillNotDraw(false);
38 | // Retrieve attributes from xml
39 | final TypedArray typedArray = context.obtainStyledAttributes(attrs, com.ytjojo.shadowlayout.R.styleable.ShadowLayout);
40 | int model = typedArray.getInt(com.ytjojo.shadowlayout.R.styleable.ShadowLayout_sl_shadow_model, SHADOW_MODEL_AUTO);
41 | if (model == SHADOW_MODEL_AUTO) {
42 | mShadowDeltegate = new AutoModel(this, typedArray);
43 | } else if (model == SHADOW_MODEL_SHAP) {
44 | mShadowDeltegate = new ExactlyModel(this, typedArray);
45 | }else if(model == SHADOW_MODEL_PATH){
46 | mShadowDeltegate = new PathModel(this,typedArray);
47 | }
48 | typedArray.recycle();
49 | }
50 |
51 | @Override
52 | protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
53 | super.onLayout(changed, left, top, right, bottom);
54 | mShadowDeltegate.onLayout(changed, left, top, right, bottom);
55 | mShadowDeltegate.invalidateShadow();
56 | }
57 |
58 | @Override
59 | protected void onDetachedFromWindow() {
60 | super.onDetachedFromWindow();
61 | mShadowDeltegate.onDetachedFromWindow();
62 | }
63 |
64 | @Override
65 | protected void onAttachedToWindow() {
66 | super.onAttachedToWindow();
67 | mShadowDeltegate.onAttachToWindow();
68 | }
69 |
70 | @Override
71 | protected void dispatchDraw(Canvas canvas) {
72 | mShadowDeltegate.onDraw(canvas);
73 | mShadowDeltegate.onDrawOver(canvas);
74 | }
75 |
76 | @Override
77 | protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
78 | try {
79 | canvas.save();
80 | return mShadowDeltegate.onClipCanvas(canvas,child)&super.drawChild(canvas, child, drawingTime);
81 | }finally {
82 | canvas.restore();
83 | }
84 | }
85 | public void setShadowColor(@ColorInt int color) {
86 | mShadowDeltegate.setShadowColor(color);
87 | }
88 | public void superdispatchDraw(Canvas canvas){
89 | super.dispatchDraw(canvas);
90 | }
91 | public ShadowDelegate getShadowDeltegate(){
92 | return mShadowDeltegate;
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/app/src/main/java/app/mosn/zdepthshadowsample/ChangeZDepthActivity.java:
--------------------------------------------------------------------------------
1 | package app.mosn.zdepthshadowsample;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 | import android.support.v7.app.AppCompatActivity;
6 | import android.support.v7.widget.Toolbar;
7 |
8 | import com.ytjojo.shadowlayout.ShadowLayout;
9 | import com.ytjojo.shadowlayout.ZDepth;
10 | import com.ytjojo.shadowlayout.shadowdelegate.ExactlyModel;
11 | import com.ytjojo.shadowlayout.demo.R;
12 |
13 | import butterknife.BindView;
14 | import butterknife.ButterKnife;
15 | import butterknife.OnClick;
16 |
17 | public class ChangeZDepthActivity extends AppCompatActivity {
18 |
19 | @BindView(R.id.toolBar)
20 | Toolbar mToolbar;
21 |
22 | @BindView(R.id.zDepthShadowLayout_toolBar)
23 | ShadowLayout mZDepthShadowLayoutToolbar;
24 |
25 | @BindView(R.id.zDepthShadowLayout_rect)
26 | ShadowLayout mZDepthShadowLayoutRect;
27 |
28 | @BindView(R.id.zDepthShadowLayout_oval)
29 | ShadowLayout mZDepthShadowLayoutOval;
30 | ExactlyModel mExactlyModelToobar;
31 | ExactlyModel mExactlyModelLayoutRect;
32 | ExactlyModel mExactlyModelLayoutOval;
33 |
34 | @Override
35 | protected void onCreate(Bundle savedInstanceState) {
36 | super.onCreate(savedInstanceState);
37 | setContentView(R.layout.activity_change_zdepth);
38 | ButterKnife.bind(this);
39 | setSupportActionBar(mToolbar);
40 | }
41 |
42 | @Override
43 | protected void onPostCreate(@Nullable Bundle savedInstanceState) {
44 | super.onPostCreate(savedInstanceState);
45 | mExactlyModelLayoutOval = (ExactlyModel) mZDepthShadowLayoutOval.getShadowDeltegate();
46 | mExactlyModelLayoutRect = (ExactlyModel) mZDepthShadowLayoutToolbar.getShadowDeltegate();
47 | mExactlyModelToobar = (ExactlyModel) mZDepthShadowLayoutRect.getShadowDeltegate();
48 | }
49 |
50 | @OnClick(R.id.button_zDepth_0)
51 | protected void onClickZDepth0() {
52 | mExactlyModelLayoutRect.changeZDepth(ZDepth.Depth0);
53 | mExactlyModelLayoutOval.changeZDepth(ZDepth.Depth0);
54 | mExactlyModelToobar.changeZDepth(ZDepth.Depth0);
55 | }
56 |
57 | @OnClick(R.id.button_zDepth_1)
58 | protected void onClickZDepth1() {
59 | mExactlyModelLayoutRect.changeZDepth(ZDepth.Depth1);
60 | mExactlyModelLayoutOval.changeZDepth(ZDepth.Depth1);
61 | mExactlyModelToobar.changeZDepth(ZDepth.Depth1);
62 | }
63 |
64 | @OnClick(R.id.button_zDepth_2)
65 | protected void onClickZDepth2() {
66 | mExactlyModelLayoutRect.changeZDepth(ZDepth.Depth2);
67 | mExactlyModelLayoutOval.changeZDepth(ZDepth.Depth2);
68 | mExactlyModelToobar.changeZDepth(ZDepth.Depth2);
69 | }
70 |
71 | @OnClick(R.id.button_zDepth_3)
72 | protected void onClickZDepth3() {
73 | mExactlyModelLayoutRect.changeZDepth(ZDepth.Depth3);
74 | mExactlyModelLayoutOval.changeZDepth(ZDepth.Depth3);
75 | mExactlyModelToobar.changeZDepth(ZDepth.Depth3);
76 | }
77 |
78 | @OnClick(R.id.button_zDepth_4)
79 | protected void onClickZDepth4() {
80 | mExactlyModelLayoutRect.changeZDepth(ZDepth.Depth4);
81 | mExactlyModelLayoutOval.changeZDepth(ZDepth.Depth4);
82 | mExactlyModelToobar.changeZDepth(ZDepth.Depth4);
83 | }
84 |
85 | @OnClick(R.id.button_zDepth_5)
86 | protected void onClickZDepth5() {
87 | mExactlyModelLayoutRect.changeZDepth(ZDepth.Depth5);
88 | mExactlyModelLayoutOval.changeZDepth(ZDepth.Depth5);
89 | mExactlyModelToobar.changeZDepth(ZDepth.Depth5);
90 | }
91 |
92 | }
93 |
--------------------------------------------------------------------------------
/library/src/main/java/com/ytjojo/shadowlayout/ZDepth.java:
--------------------------------------------------------------------------------
1 | package com.ytjojo.shadowlayout;
2 |
3 | import android.content.Context;
4 | import android.graphics.Color;
5 |
6 | import com.ytjojo.shadowlayout.utils.DisplayUtils;
7 |
8 |
9 | public enum ZDepth {
10 |
11 | Depth0( // TODO
12 | 0,
13 | 0,
14 | 0,
15 | 0,
16 | 0,
17 | 0
18 | ),
19 |
20 | Depth1(
21 | 30, // alpha to black
22 | 61, // alpha to black
23 | 1.0f, // dp
24 | 1.0f, // dp
25 | 1.5f, // dp
26 | 1.0f // dp
27 | ),
28 | Depth2(
29 | 40,
30 | 58,
31 | 3.0f,
32 | 3.0f,
33 | 3.0f,
34 | 3.0f
35 | ),
36 | Depth3(
37 | 48,
38 | 58,
39 | 10.0f,
40 | 6.0f,
41 | 10.0f,
42 | 3.0f
43 | ),
44 | Depth4(
45 | 64,
46 | 56,
47 | 14.0f,
48 | 10.0f,
49 | 14.0f,
50 | 5.0f
51 | ),
52 | Depth5(
53 | 76,
54 | 56,
55 | 19.0f,
56 | 15.0f,
57 | 19.0f,
58 | 6.0f
59 | );
60 |
61 | public int mAlphaTopShadow; // alpha to black
62 | public int mAlphaBottomShadow; // alpha to black
63 |
64 | public final float mOffsetYTopShadow; // dp
65 | public final float mOffsetYBottomShadow; // dp
66 |
67 | public final float mBlurTopShadow; // dp
68 | public final float mBlurBottomShadow; // dp
69 |
70 | private ZDepth(int alphaTopShadow, int alphaBottomShadow, float offsetYTopShadow, float offsetYBottomShadow, float blurTopShadow, float blurBottomShadow) {
71 | mAlphaTopShadow = alphaTopShadow;
72 | mAlphaBottomShadow = alphaBottomShadow;
73 | mOffsetYTopShadow = offsetYTopShadow;
74 | mOffsetYBottomShadow = offsetYBottomShadow;
75 | mBlurTopShadow = blurTopShadow;
76 | mBlurBottomShadow = blurBottomShadow;
77 | }
78 |
79 | public int getAlphaTopShadow() {
80 | return mAlphaTopShadow;
81 | }
82 |
83 | public int getAlphaBottomShadow() {
84 | return mAlphaBottomShadow;
85 | }
86 |
87 | public float getOffsetYTopShadowPx(Context context) {
88 | return DisplayUtils.convertDpToPx(context, mOffsetYTopShadow);
89 | }
90 |
91 | public float getOffsetYBottomShadowPx(Context context) {
92 | return DisplayUtils.convertDpToPx(context, mOffsetYBottomShadow);
93 | }
94 |
95 | public float getBlurTopShadowPx(Context context) {
96 | return DisplayUtils.convertDpToPx(context, mBlurTopShadow);
97 | }
98 |
99 | public float getBlurBottomShadowPx(Context context) {
100 | return DisplayUtils.convertDpToPx(context, mBlurBottomShadow);
101 | }
102 |
103 |
104 |
105 | public float mOffsetYTopShadowPx; // px
106 | public float mOffsetYBottomShadowPx; // px
107 |
108 | public float mBlurTopShadowPx; // px
109 | public float mBlurBottomShadowPx; // px
110 |
111 | public void initZDepth(Context context) {
112 | mOffsetYTopShadowPx = getOffsetYTopShadowPx(context);
113 | mOffsetYBottomShadowPx = getOffsetYBottomShadowPx(context);
114 | mBlurTopShadowPx =getBlurTopShadowPx(context);
115 | mBlurBottomShadowPx = getBlurBottomShadowPx(context);
116 | }
117 |
118 | public int getColorTopShadow() {
119 | return Color.argb(mAlphaTopShadow, 0, 0, 0);
120 | }
121 |
122 | public int getColorBottomShadow() {
123 | return Color.argb(mAlphaBottomShadow, 0, 0, 0);
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/library/src/main/res/values/attrs.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 |
--------------------------------------------------------------------------------
/library/src/main/java/com/ytjojo/shadowlayout/shadow/ShadowRect.java:
--------------------------------------------------------------------------------
1 | package com.ytjojo.shadowlayout.shadow;
2 |
3 | import android.graphics.BlurMaskFilter;
4 | import android.graphics.Canvas;
5 | import android.graphics.Path;
6 | import android.graphics.Rect;
7 | import android.graphics.RectF;
8 | import android.graphics.Region;
9 | import android.graphics.drawable.ShapeDrawable;
10 | import android.graphics.drawable.shapes.RectShape;
11 | import android.view.View;
12 |
13 |
14 | public class ShadowRect implements Shadow {
15 |
16 | private ShapeDrawable mTopShadow;
17 | private ShapeDrawable mBottomShadow;
18 |
19 | private Rect mRectTopShadow;
20 | private Rect mRectBottomShadow;
21 | Path mPath;
22 | int mRoundRectRadius;
23 | RectF mClipRect;
24 |
25 | public ShadowRect() {
26 | mRectTopShadow = new Rect();
27 | mRectBottomShadow = new Rect();
28 | mTopShadow = new ShapeDrawable(new RectShape());
29 | mBottomShadow = new ShapeDrawable(new RectShape());
30 | mPath = new Path();
31 | mClipRect = new RectF();
32 | }
33 |
34 | float blurTopShadow;
35 |
36 | @Override
37 | public void setParameter(int colorTopShadow, int colorBottomShadow, float offsetTopShadow, float offsetBottomShadow,
38 | float blurTopShadow,
39 | float blurBottomShadow,
40 | Rect rect) {
41 | mRectTopShadow.left = rect.left;
42 | mRectTopShadow.top = (int) (rect.top + offsetTopShadow);
43 | mRectTopShadow.right = rect.right;
44 | mRectTopShadow.bottom = (int) (rect.bottom + offsetTopShadow / 2);
45 | // mRectTopShadow.bottom = (int) (rect.bottom );
46 |
47 | mRectBottomShadow.left = rect.left;
48 | mRectBottomShadow.top = (int) (rect.top + offsetBottomShadow);
49 | mRectBottomShadow.right = rect.right;
50 | mRectBottomShadow.bottom = (int) (rect.bottom + offsetBottomShadow / 2);
51 |
52 |
53 | mTopShadow.getPaint().setColor(colorTopShadow);
54 | if (0 < blurTopShadow) {
55 | mTopShadow.getPaint().setMaskFilter(new BlurMaskFilter(blurTopShadow, BlurMaskFilter.Blur.NORMAL));
56 | } else {
57 | mTopShadow.getPaint().setMaskFilter(null);
58 | }
59 |
60 | mBottomShadow.getPaint().setColor(colorBottomShadow);
61 | if (0 < blurBottomShadow) {
62 | mBottomShadow.getPaint().setMaskFilter(new BlurMaskFilter(blurBottomShadow, BlurMaskFilter.Blur.NORMAL));
63 | } else {
64 | mBottomShadow.getPaint().setMaskFilter(null);
65 | }
66 | this.blurTopShadow = blurTopShadow;
67 | }
68 |
69 | @Override
70 | public void onDraw(Canvas canvas) {
71 | if (mRoundRectRadius <= 0) {
72 | canvas.drawRect(mRectBottomShadow, mBottomShadow.getPaint());
73 | canvas.drawRect(mRectTopShadow, mTopShadow.getPaint());
74 | }else {
75 | canvas.drawRoundRect(new RectF(mRectBottomShadow.left, mRectBottomShadow.top, mRectBottomShadow.right, mRectBottomShadow.bottom)
76 | , mRoundRectRadius, mRoundRectRadius, mBottomShadow.getPaint());
77 | canvas.drawRoundRect(new RectF(mRectTopShadow.left, mRectTopShadow.top, mRectTopShadow.right, mRectTopShadow.bottom)
78 | , mRoundRectRadius, mRoundRectRadius, mTopShadow.getPaint());
79 | }
80 |
81 |
82 |
83 | }
84 |
85 | @Override
86 | public void onDrawOver(Canvas canvas) {
87 |
88 | }
89 |
90 | @Override
91 | public boolean onClipChildCanvas(Canvas canvas, View child) {
92 | if (mRoundRectRadius <= 0) {
93 | return false;
94 | }
95 | mClipRect.set(child.getLeft(), child.getTop(), child.getRight(), child.getBottom());
96 | mPath.reset();
97 | mPath.addRoundRect(mClipRect, mRoundRectRadius, mRoundRectRadius, Path.Direction.CW);
98 | canvas.clipPath(mPath, Region.Op.REPLACE);
99 | return false;
100 |
101 | }
102 |
103 | @Override
104 | public void onLayout(View parent, int left, int top, int right, int bottom) {
105 |
106 | }
107 |
108 | public void setRoundRectRadius(int roundRectRadius) {
109 | mRoundRectRadius = roundRectRadius;
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/app/src/main/java/app/mosn/zdepthshadowsample/ClipView.java:
--------------------------------------------------------------------------------
1 | package app.mosn.zdepthshadowsample;
2 |
3 | import android.content.Context;
4 | import android.graphics.BlurMaskFilter;
5 | import android.graphics.Canvas;
6 | import android.graphics.Color;
7 | import android.graphics.Paint;
8 | import android.graphics.Path;
9 | import android.graphics.Region;
10 | import android.support.annotation.Nullable;
11 | import android.text.TextPaint;
12 | import android.util.AttributeSet;
13 | import android.view.View;
14 |
15 | /**
16 | * Created by Administrator on 2018/3/18 0018.
17 | */
18 |
19 | public class ClipView extends View {
20 |
21 | public ClipView(Context context) {
22 | this(context,null);
23 | }
24 |
25 | public ClipView(Context context, @Nullable AttributeSet attrs) {
26 | this(context, attrs,0);
27 | }
28 |
29 | public ClipView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
30 | super(context, attrs, defStyleAttr);
31 | init();
32 |
33 |
34 | }
35 | Paint mPaint ;
36 | TextPaint mTextPaint;
37 | private void init(){
38 | mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
39 | mPaint.setDither(true);
40 | mPaint.setStyle(Paint.Style.FILL);
41 | mPaint.setColor(Color.YELLOW);
42 | setLayerType(LAYER_TYPE_SOFTWARE, null);
43 | mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
44 | mTextPaint.setColor(Color.BLACK);
45 | mTextPaint.setTextSize(40);
46 | mPath = new Path();
47 |
48 | }
49 | int mCircleRadus = 100;
50 | int mBlurRadus =50;
51 | Path mPath;
52 | @Override
53 | protected void onDraw(Canvas canvas) {
54 | super.onDraw(canvas);
55 | // mPath.reset();
56 | // mPath.addRect(0,0,getWidth(),getHeight(), Path.Direction.CCW);
57 | // canvas.clipPath(mPath);
58 | mPath.reset();
59 | int x = 300;
60 | int y = 140;
61 | canvas.drawText( Region.Op.INTERSECT.toString(),300,50,mTextPaint);
62 | canvas.save();
63 | canvas.translate(x,y);
64 | mPaint.setColor(Color.YELLOW);
65 | canvas.drawRect(-100,-100,200,300,mPaint);
66 | mPath.addCircle(0,0,80, Path.Direction.CCW);
67 | canvas.clipPath(mPath, Region.Op.INTERSECT);
68 | mPaint.setColor(Color.RED);
69 | canvas.drawRect(-100,0,100,200,mPaint);
70 | canvas.restore();
71 |
72 | y+=460;
73 | canvas.drawText( Region.Op.DIFFERENCE.toString(),x,y,mTextPaint);
74 |
75 |
76 | canvas.save();
77 | canvas.translate(x,y);
78 | mPaint.setColor(Color.YELLOW);
79 | canvas.drawRect(-100,-100,200,300,mPaint);
80 | canvas.clipPath(mPath, Region.Op.DIFFERENCE);
81 | mPaint.setColor(Color.RED);
82 | canvas.drawRect(-100,0,100,200,mPaint);
83 | canvas.restore();
84 |
85 | y+=460;
86 | canvas.drawText( Region.Op.REPLACE.toString(),x,y-80,mTextPaint);
87 | canvas.save();
88 | canvas.translate(x,y);
89 | mPaint.setColor(Color.YELLOW);
90 | canvas.drawRect(-100,-100,200,300,mPaint);
91 | canvas.clipPath(mPath, Region.Op.REPLACE);
92 | mPaint.setColor(Color.RED);
93 | canvas.drawRect(-100,0,100,200,mPaint);
94 |
95 | canvas.restore();
96 |
97 |
98 | canvas.save();
99 | y+=460;
100 | canvas.drawText( Region.Op.REVERSE_DIFFERENCE.toString(),x,y-80,mTextPaint);
101 | canvas.translate(x,y);
102 | mPaint.setColor(Color.YELLOW);
103 | canvas.drawRect(-100,-100,200,300,mPaint);
104 | canvas.clipPath(mPath, Region.Op.REVERSE_DIFFERENCE);
105 | mPaint.setColor(Color.RED);
106 | canvas.drawRect(-100,0,100,200,mPaint);
107 | canvas.restore();
108 |
109 | y+=460;
110 | canvas.drawText( Region.Op.UNION.toString(),x,y-80,mTextPaint);
111 | canvas.save();
112 | canvas.translate(x,y);
113 | mPaint.setColor(Color.YELLOW);
114 | canvas.drawRect(-100,-100,200,300,mPaint);
115 | canvas.clipPath(mPath, Region.Op.UNION);
116 | mPaint.setColor(Color.RED);
117 | canvas.drawRect(-100,0,100,200,mPaint);
118 |
119 | canvas.restore();
120 | y+=460;
121 | canvas.drawText( Region.Op.XOR.toString(),x,y-80,mTextPaint);
122 | canvas.save();
123 | canvas.translate(x,y);
124 | mPaint.setColor(Color.YELLOW);
125 | canvas.drawRect(-100,-100,200,300,mPaint);
126 | canvas.clipPath(mPath, Region.Op.XOR);
127 | mPaint.setColor(Color.RED);
128 | canvas.drawRect(-100,0,100,200,mPaint);
129 |
130 | canvas.restore();
131 | mPath.reset();
132 | }
133 | int x;
134 | int y;
135 | private void drawRect(Canvas canvas,Region.Op op){
136 | canvas.save();
137 | canvas.translate(x,y);
138 | mPaint.setColor(Color.YELLOW);
139 | canvas.drawRect(-100,100,200,300,mPaint);
140 | canvas.clipPath(mPath, op);
141 | mPaint.setColor(Color.RED);
142 | canvas.drawRect(-100,0,100,200,mPaint);
143 |
144 | canvas.restore();
145 | }
146 | }
147 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | ShadowLayout
3 |
4 | Speaking at conferences is an investment of speakers in time, energy, and knowledge. The quality of a presentation and of the conference itself can be measured in the amount of investment made.
5 |
6 | Here are my tips for future conference speakers.
7 |
8 | Choosing A Conference
9 |
10 | At which conference you choose to speak is arguably as important as the topic selection and the amount of work put into the presentation. There are very obvious factors that everyone should consider such as the overall theme, audience that will be attending, and overall conference size.
11 |
12 | A conference of 200 people on a specific topic in a remote region deserves a very different preparation than one of 2000 people on a general topic in a large tech hub. The smaller of these two would require something very detailed on which you consider yourself an expert because the people in attendance will expect it. At the larger one you can still give the same detailed talk, but you also have the option of being more broad, appealing more to introductory learners, and not having to be an absolute authority on the subject.
13 |
14 | Beyond those, there are other very important factors that I consider essential criteria when selecting where to speak.
15 |
16 | Recording
17 |
18 | Unless you are going to give the same presentation over and over again (and some do this, refining it over time), having your talk recorded means you instantly increase the size of your potential audience by 1000x. Not only does this force you to know what you are talking about and make pretty slides, but it helps justify the amount of work required to prepare.
19 |
20 | Rather than having only static images to refer to or your sweet (cough) prezi, those wishing to review your presentation can do so directly from you in addition to the static version (see ‘Publishing’ below).
21 |
22 | Some conferences will really go above and beyond in recording. Devoxx not only uses professional recording equipment with manned cameras, but they also publish their talks on parleys.com which features slides that are synchronized with the video. You can watch my talk from last year on Dagger for an example.
23 |
24 | Venue
25 |
26 | With the amount of time it takes to prepare a presentation, you want it to be seen and heard by as many as possible. A bad venue can really turn an otherwise interesting set of speakers into a painful experience. Not being able to see or hear in a room is bad, but having to turn away tons of people due to poor planning or room size is even worse.
27 |
28 | Beyond the physical, the technical facilities of a conference are of great importance. The size, placement, and resolution of the screen ensures that your content will be legible to all in the room. At this point it is inexcusable to have anything other than a widescreen, high-definition projector. Screen size should simply be as large as possible. For a presentation of anything over 20 or 30 a speaker and mic setup is essential. The size of the room should dictate how large the speaker setup needs to be.
29 |
30 |
31 |
32 | This is another Devoxx slam-dunk as it is hosted inside a movie theater with stadium seating (pictured). Presenters wear tiny mics and stand beneath an absolutely massive screen onto which both your slides and a real-time video feed is shown. As both an attendee and presenter it’s a fantastic experience.
33 |
34 | Organizers
35 |
36 | The people behind the conference is an interesting factor to guage a conference by but it turns out to be an important one. Some conferences are run by companies who have motives beyond the conference content itself. All conferences will have sponsors and may even be run by people who work for a single company. The difference is the companies for which running conferences is part of their job. By doing this, their motivation for recording talks, finding the best venues, and having the best equipment is greatly diminished by ulterior motives.
37 |
38 | A conference that is run by a company is likely still a good conference to attend and will attract good speakers. It’s just a choice you have to make as to whether you want to support something like that. There is a well-known Android conference in San Francisco that I would love to see destroyed by a Droidcon SF since they are guilty of not doing the things listed above.
39 |
40 | Creating Your Slides
41 |
42 | There are tons of articles on how to create effective slides. Slides should normally exist to augment and re-enforce you. Granted, some things like screenshots and code snippets are invaluable, and invert the roles allowing you to augment them. I’m not going re-iterate the well-known things and instead focus on what’s applicable for technical talks.
43 |
44 | Getting Started
45 |
46 | There’s a variety of tools to choose from for creating slides, choose the one that best suits the job. Google Slides is fantastic for collaborating on content, Keynote has a fantastic balance of simplicity and power, and Javascript-based tools allow fantastic interactivity. There’s also PowerPoint, but I’m not a Windows user. All will work, choose the one which will make you the most productive and I’ll leave it to other articles to compare.
47 |
48 | Slides should be done in widescreen (16:9) at 1080p (1920x1080) resolution. Hopefully this will be the native resolution at which they will be played (as discussed above), but at worst they will be downscaled which is always better than having them upscaled.
49 |
50 | Never start a presentation with a description of who you are, what you do, and the outline of your slides. This is content for the abstract of your talk that most people will have read and used in choosing to attend. Those who didn’t read this information don’t need it because they chose your talk for its catchy title or something and thus won’t care either way.
51 |
52 | Text Bullets
53 |
54 | Good ‘ol bullets of text. The fundamental building block of a presentation. Some people can get away with using only single words, short phrases, and pretty images but rarely does that fly for a technical talk.
55 |
56 | There is no “too large” for font size of your text. Better to err on the side of large than too small. A single slide should only be able to fit 6 single-line bullets of text. What you think is readable when sitting two feet from your 23” monitor might not be readable at full scale. Start your slideshow and stand back 6 to 10 feet (depending on monitor size) and ensure that everything is readable.
57 |
58 |
59 |
--------------------------------------------------------------------------------
/gradle-mvn-push.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Chris Banes
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | apply plugin: 'maven'
18 | apply plugin: 'signing'
19 |
20 | version = VERSION_NAME
21 | group = GROUP
22 |
23 | def isReleaseBuild() {
24 | return VERSION_NAME.contains("SNAPSHOT") == false
25 | }
26 |
27 | def getReleaseRepositoryUrl() {
28 | return hasProperty('RELEASE_REPOSITORY_URL') ? RELEASE_REPOSITORY_URL :
29 | "https://oss.sonatype.org/service/local/staging/deploy/maven2/"
30 | }
31 |
32 | def getSnapshotRepositoryUrl() {
33 | return hasProperty('SNAPSHOT_REPOSITORY_URL') ? SNAPSHOT_REPOSITORY_URL :
34 | "https://oss.sonatype.org/content/repositories/snapshots/"
35 | }
36 |
37 | def getRepositoryUsername() {
38 | return hasProperty('SONATYPE_NEXUS_USERNAME') ? SONATYPE_NEXUS_USERNAME : ""
39 | }
40 |
41 | def getRepositoryPassword() {
42 | return hasProperty('SONATYPE_NEXUS_PASSWORD') ? SONATYPE_NEXUS_PASSWORD : ""
43 | }
44 |
45 | afterEvaluate { project ->
46 | uploadArchives {
47 | repositories {
48 | mavenDeployer {
49 | beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
50 |
51 | pom.groupId = GROUP
52 | pom.artifactId = POM_ARTIFACT_ID
53 | pom.version = VERSION_NAME
54 |
55 | repository(url: getReleaseRepositoryUrl()) {
56 | authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())
57 | }
58 | snapshotRepository(url: getSnapshotRepositoryUrl()) {
59 | authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())
60 | }
61 |
62 | pom.project {
63 | name POM_NAME
64 | packaging POM_PACKAGING
65 | description POM_DESCRIPTION
66 | url POM_URL
67 |
68 | scm {
69 | url POM_SCM_URL
70 | connection POM_SCM_CONNECTION
71 | developerConnection POM_SCM_DEV_CONNECTION
72 | }
73 |
74 | licenses {
75 | license {
76 | name POM_LICENCE_NAME
77 | url POM_LICENCE_URL
78 | distribution POM_LICENCE_DIST
79 | }
80 | }
81 |
82 | developers {
83 | developer {
84 | id POM_DEVELOPER_ID
85 | name POM_DEVELOPER_NAME
86 | }
87 | }
88 | }
89 | }
90 | }
91 | }
92 |
93 | signing {
94 | required { isReleaseBuild() && gradle.taskGraph.hasTask("uploadArchives") }
95 | sign configurations.archives
96 | }
97 |
98 | if (project.getPlugins().hasPlugin('com.android.application') ||
99 | project.getPlugins().hasPlugin('com.android.library')) {
100 | task install(type: Upload, dependsOn: assemble) {
101 | repositories.mavenInstaller {
102 | configuration = configurations.archives
103 |
104 | pom.groupId = GROUP
105 | pom.artifactId = POM_ARTIFACT_ID
106 | pom.version = VERSION_NAME
107 |
108 | pom.project {
109 | name POM_NAME
110 | packaging POM_PACKAGING
111 | description POM_DESCRIPTION
112 | url POM_URL
113 |
114 | scm {
115 | url POM_SCM_URL
116 | connection POM_SCM_CONNECTION
117 | developerConnection POM_SCM_DEV_CONNECTION
118 | }
119 |
120 | licenses {
121 | license {
122 | name POM_LICENCE_NAME
123 | url POM_LICENCE_URL
124 | distribution POM_LICENCE_DIST
125 | }
126 | }
127 |
128 | developers {
129 | developer {
130 | id POM_DEVELOPER_ID
131 | name POM_DEVELOPER_NAME
132 | }
133 | }
134 | }
135 | }
136 | }
137 |
138 | task androidJavadocs(type: Javadoc) {
139 | source = android.sourceSets.main.java.source
140 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
141 | }
142 |
143 | task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) {
144 | classifier = 'javadoc'
145 | from androidJavadocs.destinationDir
146 | }
147 |
148 | task androidSourcesJar(type: Jar) {
149 | classifier = 'sources'
150 | from android.sourceSets.main.java.source
151 | }
152 | } else {
153 | install {
154 | repositories.mavenInstaller {
155 | pom.groupId = GROUP
156 | pom.artifactId = POM_ARTIFACT_ID
157 | pom.version = VERSION_NAME
158 |
159 | pom.project {
160 | name POM_NAME
161 | packaging POM_PACKAGING
162 | description POM_DESCRIPTION
163 | url POM_URL
164 |
165 | scm {
166 | url POM_SCM_URL
167 | connection POM_SCM_CONNECTION
168 | developerConnection POM_SCM_DEV_CONNECTION
169 | }
170 |
171 | licenses {
172 | license {
173 | name POM_LICENCE_NAME
174 | url POM_LICENCE_URL
175 | distribution POM_LICENCE_DIST
176 | }
177 | }
178 |
179 | developers {
180 | developer {
181 | id POM_DEVELOPER_ID
182 | name POM_DEVELOPER_NAME
183 | }
184 | }
185 | }
186 | }
187 | }
188 |
189 | task sourcesJar(type: Jar, dependsOn: classes) {
190 | classifier = 'sources'
191 | from sourceSets.main.allSource
192 | }
193 |
194 | task javadocJar(type: Jar, dependsOn: javadoc) {
195 | classifier = 'javadoc'
196 | from javadoc.destinationDir
197 | }
198 | }
199 |
200 | if (JavaVersion.current().isJava8Compatible()) {
201 | allprojects {
202 | tasks.withType(Javadoc) {
203 | options.addStringOption('Xdoclint:none', '-quiet')
204 | }
205 | }
206 | }
207 |
208 | artifacts {
209 | if (project.getPlugins().hasPlugin('com.android.application') ||
210 | project.getPlugins().hasPlugin('com.android.library')) {
211 | archives androidSourcesJar
212 | archives androidJavadocsJar
213 | } else {
214 | archives sourcesJar
215 | archives javadocJar
216 | }
217 | }
218 | }
219 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_angle_auto.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
16 |
17 |
23 |
24 |
32 |
33 |
34 |
35 |
43 |
44 |
48 |
49 |
54 |
55 |
60 |
61 |
66 |
67 |
75 |
76 |
77 |
78 |
81 |
82 |
87 |
88 |
93 |
94 |
102 |
103 |
104 |
105 |
106 |
107 |
113 |
114 |
119 |
120 |
125 |
126 |
134 |
135 |
136 |
137 |
140 |
141 |
146 |
147 |
152 |
153 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_simple_zdepth.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
19 |
20 |
26 |
27 |
28 |
29 |
37 |
38 |
44 |
45 |
46 |
47 |
53 |
54 |
60 |
61 |
62 |
63 |
69 |
70 |
76 |
77 |
78 |
79 |
85 |
86 |
92 |
93 |
94 |
95 |
101 |
102 |
108 |
109 |
110 |
116 |
117 |
124 |
125 |
126 |
127 |
133 |
134 |
141 |
142 |
143 |
144 |
150 |
151 |
158 |
159 |
160 |
161 |
167 |
168 |
175 |
176 |
177 |
178 |
184 |
185 |
192 |
193 |
194 |
195 |
201 |
202 |
209 |
210 |
211 |
212 |
213 |
214 |
--------------------------------------------------------------------------------
/library/src/main/java/com/ytjojo/shadowlayout/shadowdelegate/PathModel.java:
--------------------------------------------------------------------------------
1 | package com.ytjojo.shadowlayout.shadowdelegate;
2 |
3 | import android.content.res.TypedArray;
4 | import android.graphics.BlurMaskFilter;
5 | import android.graphics.Canvas;
6 | import android.graphics.Color;
7 | import android.graphics.Paint;
8 | import android.graphics.Path;
9 | import android.graphics.Point;
10 | import android.graphics.Rect;
11 | import android.graphics.Region;
12 | import android.os.Build;
13 | import android.support.annotation.ColorInt;
14 | import android.view.View;
15 |
16 | import com.ytjojo.shadowlayout.R;
17 | import com.ytjojo.shadowlayout.ShadowLayout;
18 |
19 | /**
20 | * Created by Administrator on 2017/11/4 0004.
21 | */
22 |
23 | public class PathModel implements ShadowDelegate {
24 | private final static float MIN_RADIUS = 0.1F;
25 | Path mPath;
26 | Path mClipPath;
27 | Path mShadowpath;
28 | Paint mPaint;
29 | ShadowLayout mParent;
30 | float mShadowRadius;
31 | private float mOffsetDy;
32 | private float mOffsetDx;
33 |
34 | private Point mControlPoint1;
35 | private Point mControlPoint2;
36 | private int mEndRightY;
37 | private int mStartLeftY;
38 | private float mCoordinatex1;
39 | private float mCoordinatey1;
40 | private float mCoordinatex2;
41 | private float mCoordinatey2;
42 | private float mRatgStartLeftY;
43 | private float mRateEndRightY;
44 | Rect mBoundsRect;
45 |
46 | public PathModel(ShadowLayout parent, TypedArray typedArray) {
47 | mParent = parent;
48 | mBoundsRect = new Rect();
49 | mParent.setWillNotDraw(false);
50 | mParent.setClipToPadding(false);
51 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
52 | mParent.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
53 | }
54 | mPath = new Path();
55 | mClipPath = new Path();
56 | mShadowpath = new Path();
57 | mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
58 | mPaint.setDither(true);
59 | mPaint.setStyle(Paint.Style.FILL);
60 | setShadowColor(
61 | typedArray.getColor(
62 | R.styleable.ShadowLayout_sl_shadow_color, Color.BLACK
63 | )
64 | );
65 |
66 | setShadowRadius(
67 | typedArray.getDimension(
68 | R.styleable.ShadowLayout_sl_shadow_radius, 25
69 | )
70 | );
71 | mOffsetDx = typedArray.getDimensionPixelSize(
72 | R.styleable.ShadowLayout_sl_shadow_offsetdx, 0
73 | );
74 | mOffsetDy = typedArray.getDimensionPixelSize(
75 | R.styleable.ShadowLayout_sl_shadow_offsetdy, 0
76 | );
77 | mCoordinatex1 = typedArray.getFloat(R.styleable.ShadowLayout_shadow_path_coordinatex1,0f);
78 | mCoordinatey1 = typedArray.getFloat(R.styleable.ShadowLayout_shadow_path_coordinatey1,1f);
79 | mCoordinatex2 = typedArray.getFloat(R.styleable.ShadowLayout_shadow_path_coordinatex2,1f);
80 | mCoordinatey2 = typedArray.getFloat(R.styleable.ShadowLayout_shadow_path_coordinatey2,1f);
81 | mRatgStartLeftY = typedArray.getFloat(R.styleable.ShadowLayout_shadow_path_startleft_y_rate,0.6f);
82 | mRateEndRightY = typedArray.getFloat(R.styleable.ShadowLayout_shadow_path_endright_y_rate,0.6f);
83 | }
84 |
85 |
86 | @Override
87 | public void onDraw(Canvas canvas) {
88 | mParent.superdispatchDraw(canvas);
89 | }
90 |
91 | @Override
92 | public void onDrawOver(Canvas canvas) {
93 | canvas.save();
94 | // if(Build.VERSION.SDK_INT>=19){
95 | // canvas.clipPath(mPath);
96 | // }else{
97 | // canvas.clipPath(mPath, Region.Op.REPLACE);
98 | // canvas.clipPath(mClipPath, Region.Op.DIFFERENCE);
99 | // }
100 | canvas.clipPath(mPath, Region.Op.REPLACE);
101 | canvas.clipPath(mClipPath, Region.Op.DIFFERENCE);
102 | mPaint.setColor(Color.BLACK);
103 | mShadowpath.set(mClipPath);
104 | mShadowpath.offset(mOffsetDx, mOffsetDy);
105 | canvas.drawPath(mShadowpath, mPaint);
106 | canvas.restore();
107 |
108 | }
109 |
110 | @Override
111 | public boolean onClipCanvas(Canvas canvas, View child) {
112 |
113 | canvas.clipPath(mClipPath);
114 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
115 | child.invalidateOutline();
116 | }
117 | return false;
118 | }
119 |
120 | @Override
121 | public void invalidateShadow() {
122 | mParent.postInvalidate();
123 | }
124 |
125 | @Override
126 | public void setShadowColor(@ColorInt int color) {
127 | mPaint.setColor(color);
128 | mParent.postInvalidate();
129 | }
130 |
131 | @Override
132 | public void onLayout(boolean changed, int left, int top, int right, int bottom) {
133 | mBoundsRect.set(left,top,right,bottom);
134 | mPath.reset();
135 | mShadowpath.reset();
136 | mPath.lineTo(left, top);
137 | mPath.lineTo(right, top);
138 | mPath.lineTo(right, bottom);
139 | mPath.lineTo(left, bottom);
140 | mPath.lineTo(left, top);
141 | if(!useCustom){
142 | mClipPath.reset();
143 | int width = right - left;
144 | int height = bottom - top;
145 | if(mControlPoint1==null){
146 | mControlPoint1 = new Point();
147 | }
148 | if(mControlPoint2==null){
149 | mControlPoint2 = new Point();
150 | }
151 | mControlPoint1.set((int)(mCoordinatex1*width+left),(int)(mCoordinatey1*height+top));
152 | mControlPoint2.set((int)(mCoordinatex2*width+left),(int)(mCoordinatey2*height+top));
153 | mStartLeftY = (int) (mRatgStartLeftY*height+top);
154 | mEndRightY = (int) (mRateEndRightY*height+top);
155 |
156 | mClipPath.moveTo(left, top);
157 | mClipPath.lineTo(left, mStartLeftY);
158 | mClipPath.cubicTo(mControlPoint1.x, mControlPoint1.y, mControlPoint2.x, mControlPoint2.y, right,mEndRightY);
159 | mClipPath.lineTo(right, top);
160 | mClipPath.lineTo(left, top);
161 |
162 | // if(Build.VERSION.SDK_INT>=19){
163 | // mPath.op(mClipPath, Path.Op.DIFFERENCE);
164 | // }
165 | }
166 |
167 |
168 | }
169 | public void changeClipPath(){
170 | mClipPath.reset();
171 | if(mBoundsRect.isEmpty()){
172 | return;
173 | }
174 | if(mControlPoint1==null){
175 | mControlPoint1 = new Point();
176 | }
177 | if(mControlPoint2==null){
178 | mControlPoint2 = new Point();
179 | }
180 | mControlPoint1.set((int)(mCoordinatex1*mBoundsRect.width()+mBoundsRect.left),(int)(mCoordinatey1*mBoundsRect.height()+mBoundsRect.top));
181 | mControlPoint2.set((int)(mCoordinatex2*mBoundsRect.width()+mBoundsRect.left),(int)(mCoordinatey2*mBoundsRect.height()+mBoundsRect.top));
182 | mStartLeftY = (int) (mRatgStartLeftY*mBoundsRect.height()+mBoundsRect.top);
183 | mEndRightY = (int) (mRateEndRightY*mBoundsRect.height()+mBoundsRect.top);
184 |
185 | mClipPath.moveTo(mBoundsRect.left, mBoundsRect.top);
186 | mClipPath.lineTo(mBoundsRect.left, mStartLeftY);
187 | mClipPath.cubicTo(mControlPoint1.x, mControlPoint1.y, mControlPoint2.x, mControlPoint2.y, mBoundsRect.right,mEndRightY);
188 | mClipPath.lineTo(mBoundsRect.right, mBoundsRect.top);
189 | mClipPath.lineTo(mBoundsRect.left, mBoundsRect.top);
190 | invalidateShadow();
191 | }
192 |
193 | @Override
194 | public void onAttachToWindow() {
195 |
196 | }
197 |
198 | @Override
199 | public void onDetachedFromWindow() {
200 |
201 | }
202 |
203 | public void setShadowRadius(final float shadowRadius) {
204 | mShadowRadius = Math.max(MIN_RADIUS, shadowRadius);
205 |
206 | if (mParent.isInEditMode()) return;
207 | // Set blur filter to paint
208 | mPaint.setMaskFilter(new BlurMaskFilter(mShadowRadius, BlurMaskFilter.Blur.NORMAL));
209 | invalidateShadow();
210 | }
211 | private boolean useCustom;
212 | public void setPath(Path path){
213 | useCustom = true;
214 | this.mClipPath = path;
215 | invalidateShadow();
216 | }
217 | public void setControlPoint1(float xRate,float yRate){
218 | this.mCoordinatex1 =xRate;
219 | this.mCoordinatey1 =yRate;
220 | }
221 | public void setControlPoint2(float xRate,float yRate){
222 | this.mCoordinatex2 =xRate;
223 | this.mCoordinatey2 =yRate;
224 | }
225 |
226 | public void setRatgStartLeftY(int ratgStartLeftY) {
227 | this.mRatgStartLeftY = ratgStartLeftY;
228 | }
229 | public void setRateEndRightY(int rateEndRightY) {
230 | this.mRateEndRightY = rateEndRightY;
231 | }
232 | }
233 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ShadowLayout
2 | ==================
3 |
4 | Android powerful library- draw any shape of z-depth shadow of MaterialDesign,auto fit shape ,roundRect , Circle, clipe Path shape all be supportted
5 |
6 |
7 | ## Thanks
8 |
9 | sho5nn
10 | https://github.com/sho5nn/ZDepthShadow
11 |
12 | Devlight
13 | https://github.com/Devlight/ShadowLayout
14 |
15 | ##中文原理分析
16 | [中文原理分析](强大的剪裁+阴影效果布局ShadowLayout.md)
17 |
18 | ## Demo
19 |
20 | 
21 |
22 | ## Screen Capture
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 | ## Download
55 |
56 | ```groovy
57 | apply plugin: 'com.android.application'
58 |
59 | repositories {
60 | jcenter()
61 | mavenCentral()
62 | }
63 |
64 | android {
65 | // something code...
66 | }
67 |
68 | dependencies {
69 | compile 'com.github.ytjojo:ShadowLayout:1.0.1'
70 | }
71 | ```
72 |
73 | ## How to Use
74 |
75 | ShapeModel
76 |
77 | ```xml
78 |
84 |
85 |
91 |
92 |
93 | ```
94 |
95 | Shapmodel clip
96 |
97 | ```xml
98 |
107 |
108 |
113 |
114 | ```
115 |
116 | autoModel
117 |
118 | ```xml
119 |
127 |
128 |
134 |
135 | ```
136 |
137 | auto model use angle
138 |
139 | ```xml
140 |
148 |
149 |
155 |
156 |
164 |
165 |
166 | ```
167 |
168 | 
169 |
170 |
171 |
172 | PathModel
173 |
174 | ```xml
175 |
186 |
191 |
192 | ```
193 |
194 |
195 |
196 | you can custom path
197 |
198 | ```java
199 | PathModel pathModel= (PathModel) shadowLayout.getShadowDeltegate();
200 | pathModel.setPath(mCustomPath);
201 | ```
202 |
203 |
204 |
205 | ### Attribute
206 |
207 |
208 |
209 | #### attrs.xml
210 |
211 | ```xml
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 | ```
290 |
291 | ## What is ZDepth?
292 |
293 | 
294 |
295 | #### Example : z-depth 5
296 |
297 | 
298 |
299 |
300 |
301 |
302 |
303 |
304 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
17 |
22 |
27 |
31 |
40 |
41 |
46 |
47 |
48 |
49 |
50 |
55 |
56 |
67 |
68 |
75 |
76 |
77 |
87 |
88 |
95 |
96 |
97 |
105 |
106 |
115 |
116 |
124 |
125 |
126 |
135 |
136 |
142 |
143 |
144 |
153 |
154 |
159 |
160 |
161 |
170 |
171 |
177 |
178 |
179 |
184 |
185 |
191 |
192 |
197 |
198 |
204 |
205 |
210 |
211 |
217 |
218 |
223 |
224 |
230 |
231 |
237 |
238 |
239 |
244 |
245 |
246 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_change_zdepth.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
25 |
26 |
32 |
33 |
34 |
35 |
43 |
44 |
50 |
51 |
52 |
53 |
54 |
64 |
65 |
72 |
73 |
74 |
75 |
82 |
83 |
94 |
95 |
102 |
103 |
104 |
115 |
116 |
123 |
124 |
125 |
126 |
137 |
138 |
145 |
146 |
147 |
148 |
154 |
155 |
166 |
167 |
174 |
175 |
176 |
187 |
188 |
195 |
196 |
197 |
198 |
199 |
204 |
205 |
216 |
217 |
224 |
225 |
226 |
227 |
228 |
229 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_simple_auto.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
12 |
21 |
26 |
32 |
38 |
44 |
50 |
56 |
57 |
58 |
59 |
60 |
65 |
66 |
74 |
75 |
81 |
82 |
83 |
91 |
92 |
98 |
99 |
100 |
101 |
102 |
107 |
108 |
116 |
117 |
123 |
124 |
125 |
133 |
134 |
140 |
141 |
142 |
143 |
144 |
145 |
150 |
151 |
159 |
160 |
166 |
167 |
168 |
176 |
177 |
183 |
184 |
185 |
186 |
187 |
192 |
193 |
201 |
202 |
208 |
209 |
210 |
218 |
219 |
225 |
226 |
227 |
228 |
229 |
234 |
235 |
243 |
244 |
250 |
251 |
252 |
260 |
261 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
--------------------------------------------------------------------------------
/app/src/main/java/app/mosn/zdepthshadowsample/MainActivity.java:
--------------------------------------------------------------------------------
1 | package app.mosn.zdepthshadowsample;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import android.graphics.Color;
6 | import android.os.Bundle;
7 | import android.support.annotation.ColorInt;
8 | import android.widget.CompoundButton;
9 | import android.widget.ImageView;
10 | import android.widget.SeekBar;
11 | import android.widget.Switch;
12 | import android.widget.TextView;
13 |
14 | import com.bumptech.glide.Glide;
15 | import com.bumptech.glide.load.MultiTransformation;
16 | import com.bumptech.glide.load.resource.bitmap.CenterCrop;
17 | import com.jaredrummler.android.colorpicker.ColorPickerDialog;
18 | import com.jaredrummler.android.colorpicker.ColorPickerDialogListener;
19 | import com.orhanobut.logger.AndroidLogAdapter;
20 | import com.orhanobut.logger.FormatStrategy;
21 | import com.orhanobut.logger.LogcatLogStrategy;
22 | import com.orhanobut.logger.Logger;
23 | import com.orhanobut.logger.PrettyFormatStrategy;
24 | import com.ytjojo.shadowlayout.ShadowLayout;
25 | import com.ytjojo.shadowlayout.demo.R;
26 | import com.ytjojo.shadowlayout.shadowdelegate.AutoModel;
27 |
28 | import butterknife.BindView;
29 | import butterknife.ButterKnife;
30 | import butterknife.OnClick;
31 | import jp.wasabeef.glide.transformations.RoundedCornersTransformation;
32 |
33 | import static com.bumptech.glide.request.RequestOptions.bitmapTransform;
34 | public class MainActivity extends Activity {
35 |
36 | ShadowLayout mRoundSL;
37 | ShadowLayout mCircleSL;
38 | ImageView mImgRound;
39 | SeekBar progressBar;
40 | TextView mTvOffsetDx;
41 | TextView mTvZoomDy;
42 | TextView mTvOffsetDy;
43 | TextView mTvRadius;
44 | AutoModel mRoundAm;
45 | AutoModel mCirclAm;
46 | @BindView(R.id.ovalShapeSl)
47 | ShadowLayout mOvalShapeSl;
48 | @Override
49 | protected void onCreate(Bundle savedInstanceState) {
50 | super.onCreate(savedInstanceState);
51 | FormatStrategy formatStrategy = PrettyFormatStrategy.newBuilder()
52 | .showThreadInfo(false) // (Optional) Whether to show thread info or not. Default true
53 | .methodCount(2) // (Optional) How many method line to show. Default 2
54 | .methodOffset(5) // (Optional) Hides internal method calls up to offset. Default 5
55 | .logStrategy(new LogcatLogStrategy()) // (Optional) Changes the log strategy to print out. Default LogCat
56 | .tag("My custom tag") // (Optional) Global tag for every log. Default PRETTY_LOGGER
57 | .build();
58 |
59 | Logger.addLogAdapter(new AndroidLogAdapter(formatStrategy));
60 | setContentView(R.layout.activity_main);
61 | ButterKnife.bind(this);
62 | mCircleSL = (ShadowLayout) findViewById(R.id.sl_circle);
63 | mRoundSL = (ShadowLayout) findViewById(R.id.sl_round);
64 | int value= (int) DisplayUtil.dip2px(30,this);
65 | mRoundSL.setPadding(value,value,value,value);
66 | mCircleSL.setPadding(value,value,value,value);
67 | mCirclAm= (AutoModel) mCircleSL.getShadowDeltegate();
68 | mRoundAm= (AutoModel) mRoundSL.getShadowDeltegate();
69 | mImgRound = (ImageView) findViewById(R.id.img_round);
70 | mTvRadius = (TextView) findViewById(R.id.tv_radius);
71 | mTvOffsetDx = (TextView) findViewById(R.id.tv_offsetDx);
72 | mTvOffsetDy = (TextView) findViewById(R.id.tv_offsetDy);
73 | mTvZoomDy = (TextView) findViewById(R.id.tv_zoomdy);
74 | mImgRound.postDelayed(new Runnable() {
75 | @Override
76 | public void run() {
77 | mImgRound.requestLayout();
78 | }
79 | },2000);
80 | MultiTransformation multi = new MultiTransformation(
81 | new CenterCrop(),
82 | new RoundedCornersTransformation(25, 0, RoundedCornersTransformation.CornerType.ALL));
83 | Glide.with(this).load(R.mipmap.ngr_patient_back_followup_statistics_1).apply( bitmapTransform(multi)).into(mImgRound);
84 | progressBar = (SeekBar) findViewById(R.id.seekbar_zoomdy);
85 | progressBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
86 |
87 | @Override
88 | public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
89 | if(fromUser){
90 | float zoomDy = DisplayUtil.dip2px(progress,MainActivity.this);
91 | zoomDy -= DisplayUtil.dip2px(seekBar.getMax()/2,MainActivity.this);
92 | mCirclAm.setZoomDy(zoomDy);
93 | mRoundAm.setZoomDy(zoomDy);
94 | mTvZoomDy.setText("zoomdy value ="+zoomDy);
95 | }
96 | }
97 |
98 | @Override
99 | public void onStartTrackingTouch(SeekBar seekBar) {
100 |
101 | }
102 |
103 | @Override
104 | public void onStopTrackingTouch(SeekBar seekBar) {
105 |
106 | }
107 | });
108 | progressBar = (SeekBar) findViewById(R.id.seekbar_dx);
109 | progressBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
110 | @Override
111 | public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
112 | if(fromUser){
113 | float offsetDx = DisplayUtil.dip2px(progress,MainActivity.this);
114 | offsetDx -= DisplayUtil.dip2px(seekBar.getMax()/2,MainActivity.this);
115 | mCirclAm.setOffsetDx(offsetDx);
116 | mRoundAm.setOffsetDx(offsetDx);
117 | mTvOffsetDx.setText("offsetDx value ="+offsetDx);
118 | }
119 | }
120 |
121 | @Override
122 | public void onStartTrackingTouch(SeekBar seekBar) {
123 |
124 | }
125 |
126 | @Override
127 | public void onStopTrackingTouch(SeekBar seekBar) {
128 |
129 | }
130 | });
131 | progressBar = (SeekBar) findViewById(R.id.seekbar_dy);
132 | progressBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
133 | @Override
134 | public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
135 | if(fromUser){
136 | float offsetDy = DisplayUtil.dip2px(progress,MainActivity.this);
137 | offsetDy -= DisplayUtil.dip2px(seekBar.getMax()/2,MainActivity.this);
138 | mCirclAm.setOffsetDy(offsetDy);
139 | mRoundAm.setOffsetDy(offsetDy);
140 | mTvOffsetDy.setText("offsetDy value ="+offsetDy);
141 | }
142 | }
143 |
144 | @Override
145 | public void onStartTrackingTouch(SeekBar seekBar) {
146 |
147 | }
148 |
149 | @Override
150 | public void onStopTrackingTouch(SeekBar seekBar) {
151 |
152 | }
153 | });
154 | progressBar = (SeekBar) findViewById(R.id.seekbar_radius);
155 | progressBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
156 | @Override
157 | public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
158 | if(fromUser){
159 | float radius = DisplayUtil.dip2px(progress,MainActivity.this);
160 | mCirclAm.setRadius(radius);
161 | mRoundAm.setRadius(radius);
162 | mTvRadius.setText("radius value ="+radius);
163 | }
164 | }
165 |
166 | @Override
167 | public void onStartTrackingTouch(SeekBar seekBar) {
168 |
169 | }
170 |
171 | @Override
172 | public void onStopTrackingTouch(SeekBar seekBar) {
173 |
174 | }
175 | });
176 | Switch sw = (Switch) findViewById(R.id.switch_drawCenter);
177 | sw.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
178 | @Override
179 | public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
180 | mCirclAm.setDrawCenter(isChecked);
181 | mRoundAm.setDrawCenter(isChecked);
182 | }
183 | });
184 | }
185 | @OnClick(R.id.tv_Simplezdepth)
186 | public void goSimpleZdepth(){
187 | Intent intent = new Intent(this, SimpleZDepthActivity.class);
188 | startActivity(intent);
189 | }
190 | @OnClick(R.id.tv_Changezdepth)
191 | public void goChangeZdepth(){
192 | Intent intent = new Intent(this, ChangeZDepthActivity.class);
193 | startActivity(intent);
194 | }
195 | @OnClick(R.id.sl_goSimpleAuto)
196 | public void goSimpleAuto(){
197 | Intent intent = new Intent(this, SimpleAutoActivity.class);
198 | startActivity(intent);
199 | }
200 | @OnClick(R.id.sl_goAngleActivity)
201 | public void goAngleAuto(){
202 | Intent intent = new Intent(this, SimpleAngleAutoActivity.class);
203 | startActivity(intent);
204 | }
205 | @OnClick(R.id.sl_round)
206 | public void roundSelectColor(){
207 | ColorPickerDialog dialog =ColorPickerDialog.newBuilder()
208 | .setDialogType(ColorPickerDialog.TYPE_CUSTOM)
209 | .setAllowPresets(false)
210 | .setDialogId(1)
211 | .setColor(Color.BLACK)
212 | .setShowAlphaSlider(true)
213 | .create();
214 | dialog.show(getFragmentManager(),"color-picker-dialog");
215 |
216 |
217 | dialog.setColorPickerDialogListener(new ColorPickerDialogListener() {
218 | @Override
219 | public void onColorSelected(int dialogId, @ColorInt int color) {
220 | if(dialogId ==1){
221 | mRoundSL.setShadowColor(color);
222 | }
223 | }
224 |
225 | @Override
226 | public void onDialogDismissed(int dialogId) {
227 |
228 | }
229 | });
230 |
231 | }
232 | @OnClick(R.id.sl_circle)
233 | public void circleSelectColor(){
234 | ColorPickerDialog dialog =ColorPickerDialog.newBuilder()
235 | .setDialogType(ColorPickerDialog.TYPE_CUSTOM)
236 | .setAllowPresets(false)
237 | .setDialogId(0)
238 | .setColor(Color.BLACK)
239 | .setShowAlphaSlider(true)
240 | .create();
241 | dialog.show(getFragmentManager(),"color-picker-dialog");
242 |
243 |
244 | dialog.setColorPickerDialogListener(new ColorPickerDialogListener() {
245 | @Override
246 | public void onColorSelected(int dialogId, @ColorInt int color) {
247 | if(dialogId ==0){
248 | mCircleSL.setShadowColor(color);
249 | }
250 | }
251 |
252 | @Override
253 | public void onDialogDismissed(int dialogId) {
254 |
255 | }
256 | });
257 | }
258 | @OnClick(R.id.ovalShapeSl)
259 | public void ovalShapeSlSelectColor(){
260 | ColorPickerDialog dialog =ColorPickerDialog.newBuilder()
261 | .setDialogType(ColorPickerDialog.TYPE_PRESETS)
262 | .setAllowPresets(false)
263 | .setDialogId(2)
264 | .setColor(Color.BLACK)
265 | .setShowAlphaSlider(true)
266 | .create();
267 | dialog.show(getFragmentManager(),"color-picker-dialog");
268 |
269 |
270 | dialog.setColorPickerDialogListener(new ColorPickerDialogListener() {
271 | @Override
272 | public void onColorSelected(int dialogId, @ColorInt int color) {
273 | if(dialogId ==2){
274 | mOvalShapeSl.setShadowColor(color);
275 | }
276 | }
277 |
278 | @Override
279 | public void onDialogDismissed(int dialogId) {
280 |
281 | }
282 | });
283 | }
284 |
285 | @OnClick(R.id.tv_pathModel)
286 | protected void goSimplePathShadowActivity() {
287 | Intent intent = new Intent(this,SimplePathShadowActivity.class);
288 | startActivity(intent);
289 | }
290 | @OnClick(R.id.tv_blurmaskfilterView)
291 | protected void goBlurMaskFilterActivity() {
292 | Intent intent = new Intent(this,BlurMaskFilterActivity.class);
293 | startActivity(intent);
294 | }
295 | }
296 |
--------------------------------------------------------------------------------
/library/src/main/java/com/ytjojo/shadowlayout/shadowdelegate/AutoModel.java:
--------------------------------------------------------------------------------
1 | package com.ytjojo.shadowlayout.shadowdelegate;
2 |
3 | import android.content.res.TypedArray;
4 | import android.graphics.Bitmap;
5 | import android.graphics.BlurMaskFilter;
6 | import android.graphics.Canvas;
7 | import android.graphics.Color;
8 | import android.graphics.Matrix;
9 | import android.graphics.Paint;
10 | import android.graphics.Path;
11 | import android.graphics.PorterDuff;
12 | import android.graphics.Rect;
13 | import android.support.annotation.FloatRange;
14 | import android.view.View;
15 |
16 | import com.ytjojo.shadowlayout.R;
17 | import com.ytjojo.shadowlayout.ShadowLayout;
18 |
19 | /**
20 | * Created by Administrator on 2017/11/1 0001.
21 | */
22 |
23 | public class AutoModel implements ShadowDelegate {
24 |
25 |
26 | // Default shadow values
27 | private final static float DEFAULT_SHADOW_RADIUS = 30.0F;
28 | private final static float DEFAULT_SHADOW_DISTANCE = 15.0F;
29 | private final static float DEFAULT_SHADOW_ANGLE = 45.0F;
30 | private final static int DEFAULT_SHADOW_COLOR = Color.DKGRAY;
31 |
32 | // Shadow bounds values
33 | private final static int MAX_ALPHA = 255;
34 | private final static float MAX_ANGLE = 360.0F;
35 | private final static float MIN_RADIUS = 0.1F;
36 | private final static float MIN_ANGLE = 0.0F;
37 | // Shadow paint
38 | private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG) {
39 | {
40 | setDither(true);
41 | setFilterBitmap(true);
42 | }
43 | };
44 | // Shadow bitmap and canvas
45 | private Bitmap mBitmap;
46 | private final Canvas mCanvas = new Canvas();
47 | // View bounds
48 | private final Rect mBounds = new Rect();
49 | // Check whether need to redraw shadow
50 | private boolean mInvalidateShadow = true;
51 |
52 | // Detect if shadow is visible
53 | private boolean mIsShadowed;
54 |
55 | // Shadow variables
56 | private int mShadowColor;
57 | private int mShadowAlpha;
58 | private float mShadowRadius;
59 | private float mShadowDistance;
60 | private float mShadowAngle;
61 | private float mOffsetDy;
62 | private float mOffsetDx;
63 | private float mZoomDy;
64 | private boolean mDrawCenter = true;
65 | ShadowLayout mParent;
66 |
67 | public AutoModel(ShadowLayout parent,TypedArray typedArray) {
68 | mParent = parent;
69 | mParent.setWillNotDraw(false);
70 | mParent.setLayerType(View.LAYER_TYPE_HARDWARE, mPaint);
71 |
72 | setIsShadowed(typedArray.getBoolean(R.styleable.ShadowLayout_sl_shadowed, true));
73 | setShadowRadius(
74 | typedArray.getDimension(
75 | R.styleable.ShadowLayout_sl_shadow_radius, DEFAULT_SHADOW_RADIUS
76 | )
77 | );
78 | mOffsetDx=typedArray.getDimensionPixelSize(
79 | R.styleable.ShadowLayout_sl_shadow_offsetdx, Integer.MAX_VALUE
80 | );
81 | mOffsetDy=typedArray.getDimensionPixelSize(
82 | R.styleable.ShadowLayout_sl_shadow_offsetdy, Integer.MAX_VALUE
83 | );
84 | mShadowDistance= typedArray.getDimension(
85 | R.styleable.ShadowLayout_sl_shadow_distance, 0
86 | );
87 | setShadowAngle(
88 | typedArray.getInteger(
89 | R.styleable.ShadowLayout_sl_shadow_angle, (int) DEFAULT_SHADOW_ANGLE
90 | )
91 | );
92 | setShadowColor(
93 | typedArray.getColor(
94 | R.styleable.ShadowLayout_sl_shadow_color, DEFAULT_SHADOW_COLOR
95 | )
96 | );
97 |
98 | mZoomDy = typedArray.getDimensionPixelSize( R.styleable.ShadowLayout_sl_shadow_zoomdy, 0);
99 |
100 | // Set padding for shadow bitmap
101 | final int padding = (int) (mShadowRadius+Math.max(mOffsetDx,mOffsetDy));
102 | mParent.setPadding(padding, padding, padding, padding);
103 | }
104 |
105 | @Override
106 | public void onDetachedFromWindow() {
107 | // Clear shadow bitmap
108 | if (mBitmap != null) {
109 | mBitmap.recycle();
110 | mBitmap = null;
111 | }
112 | }
113 |
114 | public boolean isShadowed() {
115 | return mIsShadowed;
116 | }
117 |
118 | public void setIsShadowed(final boolean isShadowed) {
119 | mIsShadowed = isShadowed;
120 | if(mParent.isLayoutRequested() &&mParent.getParent()!=null){
121 | mParent.postInvalidate();
122 | }
123 | }
124 |
125 | public float getShadowDistance() {
126 | return mShadowDistance;
127 | }
128 |
129 | public void setShadowDistance(final float shadowDistance) {
130 | mShadowDistance = shadowDistance;
131 | resetShadow();
132 | }
133 |
134 | public float getShadowAngle() {
135 | return mShadowAngle;
136 | }
137 |
138 | public void setShadowAngle(@FloatRange(from = MIN_ANGLE, to = MAX_ANGLE) final float shadowAngle) {
139 | mShadowAngle = Math.max(MIN_ANGLE, Math.min(shadowAngle, MAX_ANGLE));
140 | resetShadow();
141 | }
142 |
143 | public float getShadowRadius() {
144 | return mShadowRadius;
145 | }
146 |
147 | public void setShadowRadius(final float shadowRadius) {
148 | mShadowRadius = Math.max(MIN_RADIUS, shadowRadius);
149 |
150 | if ( mParent.isInEditMode()) return;
151 | // Set blur filter to paint
152 | mPaint.setMaskFilter(new BlurMaskFilter(mShadowRadius, BlurMaskFilter.Blur.NORMAL));
153 | invalidateShadow();
154 | }
155 |
156 | public void setRadius(final float shadowRadius) {
157 | mShadowRadius = Math.max(MIN_RADIUS, shadowRadius);
158 | if ( mParent.isInEditMode()) return;
159 | // Set blur filter to paint
160 | mPaint.setMaskFilter(new BlurMaskFilter(mShadowRadius, BlurMaskFilter.Blur.NORMAL));
161 | mInvalidateShadow = true;
162 | mParent.postInvalidate();
163 | }
164 |
165 | public int getShadowColor() {
166 | return mShadowColor;
167 | }
168 |
169 | public void setShadowColor(final int shadowColor) {
170 | mShadowColor = shadowColor;
171 | mShadowAlpha = Color.alpha(shadowColor);
172 | invalidateShadow();
173 | }
174 | public void invalidateShadow(){
175 | mInvalidateShadow = true;
176 | mParent.postInvalidate();
177 | }
178 |
179 | public float getOffsetDx() {
180 | return mOffsetDx;
181 | }
182 |
183 | public float getOffsetDy() {
184 | return mOffsetDy;
185 | }
186 |
187 | // Reset shadow layer
188 | private void resetShadow() {
189 | // Detect shadow axis offset
190 | if(mShadowDistance >0){
191 | mOffsetDx = (float) ((mShadowDistance) * Math.cos(mShadowAngle / 180.0F * Math.PI));
192 | mOffsetDy = (float) ((mShadowDistance) * Math.sin(mShadowAngle / 180.0F * Math.PI));
193 | }
194 |
195 | mInvalidateShadow = true;
196 | mParent.postInvalidate();
197 | }
198 |
199 | private int adjustShadowAlpha(final boolean adjust) {
200 | return Color.argb(
201 | adjust ? MAX_ALPHA : mShadowAlpha,
202 | Color.red(mShadowColor),
203 | Color.green(mShadowColor),
204 | Color.blue(mShadowColor)
205 | );
206 | }
207 |
208 | public void onLayout(boolean changed, int left, int top, int right, int bottom) {
209 |
210 | mBounds.set(
211 | 0, 0, mParent.getMeasuredWidth(), mParent.getMeasuredHeight()
212 | );
213 | }
214 |
215 | @Override
216 | public void onAttachToWindow() {
217 |
218 | }
219 |
220 |
221 | @Override
222 | public void onDraw(final Canvas canvas) {
223 | // If is not shadowed, skip
224 | if (mIsShadowed) {
225 | // If need to redraw shadow
226 | if (mInvalidateShadow) {
227 | // If bounds is zero
228 | if (mBounds.width() != 0 && mBounds.height() != 0) {
229 | // Reset bitmap to bounds
230 | mBitmap = Bitmap.createBitmap(
231 | mBounds.width(), mBounds.height(), Bitmap.Config.ARGB_8888
232 | );
233 | // Canvas reset
234 | mCanvas.setBitmap(mBitmap);
235 |
236 | // We just redraw
237 | mInvalidateShadow = false;
238 | // Main feature of this lib. We create the local copy of all content, so now
239 | // we can draw bitmap as a bottom layer of natural canvas.
240 | // We draw shadow like blur effect on bitmap, cause of setShadowLayer() method of
241 | // paint does`t draw shadow, it draw another copy of bitmap
242 | mParent.superdispatchDraw(mCanvas);
243 |
244 | // Get the alpha bounds of bitmap
245 | Bitmap extractedAlpha = mBitmap.extractAlpha();
246 | // Clear past content content to draw shadow
247 | mCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
248 |
249 | // Draw extracted alpha bounds of our local canvas
250 | mPaint.setColor(adjustShadowAlpha(false));
251 | if(mZoomDy !=0f && mZoomDy != Integer.MAX_VALUE){
252 | extractedAlpha = getScaleBitmap(extractedAlpha,mZoomDy);
253 | }
254 | if(mDrawCenter){
255 | final int w= extractedAlpha.getWidth();
256 | final int h = extractedAlpha.getHeight();
257 | float l = (mCanvas.getWidth()-w)/2+(mOffsetDx==Integer.MAX_VALUE?0:mOffsetDx);
258 | float t = (mCanvas.getHeight()-h)/2 +(mOffsetDy==Integer.MAX_VALUE?0:mOffsetDy);
259 | mCanvas.drawBitmap(extractedAlpha, l, t, mPaint);
260 | }else{
261 | mCanvas.drawBitmap(extractedAlpha, mOffsetDx==Integer.MAX_VALUE?0:mOffsetDx, mOffsetDy==Integer.MAX_VALUE?0:mOffsetDy, mPaint);
262 |
263 | }
264 |
265 | // Recycle and clear extracted alpha
266 | extractedAlpha.recycle();
267 | } else {
268 | // Create placeholder bitmap when size is zero and wait until new size coming up
269 | mBitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.RGB_565);
270 | }
271 | }
272 |
273 | // Reset alpha to draw child with full alpha
274 | mPaint.setColor(adjustShadowAlpha(true));
275 | // Draw shadow bitmap
276 | if (mCanvas != null && mBitmap != null && !mBitmap.isRecycled())
277 | canvas.drawBitmap(mBitmap, 0.0F, 0.0F, mPaint);
278 | }
279 |
280 | // Draw child`s
281 | mParent.superdispatchDraw(mCanvas);
282 | }
283 |
284 | @Override
285 | public void onDrawOver(Canvas canvas) {
286 |
287 | }
288 |
289 | @Override
290 | public boolean onClipCanvas(Canvas canvas,View child) {
291 | if(mClipPath !=null && !mClipPath.isEmpty()){
292 | canvas.clipPath(mClipPath);
293 | }
294 | return false;
295 | }
296 | Path mClipPath;
297 | public void setClipPath(Path clipPath){
298 | mClipPath = clipPath;
299 | invalidateShadow();
300 | }
301 |
302 |
303 | public void setZoomDy(float dy){
304 | mInvalidateShadow = true;
305 | mZoomDy = dy;
306 | mParent.postInvalidate();
307 | }
308 | public void setOffsetDx(float dx){
309 | mInvalidateShadow = true;
310 | mOffsetDx = dx;
311 | mParent.postInvalidate();
312 | }
313 | public void setOffsetDy(float dy){
314 | mInvalidateShadow = true;
315 | mOffsetDy = dy;
316 | mParent.postInvalidate();
317 | }
318 |
319 | public Bitmap getScaleBitmap(Bitmap mBitmap,float dy) {
320 | int width = mBitmap.getWidth();
321 | int height = mBitmap.getHeight();
322 | float h = height+dy;
323 | if(h<=1){
324 | h=1;
325 | }
326 | float scale = h/height;
327 | Matrix matrix = new Matrix();
328 | matrix.postScale(scale, scale);
329 | Bitmap mScaleBitmap = Bitmap.createBitmap(mBitmap, 0, 0, width, height, matrix, true);
330 | return mScaleBitmap;
331 | }
332 |
333 | Runnable mRunnable= new Runnable() {
334 | @Override
335 | public void run() {
336 | mInvalidateShadow = true;
337 | mParent.postInvalidate();
338 | }
339 | };
340 | public void setDrawCenter(boolean drawCenter){
341 | this.mDrawCenter = drawCenter;
342 | mInvalidateShadow = true;
343 | mParent.postInvalidate();
344 | }
345 |
346 | }
347 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {2016} {Basil Miller}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
203 | MIT License (MIT)
204 |
205 | Copyright (c) 2016 Basil Miller
206 |
207 | Permission is hereby granted, free of charge, to any person obtaining a copy
208 | of this software and associated documentation files (the "Software"), to deal
209 | in the Software without restriction, including without limitation the rights
210 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
211 | copies of the Software, and to permit persons to whom the Software is
212 | furnished to do so, subject to the following conditions:
213 |
214 | The above copyright notice and this permission notice shall be included in
215 | all copies or substantial portions of the Software.
216 |
217 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
218 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
219 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
220 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
221 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
222 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
223 | THE SOFTWARE.
--------------------------------------------------------------------------------
/强大的剪裁+阴影效果布局ShadowLayout.md:
--------------------------------------------------------------------------------
1 |
2 | >在开发过程中经常会遇到有阴影效果的需求,实现方案有Sdk suppot的CardView,仅支持sdk>=21的android:elevation和outline,.9图设置为背景。大多数是有局限性的,如不能设置阴影颜色,不能设置阴影角度,动态阴影深度,也不能实现特殊形状的阴影,不能实现剪裁为特定形状的阴影。在开发中如果遇到原始图片是正方形,想显示为圆形并出现圆形阴影,或者图片是个正六边形,实现正六边形阴影。
3 | 原始布局是方形,实现剪裁为一边为圆弧性并实现阴影效果。现在给大家推荐一个强大阴影库,以上都能实现。https://github.com/ytjojo/ShadowLayout。功能介绍如下:
4 | ### 控件功能简介
5 | 1. 可以在xml或者代码设置阴影方向,阴影深度,阴影颜色。
6 | 2. 不管原始是什么形状都可以剪裁为圆角矩形或者圆形并带阴影。(当然你可以不设置阴影,当做一个圆形或者圆角矩形控件使用)。
7 | 3. 如果原始图片不是规则图形你可以设置自适应模式,在原始图片边框处出现阴影。
8 | 4. 可以给文字设置阴影效果。
9 | 5. 设置一个封闭path,剪裁出path并在在path边框外部出现阴影。
10 | ### 如何引入
11 | ```
12 | apply plugin: 'com.android.application'
13 |
14 | repositories {
15 | jcenter()
16 | mavenCentral()
17 | }
18 |
19 | android {
20 | // something code...
21 | }
22 |
23 | dependencies {
24 | compile 'com.github.ytjojo:ShadowLayout:1.0.1'
25 | }
26 | ```
27 |
28 | ### 效果图与设置代码
29 | 如图
30 |
31 | 
32 |
33 | 实现代码
34 |
35 | ```xml
36 |
45 |
46 |
54 |
55 |
56 | ```
57 |
58 | 
59 |
60 | 应用logo实现代码
61 |
62 | ```xml
63 |
72 |
77 |
83 |
89 |
95 |
101 |
107 |
108 |
109 |
110 |
111 | ```
112 |
113 | 这个原始图片是长方形,效果图是剪裁为下方是弧形,弧形实现原理是三阶贝尔曲线。
114 |
115 | 
116 |
117 | 实现代码
118 |
119 | ```xml
120 |
131 |
136 |
137 | ```
138 |
139 | 下图原始狗狗头像是方形的,实现效果图圆形并有阴影效果
140 | 两个按钮控件效果是圆角带阴影的,由于截图的原因阴影颜色不是很深
141 |
142 | 
143 |
144 | 狗狗头像设置的代码
145 | ```xml
146 |
155 |
156 |
161 |
162 | ```
163 |
164 | 两个圆角应用按钮效果实现代码
165 |
166 | ```xml
167 |
168 |
179 |
180 |
187 |
188 |
189 |
199 |
200 |
207 |
208 | ```
209 |
210 | ### 阴影原理简介
211 | 绘制阴影的原理其实很简单,画笔对象设置BlurMaskFilter,
212 | `mPaint.setMaskFilter(new BlurMaskFilter(mShadowRadius, BlurMaskFilter.Blur.NORMAL));`
213 | 先看下BlurMaskFilter构造函数
214 | >BlurMaskFilter(float radius, BlurMaskFilter.Blur style)
215 |
216 | radius的值为阴影扩散的距离,BlurMaskFilter.Blur是个枚举值,有四个,SOLID,NORMAL,OUTER,INNER。
217 | 我们写个BlurMaskFilterView来看看四个值分别是什么效果
218 | 代码很简单绘制一个圆形之前设置BlurMaskFilter
219 | ```java
220 | mPaint.setMaskFilter(new BlurMaskFilter(mBlurRadus,style));
221 | canvas.drawCircle(0,0,mCircleRadus,mPaint);
222 | ```
223 | 但是运行起来之后却没有阴影效果,纳尼?
224 | 突然想起来,这个方法是不支持硬件加速的,在view的构造方法加上禁用硬件加速,代码如下
225 | ```java
226 | setLayerType(LAYER_TYPE_SOFTWARE, null);
227 | ```
228 | 运行效果如图
229 |
230 | 
231 |
232 | Inner 阴影在圆形的内部,有种淡淡的浮雕感。
233 | NORMAL是对整个区域产出模糊
234 | SOLD是对透明区域边缘产出模糊,区域内不会模糊
235 | OUTER是对整个边缘产生模糊,同时区域内变为透明
236 | 图中方形用的SOLD模式
237 | 本项目中用的是NORMAL模式,阴影效果最好
238 |
239 | ### 图片阴影效果
240 | 库中的绘制图片阴影效果在AutoModel.java 的onDraw方法中,源码大致流程是先初始化布局同等大小的
241 | Canvas和bitmap对象,将创建的canvas对象作为入参,调用view的dispatchDraw方法将布局的图像保存在自己创建的画布,再从画布中获得bitmap对象,调用mBitmap.extractAlpha()方法获得一个Alpha通道图
242 | 用设置BlurMaskFilter的画笔对象将alpha通道图绘制到系统的canvas对象上,作为底图,然后调用ShadowLayout的super.dispatchDraw绘制原本要绘制的内容。总结来说就是多画了有边界模糊效果的底图,在绘制目标图片,形成叠加效果。
243 | 代码如下
244 |
245 | ```java
246 | @Override
247 | public void onDraw(final Canvas canvas) {
248 | // If is not shadowed, skip
249 | if (mIsShadowed) {
250 | // If need to redraw shadow
251 | if (mInvalidateShadow) {
252 | // If bounds is zero
253 | if (mBounds.width() != 0 && mBounds.height() != 0) {
254 | // Reset bitmap to bounds
255 | //创建一个和布局一样大小的Bitmap
256 | mBitmap = Bitmap.createBitmap(
257 | mBounds.width(), mBounds.height(), Bitmap.Config.ARGB_8888
258 | );
259 | // Canvas reset
260 | //把bitma设置进自己创建的画布上,注意哦,这是自己创建的画布
261 | //不是系统在dispatchDraw传递给我们的
262 | mCanvas.setBitmap(mBitmap);
263 |
264 | // We just redraw
265 | mInvalidateShadow = false;
266 | // Main feature of this lib. We create the local copy of all content, so now
267 | // we can draw bitmap as a bottom layer of natural canvas.
268 | // We draw shadow like blur effect on bitmap, cause of setShadowLayer() method of
269 | // paint does`t draw shadow, it draw another copy of bitmap
270 | //这一步很关键,获得原始图片,子布局需要显示的元素都在bitmap里了
271 | mParent.superdispatchDraw(mCanvas);
272 |
273 | // Get the alpha bounds of bitmap
274 | //获得alpha通道的bitmap,不能用原始图片哦
275 | Bitmap extractedAlpha = mBitmap.extractAlpha();
276 | // Clear past content content to draw shadow
277 | mCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
278 |
279 | // Draw extracted alpha bounds of our local canvas
280 | mPaint.setColor(adjustShadowAlpha(false));
281 | if(mZoomDy !=0f && mZoomDy != Integer.MAX_VALUE){
282 | extractedAlpha = getScaleBitmap(extractedAlpha,mZoomDy);
283 | }
284 | if(mDrawCenter){
285 | final int w= extractedAlpha.getWidth();
286 | final int h = extractedAlpha.getHeight();
287 | float l = (mCanvas.getWidth()-w)/2+(mOffsetDx==Integer.MAX_VALUE?0:mOffsetDx);
288 | float t = (mCanvas.getHeight()-h)/2 +(mOffsetDy==Integer.MAX_VALUE?0:mOffsetDy);
289 | mCanvas.drawBitmap(extractedAlpha, l, t, mPaint);
290 | }else{
291 | mCanvas.drawBitmap(extractedAlpha, mOffsetDx==Integer.MAX_VALUE?0:mOffsetDx, mOffsetDy==Integer.MAX_VALUE?0:mOffsetDy, mPaint);
292 |
293 | }
294 |
295 | // Recycle and clear extracted alpha
296 | extractedAlpha.recycle();
297 | } else {
298 | // Create placeholder bitmap when size is zero and wait until new size coming up
299 | mBitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.RGB_565);
300 | }
301 | }
302 |
303 | // Reset alpha to draw child with full alpha
304 | mPaint.setColor(adjustShadowAlpha(true));
305 | // Draw shadow bitmap
306 | //绘制带阴影的底图
307 | if (mCanvas != null && mBitmap != null && !mBitmap.isRecycled())
308 | canvas.drawBitmap(mBitmap, 0.0F, 0.0F, mPaint);
309 | }
310 |
311 | // Draw child`s
312 | //绘制原始的元素,
313 | mParent.superdispatchDraw(mCanvas);
314 | }
315 |
316 | ```
317 |
318 | ### 绘制区域的剪切
319 | 关于canvas剪裁推荐三篇篇文章
320 | http://blog.csdn.net/richiezhu/article/details/52956163
321 | http://blog.csdn.net/oney139/article/details/8177599
322 | http://blog.csdn.net/cquwentao/article/details/51365099
323 | canvas剪裁最重要的是Region.Op这个参数,这个枚举有6个值。 DIFFERENCE,INTERSECT,UNION,XOR,REVERSE_DIFFERENCE, REPLACE,先写个demo看看每个值的效果吧
324 | ClipView.java
325 | ```java
326 | canvas.save();
327 | canvas.translate(x,y);
328 | mPaint.setColor(Color.YELLOW);
329 | //代码先绘制了黄色矩形
330 | canvas.drawRect(-100,100,200,300,mPaint);
331 | //设置了一个圆形封闭path
332 | mPath.addCircle(0,0,80, Path.Direction.CCW);
333 | //画布根据path进行剪裁
334 | canvas.clipPath(mPath, Region.Op.INTERSECT);
335 |
336 | mPaint.setColor(Color.RED);
337 | //绘制一个红色正方形
338 | canvas.drawRect(-100,0,100,200,mPaint);
339 | canvas.restore();
340 | ```
341 |
342 | 只贴了INTERSECT类型的代码其他类型代码大同小异,这里就不贴了.代码中,先绘制黄色矩形,剪裁圆形,绘制红色方形
343 | 
344 |
345 | 通过效果图得知,剪裁之前绘制的图像不受剪裁影响
346 | >DIFFERENCE(0), //取补集
347 | INTERSECT(1), // 交集
348 | UNION(2), //并集
349 | XOR(3), //异并集
350 | REVERSE_DIFFERENCE(4), //反转补集
351 | REPLACE(5); //后者区域替代前者
352 |
353 | ### 剪裁子View
354 |
355 | 重写`1drawChild(Canvas canvas, View child, long drawingTime) `
356 | ```java
357 | @Override
358 | protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
359 | try {
360 | canvas.save();
361 | return mShadowDeltegate.onClipCanvas(canvas,child)&super.drawChild(canvas, child, drawingTime);
362 | }finally {
363 | canvas.restore();
364 | }
365 | }
366 | ```
367 | PathModel中onClipCanvas代码如下
368 | 直接设置剪裁path,最终绘制的子View就是想要形状
369 | ```java
370 | @Override
371 | public boolean onClipCanvas(Canvas canvas, View child) {
372 |
373 | canvas.clipPath(mClipPath);
374 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
375 | child.invalidateOutline();
376 | }
377 | return false;
378 | }
379 | ```
380 | ### 根据path绘制阴影
381 |
382 | ```java
383 |
384 | @Override
385 | public void onDrawOver(Canvas canvas) {
386 | canvas.save();
387 | // if(Build.VERSION.SDK_INT>=19){
388 | // canvas.clipPath(mPath);
389 | // }else{
390 | // canvas.clipPath(mPath, Region.Op.REPLACE);
391 | // canvas.clipPath(mClipPath, Region.Op.DIFFERENCE);
392 | // }
393 | canvas.clipPath(mPath, Region.Op.REPLACE);
394 | canvas.clipPath(mClipPath, Region.Op.DIFFERENCE);
395 | mPaint.setColor(Color.BLACK);
396 | mShadowpath.set(mClipPath);
397 | mShadowpath.offset(mOffsetDx, mOffsetDy);
398 | canvas.drawPath(mShadowpath, mPaint);
399 | canvas.restore();
400 |
401 | }
402 | ```
403 | mPath是ShadowLayout的整个区域。
404 | mClipPath 有两个来源一个是根据xml中用户配置的控制点生成的path。
405 | 另外一种用户调用public void setPath(Path path)来设置的path。
406 | mShadowpath是mClipPath的copy,再加上一定的x轴y轴的偏移。
407 | ```java
408 | canvas.clipPath(mPath, Region.Op.REPLACE);
409 | canvas.clipPath(mClipPath, Region.Op.DIFFERENCE);
410 | ```
411 | 这两句的意思是剪裁出当前布局除剪裁区域以外的所有区域,相当于剪裁区域的取反,但不超出当前布局。
412 | `canvas.drawPath(mShadowpath, mPaint);`这句功能是在剪裁区域外绘制阴影,最终效果是剪裁区域+阴影区域,效果上面已给出。
413 | ### 完结
414 | 大体上原理都已经说明,用到技术也不是很深,简单总结下,如有纰漏欢迎指出,如果喜欢本库,欢迎star下,鼓励下作者。
415 |
416 |
417 |
418 |
419 |
--------------------------------------------------------------------------------
/library/src/main/java/com/ytjojo/shadowlayout/shadowdelegate/ExactlyModel.java:
--------------------------------------------------------------------------------
1 | package com.ytjojo.shadowlayout.shadowdelegate;
2 |
3 | import android.animation.PropertyValuesHolder;
4 | import android.animation.ValueAnimator;
5 | import android.content.Context;
6 | import android.content.res.TypedArray;
7 | import android.graphics.Canvas;
8 | import android.graphics.Rect;
9 | import android.os.Build;
10 | import android.support.annotation.ColorInt;
11 | import android.view.View;
12 | import android.view.animation.LinearInterpolator;
13 |
14 | import com.ytjojo.shadowlayout.R;
15 | import com.ytjojo.shadowlayout.ShadowLayout;
16 | import com.ytjojo.shadowlayout.ZDepth;
17 | import com.ytjojo.shadowlayout.shadow.Shadow;
18 | import com.ytjojo.shadowlayout.shadow.ShadowOval;
19 | import com.ytjojo.shadowlayout.shadow.ShadowRect;
20 | import com.ytjojo.shadowlayout.utils.ColorUtil;
21 |
22 |
23 | public class ExactlyModel implements ShadowDelegate {
24 |
25 | protected static final String TAG = "ShadowView";
26 |
27 |
28 | protected static final int DEFAULT_ATTR_SHAPE = 0;
29 | protected static final int DEFAULT_ATTR_ZDEPTH = 1;
30 | protected static final int DEFAULT_ATTR_ZDEPTH_PADDING = 5;
31 | protected static final int DEFAULT_ATTR_ZDEPTH_ANIM_DURATION = 150;
32 | protected static final boolean DEFAULT_ATTR_ZDEPTH_DO_ANIMATION = true;
33 | private final static int DEFAULT_SHADOW_COLOR = 0xFF222222;
34 |
35 | protected static final int SHAPE_RECT = 0;
36 | protected static final int SHAPE_OVAL = 1;
37 |
38 | protected static final String ANIM_PROPERTY_ALPHA_TOP_SHADOW = "alphaTopShadow";
39 | protected static final String ANIM_PROPERTY_ALPHA_BOTTOM_SHADOW = "alphaBottomShadow";
40 | protected static final String ANIM_PROPERTY_OFFSET_TOP_SHADOW = "offsetTopShadow";
41 | protected static final String ANIM_PROPERTY_OFFSET_BOTTOM_SHADOW = "offsetBottomShadow";
42 | protected static final String ANIM_PROPERTY_BLUR_TOP_SHADOW = "blurTopShadow";
43 | protected static final String ANIM_PROPERTY_BLUR_BOTTOM_SHADOW = "blurBottomShadow";
44 |
45 | protected Shadow mShadow;
46 | protected ZDepth mZDepthParam;
47 | protected int mZDepthPaddingLeft;
48 | protected int mZDepthPaddingTop;
49 | protected int mZDepthPaddingRight;
50 | protected int mZDepthPaddingBottom;
51 | protected long mZDepthAnimDuration;
52 | protected boolean mZDepthDoAnimation;
53 | private ShadowLayout mParent;
54 | boolean mClipCanvas;
55 | private int mShadowColor = DEFAULT_SHADOW_COLOR;
56 |
57 | public ExactlyModel(ShadowLayout parent, TypedArray typedArray) {
58 | mParent = parent;
59 | mParent.setClipToPadding(false);
60 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
61 | mParent.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
62 | }
63 | init(typedArray);
64 | }
65 |
66 | protected void init(TypedArray typedArray) {
67 |
68 | int attrShape = typedArray.getInt(R.styleable.ShadowLayout_z_depth_shape, DEFAULT_ATTR_SHAPE);
69 | int attrZDepth = typedArray.getInt(R.styleable.ShadowLayout_z_depth, DEFAULT_ATTR_ZDEPTH);
70 | int attrZDepthAnimDuration = typedArray.getInt(R.styleable.ShadowLayout_z_depth_animDuration, DEFAULT_ATTR_ZDEPTH_ANIM_DURATION);
71 | boolean attrZDepthDoAnimation = typedArray.getBoolean(R.styleable.ShadowLayout_z_depth_doAnim, DEFAULT_ATTR_ZDEPTH_DO_ANIMATION);
72 |
73 | int attrZDepthPadding = typedArray.getInt(R.styleable.ShadowLayout_z_depth_padding, -1);
74 | int attrZDepthPaddingLeft = typedArray.getInt(R.styleable.ShadowLayout_z_depth_paddingLeft, -1);
75 | int attrZDepthPaddingTop = typedArray.getInt(R.styleable.ShadowLayout_z_depth_paddingTop, -1);
76 | int attrZDepthPaddingRight = typedArray.getInt(R.styleable.ShadowLayout_z_depth_paddingRight, -1);
77 | int attrZDepthPaddingBottom = typedArray.getInt(R.styleable.ShadowLayout_z_depth_paddingBottom, -1);
78 | mClipCanvas = typedArray.getBoolean(R.styleable.ShadowLayout_z_depth_clipcanvas, false);
79 | mShadowColor = typedArray.getColor(R.styleable.ShadowLayout_sl_shadow_color, DEFAULT_SHADOW_COLOR);
80 | if (attrZDepthPadding > -1) {
81 | attrZDepthPaddingLeft = attrZDepthPadding;
82 | attrZDepthPaddingTop = attrZDepthPadding;
83 | attrZDepthPaddingRight = attrZDepthPadding;
84 | attrZDepthPaddingBottom = attrZDepthPadding;
85 | } else {
86 | attrZDepthPaddingLeft = attrZDepthPaddingLeft > -1 ? attrZDepthPaddingLeft : DEFAULT_ATTR_ZDEPTH_PADDING;
87 | attrZDepthPaddingTop = attrZDepthPaddingTop > -1 ? attrZDepthPaddingTop : DEFAULT_ATTR_ZDEPTH_PADDING;
88 | attrZDepthPaddingRight = attrZDepthPaddingRight > -1 ? attrZDepthPaddingRight : DEFAULT_ATTR_ZDEPTH_PADDING;
89 | attrZDepthPaddingBottom = attrZDepthPaddingBottom > -1 ? attrZDepthPaddingBottom : DEFAULT_ATTR_ZDEPTH_PADDING;
90 | }
91 | int roundRectRadius = typedArray.getDimensionPixelOffset(R.styleable.ShadowLayout_sl_shadow_rectroundradius, 0);
92 | this.setShape(attrShape);
93 | if (attrShape == SHAPE_RECT) {
94 | ((ShadowRect) mShadow).setRoundRectRadius(roundRectRadius);
95 | }
96 | this.setZDepth(attrZDepth);
97 | this.setZDepthPaddingLeft(attrZDepthPaddingLeft);
98 | this.setZDepthPaddingTop(attrZDepthPaddingTop);
99 | this.setZDepthPaddingRight(attrZDepthPaddingRight);
100 | this.setZDepthPaddingBottom(attrZDepthPaddingBottom);
101 | this.setZDepthAnimDuration(attrZDepthAnimDuration);
102 | this.setZDepthDoAnimation(attrZDepthDoAnimation);
103 | }
104 |
105 | public Context getContext() {
106 | return mParent.getContext();
107 | }
108 |
109 | protected void setZDepthDoAnimation(boolean doAnimation) {
110 | mZDepthDoAnimation = doAnimation;
111 | }
112 |
113 | protected void setZDepthAnimDuration(long duration) {
114 | mZDepthAnimDuration = duration;
115 | }
116 |
117 | protected void setZDepthPaddingLeft(int zDepthPaddingLeftValue) {
118 | ZDepth zDepth = getZDepthWithAttributeValue(zDepthPaddingLeftValue);
119 | zDepth.initZDepth(getContext());
120 | mZDepthPaddingLeft = measureZDepthPadding(zDepth);
121 | }
122 |
123 | protected void setZDepthPaddingTop(int zDepthPaddingTopValue) {
124 | ZDepth zDepth = getZDepthWithAttributeValue(zDepthPaddingTopValue);
125 | zDepth.initZDepth(getContext());
126 | mZDepthPaddingTop = measureZDepthPadding(zDepth);
127 | }
128 |
129 | protected void setZDepthPaddingRight(int zDepthPaddingRightValue) {
130 | ZDepth zDepth = getZDepthWithAttributeValue(zDepthPaddingRightValue);
131 | zDepth.initZDepth(getContext());
132 | mZDepthPaddingRight = measureZDepthPadding(zDepth);
133 | }
134 |
135 | protected void setZDepthPaddingBottom(int zDepthPaddingBottomValue) {
136 | ZDepth zDepth = getZDepthWithAttributeValue(zDepthPaddingBottomValue);
137 | zDepth.initZDepth(getContext());
138 | mZDepthPaddingBottom = measureZDepthPadding(zDepth);
139 | }
140 |
141 | protected int measureZDepthPadding(ZDepth zDepth) {
142 | float maxAboveBlurRadius = zDepth.mBlurTopShadowPx;
143 | float maxAboveOffset = zDepth.mOffsetYTopShadowPx;
144 | float maxBelowBlurRadius = zDepth.mBlurBottomShadowPx;
145 | float maxBelowOffset = zDepth.mOffsetYBottomShadowPx;
146 |
147 | float maxAboveSize = maxAboveBlurRadius + maxAboveOffset;
148 | float maxBelowSize = maxBelowBlurRadius + maxBelowOffset;
149 |
150 | return (int) Math.max(maxAboveSize, maxBelowSize);
151 | }
152 |
153 | protected int getZDepthPaddingLeft() {
154 | return mZDepthPaddingLeft;
155 | }
156 |
157 | protected int getZDepthPaddingTop() {
158 | return mZDepthPaddingTop;
159 | }
160 |
161 | protected int getZDepthPaddingRight() {
162 | return mZDepthPaddingRight;
163 | }
164 |
165 | protected int getZDepthPaddingBottom() {
166 | return mZDepthPaddingBottom;
167 | }
168 |
169 | protected void setShape(int shape) {
170 | switch (shape) {
171 | case SHAPE_RECT:
172 | mShadow = new ShadowRect();
173 | break;
174 |
175 | case SHAPE_OVAL:
176 | mShadow = new ShadowOval();
177 | break;
178 |
179 | default:
180 | throw new IllegalArgumentException("unknown shape value.");
181 | }
182 | }
183 |
184 | protected void setZDepth(int zDepthValue) {
185 | ZDepth zDepth = getZDepthWithAttributeValue(zDepthValue);
186 | setZDepth(zDepth);
187 | }
188 |
189 | protected void setZDepth(ZDepth zDepth) {
190 | mZDepthParam = zDepth;
191 | mZDepthParam.initZDepth(getContext());
192 | }
193 |
194 | private ZDepth getZDepthWithAttributeValue(int zDepthValue) {
195 | switch (zDepthValue) {
196 | case 0:
197 | return ZDepth.Depth0;
198 | case 1:
199 | return ZDepth.Depth1;
200 | case 2:
201 | return ZDepth.Depth2;
202 | case 3:
203 | return ZDepth.Depth3;
204 | case 4:
205 | return ZDepth.Depth4;
206 | case 5:
207 | return ZDepth.Depth5;
208 | default:
209 | throw new IllegalArgumentException("unknown zDepth value.");
210 | }
211 | }
212 |
213 | Rect mShadowDrawingRect = new Rect();
214 |
215 | public void onLayout(boolean changed, int left, int top, int right, int bottom) {
216 | // int parentWidth = (right - left);
217 | // int parentHeight = (bottom - top);
218 | // mShadowDrawingRect.set(mZDepthPaddingLeft,
219 | // mZDepthPaddingTop,
220 | // parentWidth - mZDepthPaddingRight,
221 | // parentHeight - mZDepthPaddingBottom);
222 |
223 | mShadowDrawingRect.setEmpty();
224 | if(mParent.getChildCount()>0){
225 | int childCount = mParent.getChildCount();
226 | for(int i=0;i= Build.VERSION_CODES.LOLLIPOP) {
270 | child.invalidateOutline();
271 | }
272 | return result;
273 | }
274 | return false;
275 |
276 | }
277 |
278 | @Override
279 | public void invalidateShadow() {
280 | mParent.postInvalidate();
281 | }
282 |
283 | @Override
284 | public void setShadowColor(@ColorInt int color) {
285 | this.mShadowColor = color;
286 | setParameterToShadow();
287 | invalidateShadow();
288 | }
289 |
290 | private int getWidth() {
291 | return mParent.getMeasuredWidth();
292 | }
293 |
294 | private int getHeight() {
295 | return mParent.getMeasuredHeight();
296 | }
297 |
298 | public int getWidthExceptShadow() {
299 | return getWidth() - mParent.getPaddingLeft() - mParent.getPaddingRight();
300 | }
301 |
302 | public int getHeightExceptShadow() {
303 | return getHeight() - mParent.getPaddingTop() - mParent.getPaddingBottom();
304 | }
305 |
306 | private void setParameterToShadow() {
307 |
308 | int colorTop = ColorUtil.adjustAlpha(mZDepthParam.mAlphaTopShadow, mShadowColor);
309 | int colorBottom = ColorUtil.adjustAlpha(mZDepthParam.mAlphaBottomShadow,mShadowColor);
310 | mShadow.setParameter(colorTop, colorBottom, mZDepthParam.mOffsetYTopShadowPx, mZDepthParam.mOffsetYBottomShadowPx, mZDepthParam.mBlurTopShadowPx, mZDepthParam.mBlurBottomShadowPx, mShadowDrawingRect);
311 | }
312 |
313 | public void changeZDepth(ZDepth zDepth) {
314 | zDepth.initZDepth(getContext());
315 | if (!mZDepthDoAnimation) {
316 | mZDepthParam = zDepth;
317 | setParameterToShadow();
318 | mParent.invalidate();
319 | return;
320 | }
321 |
322 | PropertyValuesHolder alphaTopShadowHolder = PropertyValuesHolder.ofInt(ANIM_PROPERTY_ALPHA_TOP_SHADOW,
323 | mZDepthParam.mAlphaTopShadow,
324 | zDepth.mAlphaTopShadow);
325 | PropertyValuesHolder alphaBottomShadowHolder = PropertyValuesHolder.ofInt(ANIM_PROPERTY_ALPHA_BOTTOM_SHADOW,
326 | mZDepthParam.mAlphaBottomShadow,
327 | zDepth.mAlphaBottomShadow);
328 | PropertyValuesHolder offsetTopShadowHolder = PropertyValuesHolder.ofFloat(ANIM_PROPERTY_OFFSET_TOP_SHADOW,
329 | mZDepthParam.mOffsetYTopShadow,
330 | zDepth.mOffsetYTopShadow);
331 | PropertyValuesHolder offsetBottomShadowHolder = PropertyValuesHolder.ofFloat(ANIM_PROPERTY_OFFSET_BOTTOM_SHADOW,
332 | mZDepthParam.mOffsetYBottomShadow,
333 | zDepth.mOffsetYBottomShadow);
334 | PropertyValuesHolder blurTopShadowHolder = PropertyValuesHolder.ofFloat(ANIM_PROPERTY_BLUR_TOP_SHADOW,
335 | mZDepthParam.mBlurTopShadow,
336 | zDepth.mBlurTopShadow);
337 | PropertyValuesHolder blurBottomShadowHolder = PropertyValuesHolder.ofFloat(ANIM_PROPERTY_BLUR_BOTTOM_SHADOW,
338 | mZDepthParam.mBlurBottomShadow,
339 | zDepth.mBlurBottomShadow);
340 | mZDepthParam = zDepth;
341 | ValueAnimator anim = ValueAnimator
342 | .ofPropertyValuesHolder(
343 | alphaTopShadowHolder,
344 | alphaBottomShadowHolder,
345 | offsetTopShadowHolder,
346 | offsetBottomShadowHolder,
347 | blurTopShadowHolder,
348 | blurBottomShadowHolder);
349 | anim.setDuration(mZDepthAnimDuration);
350 | anim.setInterpolator(new LinearInterpolator());
351 | anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
352 | @Override
353 | public void onAnimationUpdate(ValueAnimator animation) {
354 | int alphaTopShadow = (Integer) animation.getAnimatedValue(ANIM_PROPERTY_ALPHA_TOP_SHADOW);
355 | int alphaBottomShadow = (Integer) animation.getAnimatedValue(ANIM_PROPERTY_ALPHA_BOTTOM_SHADOW);
356 | float offsetTopShadow = (Float) animation.getAnimatedValue(ANIM_PROPERTY_OFFSET_TOP_SHADOW);
357 | float offsetBottomShadow = (Float) animation.getAnimatedValue(ANIM_PROPERTY_OFFSET_BOTTOM_SHADOW);
358 | float blurTopShadow = (Float) animation.getAnimatedValue(ANIM_PROPERTY_BLUR_TOP_SHADOW);
359 | float blurBottomShadow = (Float) animation.getAnimatedValue(ANIM_PROPERTY_BLUR_BOTTOM_SHADOW);
360 |
361 |
362 | int colorTop = ColorUtil.adjustAlpha(alphaTopShadow,mShadowColor);
363 | int colorBottom = ColorUtil.adjustAlpha(alphaBottomShadow,mShadowColor);
364 |
365 | mShadow.setParameter(colorTop, colorBottom, offsetTopShadow, offsetBottomShadow, blurTopShadow, blurBottomShadow, mShadowDrawingRect);
366 |
367 | mParent.invalidate();
368 | }
369 | });
370 | anim.start();
371 | }
372 | }
373 |
--------------------------------------------------------------------------------