It is common to see controls with shadow effects during development, which can be implemented through CardView and Android: Elevation provided by the SDK, as well as through.9 diagrams. However, there are some disadvantages to using these two methods, such as: you can’t control the shadow color, and using too many.9 images will increase the size of the APK installation file. In view of the above problems, I wrote a library to add shadows for the control —- ShadowLayout. Next, this paper expands ShadowLayout, which is mainly divided into the following two parts:

  1. aboutShadowLayoutThe use of;
  2. aboutShadowLayoutThe principle of.

Use of ShadowLayout

Let’s take a look at the renderings of various shadows using the ShadowLayout library, as shown below:

As shown in the image above, you can control the color of the shadow, the range, the display boundaries (up, down, left, and right boundaries), and the offset of the X and Y axes by using ShadowLayout.

Add the dependent

Gradle:

    compile 'com. Lijiankun24: shadowlayout: 1.0.0'Copy the code

Maven:

< the dependency > < groupId > com. Lijiankun24 < / groupId > < artifactId > shadowlayout < / artifactId > < version > 1.0.0 < / version > <type>pom</type> </dependency>Copy the code

How to use

Add the following layout file to the XML:

    <com.lijiankun24.shadowlayout.ShadowLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="30dp"
        app:shadowColor="# 66000000"
        app:shadowDx="0dp"
        app:shadowDy="3dp"
        app:shadowRadius="10dp"
        app:shadowSide="all">

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@android:color/white"
            android:contentDescription="@null"
            android:src="@mipmap/ic_launcher"/>
    </com.lijiankun24.shadowlayout.ShadowLayout>Copy the code

The XML layout file above looks like this:

As the code in the XML above shows, there are five custom attributes with the following meanings:

  • app:shadowColor="#66000000"Control the color of the shadows,Note: the color must have a value for transparency
  • app:shadowDx="0dp"Controls the X-axis offset of the shadow
  • app:shadowDy="3dp"Controls the y offset of the shadow
  • app:shadowRadius="10dp"Controls the range of shadows
  • app:shadowSide="all|left|right|top|bottom"Controls the boundaries of the shadow display, with five values in total

The principle of ShadowLayout

The principle of ShadowLayout is very simple, which can be divided into the following steps:

  1. Obtain the attributes of the shadow through custom attributes, including: shadow color, shadow range size, shadow display boundary, and the offset of the x and y axes of the shadow.
  2. inonLayout()Method to get the range the shadow should display and set thisShadowLayoutPaddingValue to allow space for shadow display;
  3. inonDraw()Method.CanvasPaintMethod to draw shadows.

    The two most important ways to draw shadows are:

    • Paint.setShadowLayer(float radius, float dx, float dy, int shadowColor)Sets the size, color, and x and y offsets of the shadow
    • canvas.drawRect(RectF rect, Paint paint)Sets the position of the shadow display

There is only one file in the ShadowLayout library: —- ShadowLayout. Java. ShadowLayout is a subclass of RelativeLayout.

/** * ShadowLayout.java * 

* Created by lijiankun on 17/8/11. */

public class ShadowLayout extends RelativeLayout { public static final int ALL = 0x1111; public static final int LEFT = 0x0001; public static final int TOP = 0x0010; public static final int RIGHT = 0x0100; public static final int BOTTOM = 0x1000; private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private RectF mRectF = new RectF(); /** * Shadow color */ private int mShadowColor = Color.TRANSPARENT; /** * 阴影的大小范围 */ private float mShadowRadius = 0; /** * The X-axis offset of the shadow */ private float mShadowDx = 0; /** * The y offset of the shadow */ private float mShadowDy = 0; /** * 阴影显示的边界 */ private int mShadowSide = ALL; public ShadowLayout(Context context) { this(context, null); } public ShadowLayout(Context context, AttributeSet attrs) { this(context, attrs, 0); } public ShadowLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(attrs); } /** * Gets the position of the shadow to draw, and sets the Padding for ShadowLayout to leave room for the shadow to display @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); float effect = mShadowRadius + dip2px(5); float rectLeft = 0; float rectTop = 0; float rectRight = this.getWidth(); float rectBottom = this.getHeight(); int paddingLeft = 0; int paddingTop = 0; int paddingRight = 0; int paddingBottom = 0; if (((mShadowSide & LEFT) == LEFT)) { rectLeft = effect; paddingLeft = (int) effect; } if (((mShadowSide & TOP) == TOP)) { rectTop = effect; paddingTop = (int) effect; } if (((mShadowSide & RIGHT) == RIGHT)) { rectRight = this.getWidth() - effect; paddingRight = (int) effect; } if (((mShadowSide & BOTTOM) == BOTTOM)) { rectBottom = this.getHeight() - effect; paddingBottom = (int) effect; } if(mShadowDy ! =0.0 f) { rectBottom = rectBottom - mShadowDy; paddingBottom = paddingBottom + (int) mShadowDy; } if(mShadowDx ! =0.0 f) { rectRight = rectRight - mShadowDx; paddingRight = paddingRight + (int) mShadowDx; } mRectF.left = rectLeft; mRectF.top = rectTop; mRectF.right = rectRight; mRectF.bottom = rectBottom; this.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom); } /** * the real way to draw shadows */ @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawRect(mRectF, mPaint); } /** * Reads the attributes of the set shadow **@paramAttrs gets the set value */ from it private void init(AttributeSet attrs) { setLayerType(View.LAYER_TYPE_SOFTWARE, null); // Turn off hardware acceleration this.setWillNotDraw(false); // After this method is called, the onDraw(Canvas) method is executed TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.ShadowLayout); if(typedArray ! =null) { mShadowColor = typedArray.getColor(R.styleable.ShadowLayout_shadowColor, ContextCompat.getColor(getContext(), android.R.color.black)); mShadowRadius = typedArray.getDimension(R.styleable.ShadowLayout_shadowRadius, dip2px(0)); mShadowDx = typedArray.getDimension(R.styleable.ShadowLayout_shadowDx, dip2px(0)); mShadowDy = typedArray.getDimension(R.styleable.ShadowLayout_shadowDy, dip2px(0)); mShadowSide = typedArray.getInt(R.styleable.ShadowLayout_shadowSide, ALL); typedArray.recycle(); } mPaint.setAntiAlias(true); mPaint.setColor(Color.TRANSPARENT); mPaint.setShadowLayer(mShadowRadius, mShadowDx, mShadowDy, mShadowColor); } /** * dip2px dp value to px value **@param* dpValue dp value@returnPx value * / private float dip2px(float dpValue) { DisplayMetrics dm = getContext().getResources().getDisplayMetrics(); float scale = dm.density; return (dpValue * scale + 0.5 F); }}Copy the code

So far, the use method and principle of ShadowLayout library have been completely introduced. The library is ShadowLayout on GitHub, welcome star and fork, and also welcome to download APK experience through the following TWO-DIMENSIONAL code. If you have any questions, please point out. My email address is [email protected]


References:

Android view height and shadow thing – maple

ShadowViewHelper — Day_byConan