About the author: Speedy
Wechat Public Number: Android Tour
Blog Home Page: http://blog.csdn.net/speedystone
Nuggets column: https://juejin.im/user/57e082d60bd1d00057ff8c45
I. Preface
In our daily development, we need a lot of pictures to beautify our APP. Besides enhancing the aesthetics of UI, the large use of pictures also brings many problems, such as OOM (memory overflow), APK bulky volume, memory leak and so on. In fact, in most cases, we can use Shape Drawable to draw the graphics we need, thus effectively avoiding many problems caused by using pictures. ShapeDrawable can be understood as a graph drawn by color. It can be either a pure color picture or a gradient image. Shape Drawable is used with other hierarchical Drawables to draw very gorgeous graphics and animation effects.
2. Shape Drawable Explanation
ShapeDrawable corresponds to the < Shape > tag. Its grammar is as follows:
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape=["rectangle" | "oval" | "line" | "ring"] >
<corners
android:radius="integer"
android:topLeftRadius="integer"
android:topRightRadius="integer"
android:bottomLeftRadius="integer"
android:bottomRightRadius="integer" />
<gradient
android:angle="integer"
android:centerX="integer"
android:centerY="integer"
android:centerColor="integer"
android:endColor="color"
android:gradientRadius="integer"
android:startColor="color"
android:type=["linear" | "radial" | "sweep"]
android:useLevel=["true" | "false"] />
<padding
android:left="integer"
android:top="integer"
android:right="integer"
android:bottom="integer" />
<size
android:width="integer"
android:height="integer" />
<solid
android:color="color" />
<stroke
android:width="integer"
android:color="color"
android:dashWidth="integer"
android:dashGap="integer" />
</shape>
Detailed description of labels and attributes:
< shape >
android:shape Representation: Shape of a graph, which defines the following four types of shapes
- Rectangle: Rectangle. Default shape, you can draw right rectangle, round rectangle, arc, etc.
- oval: Elliptical. When the length is the same as the width, it means the right circle.
- line: line, you can draw solid and dotted lines.
- ring: ring, you can draw a progress bar.
When android:shape= "ring", it has the following special attributes:
- android:thickness thickness, the thickness of the ring = outer radius - Inner radius. When it exists with thickness Ratio, thickness shall prevail.
- Android: The inner radius of an innerRadius circle. When it coexists with innerRadius Ratio, the innerRadius shall prevail.
- Android: Inner Radius Ratio has a radius of 9 as a percentage of the entire Drawable width. If n, then the inner radius = width / n.
- android:thicknessRatio thickness as a percentage of the width of the entire Drawable, default value is 3. If n, then thickness = width / n.
- android:useLevel should generally use false, otherwise it may not achieve the desired effect unless it is used as Level List Drawable.
Angle (only applicable to android:shape= "rectangle") indicates the degree of roundness of the four corners of a shape. The radius of each roundness must be greater than 1, and no roundness exists on the side.
- android:radius sets the same angle for four corners at the same time. It has low priority and will be covered by the following.
- Android: TopLeft Radius Angle in the upper left corner
- Android: Top Right Radius Angle in the upper right corner
- Android: Bottom Left Radius Angle at the lower left corner
- Android: Bottom Right Radius Angle at the lower right corner
< gradient > Representation: Gradient effect
- android:angle gradient angle, default is 0, its value must be 45 integer times. 0 means from left to right, 90 means from top to bottom. The specific effect changes with the angle adjustment, and the angle influences the direction of gradual change.
- Android: abscissa points of center X gradient Center
- Android: the ordinate point of center Y gradient Center
- Android: Center Color Gradient Intermediate Color
- android:endColor Gradient End Color
- Android: radius of gradientRadius gradient (valid only if android:type is radio)
- android:startColor Gradient Initial Color
- android:type Gradient Type
Linear linear gradient (default)
Radial radial gradient
sweep scan line gradient
android:useLevel is generally false and is valid when Drawable is a StateList Drawable.
< padding > denotes: inner margin
- Android: top bottom left right sets the inner margins of the upper and lower sides respectively.
< size > indicates: shape size
- android:height specifies shape height
- android:width specifies shape width
Explanation: Strictly speaking, shape does not have width and height, but we specify size to have so-called width and height. When shapes are used as the background of View s, shapes are stretched, so the width does not fix the shape size as much as it is specified (there is no absolute width or height for Drawable s).
Solid > Represents: Pure color filling (exclusive from gradient, pure or gradient only one)
- android:color specifies the color of shape
Stroke > Represents: Stroke
- android:width, the wider the shape's edge, the thicker the shape's edge line
- Android: Colors for the Edge
- Android: Spacing between dashGap dotted lines
- Android: width of dashWidth dashed line
Note: If either android:dashWidth or android:dashGap is zero, the dotted line effect cannot be displayed.
3. ShapeDrawable Application Case (Imitated Wechat Radar Scanning)
First look at the screenshot of the operation effect:
Note: This case uses Layer Drawable, which will be highlighted later. Here is a brief introduction: Layer Drawable corresponds to < layer-list > label. Layer Drawable represents a hierarchical set of Drawables. By placing different Drawables on different layers, a superimposed effect can be achieved.
1. Drawing radar ripple: / res/drawable/wave.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<!--Outermost circle-->
<shape android:shape="oval">
<solid android:color="#10FFFFFF" />
<size
android:width="600dp"
android:height="600dp" />
<stroke
android:color="#10B8B8B8"
android:dashWidth="1dp" />
</shape>
</item>
<item
android:bottom="100dp"
android:left="100dp"
android:right="100dp"
android:top="100dp">
<!--Intermediate circle-->
<shape android:shape="oval">
<solid android:color="#1CFFFFFF" />
<stroke
android:color="#1CB8B8B8"
android:dashWidth="1dp" />
</shape>
</item>
<item
android:bottom="200dp"
android:left="200dp"
android:right="200dp"
android:top="200dp">
<!--Central circle-->
<shape android:shape="oval">
<solid android:color="#2CFFFFFF" />
<stroke
android:color="#2CB8B8B8"
android:dashWidth="1dp" />
</shape>
</item>
</layer-list>
Preview effect:
Drawing Scanning Beam: / res/drawable/light_beam.xml
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<size
android:width="500dp"
android:height="500dp" />
<gradient
android:endColor="#AAAAAAAA"
android:startColor="#00000000"
android:type="sweep"
/>
</shape>
Preview effect:
Activity layout file: / res/layout/activity_shape_drawable.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FA000000"
android:clipToPadding="false"
android:fitsSystemWindows="true"
tools:context="com.speedy.shapedrawabledemo.ShapeDrawableActivity">
<ImageView
android:id="@+id/ivWave"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="5dp"
android:src="@drawable/wave" />
<ImageView
android:id="@+id/ivLightbeam"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/light_beam"
/>
</FrameLayout>
Activity code:
/**
* Created by Speedy on 2017/5/09.
*/
public class ShapeDrawableActivity extends AppCompatActivity {
private ImageView ivLightbeam;
private ObjectAnimator radarScanAnim; // Scanning Animation
private int width;
private int height;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_shape_drawable);
ivLightbeam = (ImageView) findViewById(R.id.ivLightbeam);
}
@Override
protected void onResume() {
super.onResume();
startScan();
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if(height == 0 || width == 0){
//Get screen length and width
width = ScreenUtils.getScreenWidth(this);
height = ScreenUtils.getScreenHeight(this);
//Calculating the Scanning Circle Diameter Based on the Screen Length and Width
int diameter= (int) Math.sqrt(Math.pow(height,2)+ Math.pow(width,2));
//Modify the size of the beam so that it can scan the entire screen
FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(diameter,diameter);
ivLightbeam.setLayoutParams(layoutParams);
//Move the center of the scanning beam to the content center of the screen
int offsetX = (width-diameter)/2;
int offsetY = (height-diameter)/2 + ScreenUtils.getStatusHeight(this)/2;
ivLightbeam.setX(offsetX);
ivLightbeam.setY(offsetY);
}
}
@Override
protected void onPause() {
super.onPause();
stopScan();
}
// Start scanning
private void startScan(){
radarScanAnim = ObjectAnimator.ofFloat(ivLightbeam,"rotation",0f,360f);
radarScanAnim.setDuration(2000); //Scan a lap in 2 seconds
radarScanAnim.setInterpolator(new LinearInterpolator());
radarScanAnim.setRepeatCount(ObjectAnimator.INFINITE);//Cyclic scanning
ivLightbeam.setVisibility(View.VISIBLE);
radarScanAnim.start();
}
// Stop scanning
private void stopScan(){
ivLightbeam.setVisibility(View.GONE);
radarScanAnim.end();
}
}
Operating effect screenshot:
Finally, the operation effect is as follows:
Explanation: The recorded GIF loses frames seriously, so the scan looks incoherent, and it will not work like this on the mobile phone.
Demo source download address: http://download.csdn.net/detail/easyer2012/9837222