Android画布(一 )
作者:互联网
获取画布的方法
* onDraw()
* diapatchDraw()
* 通过Bitmap创建
* 通过SurfaceView的SurfaceHolder.lockCanvas()
Drawable类
- 可以通过创建dawable对象,然后将画好的drawable对象画在画布上,也是创建Bitmap的一种方式
ShapeDrawable
shape标签与GradientDrawable
- 首先shap标签所对应的类是GradientDrawable而不是ShapeDrawable,但是GradienntDrawable并不能完成shape标签的所有功能,GradientDrawable的构造函数如下
GradientDrawable(GradientDrawable.Orientation orientation, int[] colors)
- 构造函数可以看出GradientDrawable对应的是gradient标签的功能,并不能完成shape标签的构造矩形、椭圆等功能,但是获得shape的时候需要将其强制转换为GradientDrawable
获取shape标签的实例
eg: 获取shape对象并设置为圆角:
public class AndroidHuaBuActivity extends AppCompatActivity {
private Button button;
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_android_hua_bu);
button = (Button)findViewById(R.id.add_shape_corner);
textView = (TextView)findViewById(R.id.shape_tv);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//通过textView的getBackground获得shape标签
GradientDrawable gradientDrawable = (GradientDrawable)textView.getBackground();
gradientDrawable.setCornerRadius(20);
}
});
}
}
通过textView的背景将下面的xml引入:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#ff0000"/>
<stroke android:width="2dp"
android:color="#00ff00"
android:dashGap="5dp"
android:dashWidth="5dp"/>
</shape>
ShapeDrawable的构造函数:
ShapeDrawable()
ShapeDrawable(Shape shape)
- 注意:
- ShapeDrawable对象是需要与Shape对象进行关联的,所以如果使用第一个构造函数,必须使用ShapeDrawable.setShape(Shape shape)函数来设置 Shape对象,一般使用第二个构造函数
- Shape类是一个基类,draw()函数是一个虚函数,每个子类可以根据不同的需求来绘出不同的图形,所以构造ShapeDrawable并不能直接传递shape类型的队形,因为shape中没有实现draw(),而是需要传入已经实现了draw()函数的Shape类的派生类
Shape的派生类:
派生类 | 意义 |
---|---|
RectShape | 构造一个矩形Shape |
ArcShape | 构造一个扇形Shape |
OcalShape | 构造一个椭圆的Shape |
RoundRectShape | 构造一个圆角矩形Shape, 可带有镂空矩形效果 |
PathShape | 构造一个可根据路径绘制的Shape |
RectShape
public class ShapeView extends View {
private ShapeDrawable shapeDrawable;
public ShapeView(Context context) {
super(context);
init();
}
public ShapeView(Context context, AttributeSet attributeSet){
super(context, attributeSet);
init();
}
public ShapeView(Context context, AttributeSet attributeSet, int defStyle){
super(context, attributeSet, defStyle);
init();
}
private void init() {
setLayerType(LAYER_TYPE_SOFTWARE,null);
//生成一个ShapeDrawable,并将这个形状的定义为矩形
shapeDrawable = new ShapeDrawable(new RectShape());
//设置shapeDrawable在空间中的显示位置(在当前控件中的位置)
shapeDrawable.setBounds(new Rect(50, 50, 200, 100));
//获取画笔,并将整个Drawable填充为黄色
shapeDrawable.getPaint().setColor(Color.YELLOW);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//将shape实例画在画布上
shapeDrawable.draw(canvas);
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".AndroidHuabu.ShapeExample.ShapeActivity">
<com.example.adminstator.myviewdesign.AndroidHuabu.ShapeExample.ShapeView
android:layout_width="250px"
android:layout_height="150px"
android:layout_margin="100dp"
android:background="#ffffff"/>
</LinearLayout>
-
结论:
- 整个矩形区域水平居中显示,可以证明ShapeDrawable.setBounds()函数所设置的矩形位置是指所在控件中的位置,并非整个屏幕
-
Drawable画布问题:
- 通过getPaint()获得画笔,但是ShapeDrawable.draw(canvas)是将shape画到控件上,并没有绘制shapeDrawable本身。shapeDrawable是自带画笔的,质押奥得到了画笔。改变 paint的任何内容,就会立刻在ShapeDrawable上重画
ArcShape
- ArcShape是在 OvalShape所形成的椭圆的基础上,将其进行角度切割所形成的扇形,其中扇形开始的0度在椭圆的x轴正方向上
//startAngle:指的是开始的角度,扇形开始的0度在椭圆的X轴正方向上,即右中间的位置(顺时针方向)
//sweepAngle:指扇形所扫过的角度
public ArcShape(ffloat startAngle, float sweepAngle)
RoundRectShape
- 字面上的意思是圆角矩形,它不止可以实现圆角矩形,他的本意是实现镂空的圆角矩形
- 效果:
- 可以实现单纯的圆角矩形
- 可以实现中间带有镂空的圆角矩形,而且中间镂空的矩形也可以带有圆角
//outerRadii:外围矩形的各个角的角度大小,需要填充8个数字,每两个数字一组,分别对应(左上角,右上角, 右下角,左下角)4个角的角度组(x, y),每两个一组的数字构成一个椭圆。第一个数字代表椭圆的X轴半径,第二个数字代表椭圆的Y轴半径, 如果不需要指定外围矩形的各个角的角度,可以传入null
//RectF inset:表示内部矩形与 外部矩形各边的边距,RectF的4个值分别对应left,top, right, bottom, 如果不需要内部矩形的镂空效果,则可以传入null
//float[] innerRadii:表示内部矩形的各个角的角度大小,同样需要填充8个数字,其含义与outerRadii一样,如果不指定各个角的角度,则传入null即可
public RoundRectShape(float[] outerRadii, RectF inset, float[] innerRadii)
eg:
public class ShapeView extends View {
private ShapeDrawable shapeDrawable;
public ShapeView(Context context) {
super(context);
init();
}
public ShapeView(Context context, AttributeSet attributeSet){
super(context, attributeSet);
init();
}
public ShapeView(Context context, AttributeSet attributeSet, int defStyle){
super(context, attributeSet, defStyle);
init();
}
private void init() {
setLayerType(LAYER_TYPE_SOFTWARE,null);
// //生成一个ShapeDrawable,并将这个形状的定义为矩形
// shapeDrawable = new ShapeDrawable(new ArcShape(0, 300));
// //设置shapeDrawable在空间中的显示位置(在当前控件中的位置)
// shapeDrawable.setBounds(new Rect(50, 50, 200, 100));
// //获取画笔,并将整个Drawable填充为黄色
float[] outerRadii = new float[]{12, 12, 12, 12, 0, 0, 0, 0};
RectF inset = new RectF(6, 6, 6, 6);
float[] innerRadii = new float[]{50, 12, 0, 0, 12, 50, 0, 0};
shapeDrawable = new ShapeDrawable(new RoundRectShape(outerRadii, inset, innerRadii));
shapeDrawable.setBounds(50, 50, 200, 100);
shapeDrawable.getPaint().setColor(Color.BLUE);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//将shape实例画在画布上
shapeDrawable.draw(canvas);
}
}
PathShape
//path:所要画的路径
//stdWidth:表示标注宽度,即将整个ShapeDrawable的宽度分成多少份,Path中moveTo(x, y),lineTo(x, y)这些函数中的数值在这里起始都是以每一份的位置来计算的,当ShapeDrawable动态变大、变小时,每一份都会变小,而根据这些分的数值画出来的Path图形就是动态缩放
//stdHeight:表示标准高度,即将ShapeDrawable的高度分成多少份
public PathShape(Path path, float stdWidth, float stdHeight)
eg:
public class ShapeView extends View {
private ShapeDrawable shapeDrawable;
public ShapeView(Context context) {
super(context);
init();
}
public ShapeView(Context context, AttributeSet attributeSet){
super(context, attributeSet);
init();
}
public ShapeView(Context context, AttributeSet attributeSet, int defStyle){
super(context, attributeSet, defStyle);
init();
}
private void init() {
setLayerType(LAYER_TYPE_SOFTWARE,null);
Path path = new Path();
//注意这里此时的单位是份
path.moveTo(0, 0);
path.lineTo(100, 0);
path.lineTo(100, 100);
path.lineTo(0, 100);
path.close();
//首先我们要知道这里的单位是份的概念而不是px,所以为了对比,我们将shapeDrawable和画布大小设为一致
// 开始将shape 100, 100 可以发现它填满了控件如果使用的是px当然是不可能将其填满的,
// 将ShapeDrawable的高设置成200,则原来的只能占1/2,所以只能展示为控件的一半
shapeDrawable = new ShapeDrawable(new PathShape(path, 100, 200));
shapeDrawable.setBounds(new Rect(0, 0, 250, 150));
shapeDrawable.getPaint().setColor(Color.BLUE);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//将shape实例画在画布上
shapeDrawable.draw(canvas);
}
}
自定义shape
- 想要自定义shape,必须先看他的各个派生类的源码是如何实现相应的draw()
public class PathShape extends Shape {
private final float mStdWidth;
private final float mStdHeight;
private Path mPath;
private float mScaleX; // cached from onResize
private float mScaleY; // cached from onResize
/**
* PathShape constructor.
*
* @param path a Path that defines the geometric paths for this shape
* @param stdWidth the standard width for the shape. Any changes to the
* width with resize() will result in a width scaled based
* on the new width divided by this width.
* @param stdHeight the standard height for the shape. Any changes to the
* height with resize() will result in a height scaled based
* on the new height divided by this height.
*/
public PathShape(@NonNull Path path, float stdWidth, float stdHeight) {
mPath = path;
mStdWidth = stdWidth;
mStdHeight = stdHeight;
}
@Override
public void draw(Canvas canvas, Paint paint) {
canvas.save();
canvas.scale(mScaleX, mScaleY);
canvas.drawPath(mPath, paint);
canvas.restore();
}
@Override
protected void onResize(float width, float height) {
mScaleX = width / mStdWidth;
mScaleY = height / mStdHeight;
}
@Override
public PathShape clone() throws CloneNotSupportedException {
final PathShape shape = (PathShape) super.clone();
shape.mPath = new Path(mPath);
return shape;
}
}
- 发现这个派生类做的就是在创建PathShape的时候将path传递进去,然后利用draw()函数将其画出来(onResize()函数是根据我们刚才发现的份的关系,进行重新的计算)
package com.example.adminstator.myviewdesign.AndroidHuabu.ShapeExample;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.RegionIterator;
import android.graphics.drawable.shapes.Shape;
/**
* Created with Android Studio.
* Description:
*
* @author: 王拣贤
* @date: 2019/06/27
* Time: 21:32
*/
public class OwnShapeView extends Shape {
private Region region;
public OwnShapeView(Region region){
if(region!=null){
this.region = region;
}
}
@Override
public void draw(Canvas canvas, Paint paint) {
RegionIterator iter = new RegionIterator(region);
Rect r = new Rect();
while (iter.next(r)){
canvas.drawRect(r, paint);
}
}
}
标签:ShapeDrawable,画布,shapeDrawable,shape,context,new,Android,public 来源: https://blog.csdn.net/qq_39424143/article/details/93915695