自定义View继承自View类,需要重写onDraw方法,通过canvas和paint进行绘制
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawLine();
}
public void drawLine(float startX, float startY, float stopX, float stopY,
@NonNull Paint paint) {
super.drawLine(startX, startY, stopX, stopY, paint);
}
framework/base/graphics/java/android/graphics/BaseCanvas.java
public void drawLine(float startX, float startY, float stopX, float stopY,
@NonNull Paint paint) {
throwIfHasHwFeaturesInSwMode(paint);
nDrawLine(mNativeCanvasWrapper, startX, startY, stopX, stopY, paint.getNativeInstance());
}
private static native void nDrawLine(long nativeCanvas, float startX, float startY, float stopX,
float stopY, long nativePaint);
framework/base/libs/hwui/jni/android_graphics_Canvas.cpp
// If called from Canvas these are regular JNI
// If called from DisplayListCanvas they are @FastNative
static const JNINativeMethod gDrawMethods[] = {
{"nDrawColor","(JII)V", (void*) CanvasJNI::drawColor},
{"nDrawColor","(JJJI)V", (void*) CanvasJNI::drawColorLong},
{"nDrawPaint","(JJ)V", (void*) CanvasJNI::drawPaint},
{"nDrawPoint", "(JFFJ)V", (void*) CanvasJNI::drawPoint},
{"nDrawPoints", "(J[FIIJ)V", (void*) CanvasJNI::drawPoints},
{"nDrawLine", "(JFFFFJ)V", (void*) CanvasJNI::drawLine},
static void drawLine(JNIEnv* env, jobject, jlong canvasHandle, jfloat startX, jfloat startY,
jfloat stopX, jfloat stopY, jlong paintHandle) {
Paint* paint = reinterpret_cast<Paint*>(paintHandle);
get_canvas(canvasHandle)->drawLine(startX, startY, stopX, stopY, *paint);
}
static Canvas* get_canvas(jlong canvasHandle) {
return reinterpret_cast<Canvas*>(canvasHandle);
}
framework/base/libs/hwui/hwui/Canvas.cpp
virtual void drawLine(float startX, float startY, float stopX, float stopY,
const Paint& paint) = 0;
frameworks\base\libs\hwui\SkiaCanvas.cpp
void SkiaCanvas::drawLine(float startX, float startY, float stopX, float stopY,
const Paint& paint) {
applyLooper(&paint,
[&](const SkPaint& p) { mCanvas->drawLine(startX, startY, stopX, stopY, p); });
}
void applyLooper(const Paint* paint, Proc proc, void (*preFilter)(SkPaint&) = nullptr) {
BlurDrawLooper* looper = paint ? paint->getLooper() : nullptr;
Paint pnt = paint ? *paint : Paint();
if (preFilter) {
preFilter(pnt);
}
this->onFilterPaint(pnt);
if (looper) {
looper->apply(pnt, [&](SkPoint offset, const Paint& modifiedPaint) {
mCanvas->save();
mCanvas->translate(offset.fX, offset.fY);
proc(modifiedPaint);
mCanvas->restore();
});
} else {
proc(pnt);
}
}
external/skia/src/core/SkCanvas.cpp
void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
SkPoint pts[2];
pts[0].set(x0, y0);
pts[1].set(x1, y1);
this->drawPoints(kLines_PointMode, 2, pts, paint);
}
void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
TRACE_EVENT0("skia", TRACE_FUNC);
this->onDrawPoints(mode, count, pts, paint);
}
void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
const SkPaint& paint) {
if ((long)count <= 0 || paint.nothingToDraw()) {
return;
}
SkASSERT(pts != nullptr);
SkRect bounds;
// Compute bounds from points (common for drawing a single line)
if (count == 2) {
bounds.set(pts[0], pts[1]);
} else {
bounds.setBounds(pts, SkToInt(count));
}
// Enforce paint style matches implicit behavior of drawPoints
SkPaint strokePaint = paint;
strokePaint.setStyle(SkPaint::kStroke_Style);
if (this->internalQuickReject(bounds, strokePaint)) {
return;
}
auto layer = this->aboutToDraw(this, strokePaint, &bounds);
if (layer) {
this->topDevice()->drawPoints(mode, count, pts, layer->paint());
}
}
external\skia\src\core\SkDevice.h
virtual void drawPaint(const SkPaint& paint) = 0;
virtual void drawPoints(SkCanvas::PointMode mode, size_t count,
const SkPoint[], const SkPaint& paint) = 0;
external\skia\src\gpu\v1\Device.cpp
void Device::drawPaint(const SkPaint& paint) {
ASSERT_SINGLE_OWNER
GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawPaint", fContext.get());
GrPaint grPaint;
if (!SkPaintToGrPaint(this->recordingContext(), fSurfaceDrawContext->colorInfo(), paint,
this->asMatrixProvider(), &grPaint)) {
return;
}
fSurfaceDrawContext->drawPaint(this->clip(), std::move(grPaint), this->localToDevice());
}
void Device::drawPoints(SkCanvas::PointMode mode,
size_t count,
const SkPoint pts[],
const SkPaint& paint) {
ASSERT_SINGLE_OWNER
GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawPoints", fContext.get());
SkScalar width = paint.getStrokeWidth();
if (width < 0) {
return;
}
GrAA aa = fSurfaceDrawContext->chooseAA(paint);
if (count == 2 && mode == SkCanvas::kLines_PointMode) {
if (paint.getPathEffect()) {
// Probably a dashed line. Draw as a path.
GrPaint grPaint;
if (SkPaintToGrPaint(this->recordingContext(),
fSurfaceDrawContext->colorInfo(),
paint,
this->asMatrixProvider(),
&grPaint)) {
SkPath path;
path.setIsVolatile(true);
path.moveTo(pts[0]);
path.lineTo(pts[1]);
fSurfaceDrawContext->drawPath(this->clip(),
std::move(grPaint),
aa,
this->localToDevice(),
path,
GrStyle(paint, SkPaint::kStroke_Style));
}
return;
}
if (!paint.getMaskFilter() &&
paint.getStrokeWidth() > 0 && // drawStrokedLine doesn't support hairlines.
paint.getStrokeCap() != SkPaint::kRound_Cap) { // drawStrokedLine doesn't do round caps.
// Simple stroked line. Bypass path rendering.
GrPaint grPaint;
if (SkPaintToGrPaint(this->recordingContext(),
fSurfaceDrawContext->colorInfo(),
paint,
this->asMatrixProvider(),
&grPaint)) {
fSurfaceDrawContext->drawStrokedLine(this->clip(),
std::move(grPaint),
aa,
this->localToDevice(),
pts,
SkStrokeRec(paint, SkPaint::kStroke_Style));
}
return;
}
}
SkScalar scales[2];
bool isHairline = (0 == width) ||
(1 == width && this->localToDevice().getMinMaxScales(scales) &&
SkScalarNearlyEqual(scales[0], 1.f) && SkScalarNearlyEqual(scales[1], 1.f));
// we only handle non-coverage-aa hairlines and paints without path effects or mask filters,
// else we let the SkDraw call our drawPath()
if (!isHairline ||
paint.getPathEffect() ||
paint.getMaskFilter() ||
fSurfaceDrawContext->chooseAAType(aa) == GrAAType::kCoverage) {
SkRasterClip rc(this->devClipBounds());
SkDraw draw;
draw.fDst = SkPixmap(SkImageInfo::MakeUnknown(this->width(), this->height()), nullptr, 0);
draw.fMatrixProvider = this;
draw.fRC = &rc;
draw.drawPoints(mode, count, pts, paint, this);
return;
}
GrPrimitiveType primitiveType = point_mode_to_primitive_type(mode);
const SkMatrixProvider* matrixProvider = this;
GrPaint grPaint;
if (!SkPaintToGrPaint(this->recordingContext(), fSurfaceDrawContext->colorInfo(), paint,
*matrixProvider, &grPaint)) {
return;
}
static constexpr SkVertices::VertexMode kIgnoredMode = SkVertices::kTriangles_VertexMode;
sk_sp<SkVertices> vertices = SkVertices::MakeCopy(kIgnoredMode, SkToS32(count), pts, nullptr,
nullptr);
fSurfaceDrawContext->drawVertices(this->clip(), std::move(grPaint), *matrixProvider,
std::move(vertices), &primitiveType);
}