Android UI底层绘制原理

简介: Android UI底层绘制原理

自定义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);
}


目录
相关文章
|
4天前
|
安全 Shell Android开发
Android系统 init.rc sys/class系统节点写不进解决方案和原理分析
Android系统 init.rc sys/class系统节点写不进解决方案和原理分析
35 0
|
3天前
|
Android开发 移动开发 小程序
binder机制原理面试,安卓app开发教程
binder机制原理面试,安卓app开发教程
binder机制原理面试,安卓app开发教程
|
3天前
|
Android开发 算法 架构师
android的基础ui组件,这些知识点你会吗
android的基础ui组件,这些知识点你会吗
android的基础ui组件,这些知识点你会吗
|
3天前
|
Android开发 缓存 双11
android的基础ui组件,Android开发社招面试经验
android的基础ui组件,Android开发社招面试经验
android的基础ui组件,Android开发社招面试经验
|
4天前
|
存储 Java Android开发
Android系统 设置第三方应用为默认Launcher实现和原理分析
Android系统 设置第三方应用为默认Launcher实现和原理分析
68 0
|
2天前
|
Android开发 异构计算 前端开发
Android显示原理,安卓自定义view面试
Android显示原理,安卓自定义view面试
|
2天前
|
Android开发
Flutter完整开发实战详解(六、 深入Widget原理),2024百度Android岗面试真题收录解析
Flutter完整开发实战详解(六、 深入Widget原理),2024百度Android岗面试真题收录解析
|
4天前
|
Web App开发 开发框架 前端开发
Open UI5 前端开发框架配套的 Mock Server 工作原理解析
Open UI5 前端开发框架配套的 Mock Server 工作原理解析
11 0
|
4天前
|
存储 Java Shell
Android系统 实现低内存白名单防LMK原理分析
Android系统 实现低内存白名单防LMK原理分析
43 0
|
4天前
|
网络协议 Shell Android开发
Android 深入学习ADB调试原理(1)
Android 深入学习ADB调试原理(1)
32 1