Android UI底层绘制原理

news/2024/12/22 23:31:05/

自定义View继承自View类,需要重写onDraw方法,通过canvas和paint进行绘制

@Overrideprotected 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 drawPointsSkPaint 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_OWNERGR_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_OWNERGR_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);
}


http://www.ppmy.cn/news/1433673.html

相关文章

C++ | Leetcode C++题解之第45题跳跃游戏II

题目&#xff1a; 题解&#xff1a; class Solution { public:int jump(vector<int>& nums) {int maxPos 0, n nums.size(), end 0, step 0;for (int i 0; i < n - 1; i) {if (maxPos > i) {maxPos max(maxPos, i nums[i]);if (i end) {end maxPos;s…

flutter release 报错 Error: SocketException: Failed host lookup:

flutter 的 debug 模式没有任何问题 &#xff0c;打了release 包后一直报下面的错&#xff0c;查了一下是 因为没有网络权限 Error: SocketException: Failed host lookup: yomi-test-aws-sg.yomigame.games (OS Error: No address associated with hostname, errno 7) 按照下…

大模型的实践应用22-谷歌Gemma AI大模型的架构原理,以及Gemma模型的部署安装本地教程

大家好,我是微学AI,今天给大家介绍一下大模型的实践应用22-谷歌Gemma AI大模型的架构原理,以及Gemma模型的部署安装本地教程。谷歌Gemma AI大模型是由Google AI团队开发并开源。Gemma模型采用Transformer编码器-解码器架构,并加入了一些改进,例如使用稀疏注意力机制来提高推…

vue elmentui 可编辑table 实现

废话不多说上图&#xff1a; 1.可编辑input 2.可编辑下来框 3.点击chechbox 4.可编辑radio 其实后面两种可以直接显示值 需要修改直接改就行 保持风格统一所以就做了点击之后出现修改功能 上代码&#xff0c;不要哔哔 哈哈 粗暴 真得是曲不离口 拳不离手&#xff0c; 几天…

package.json 里面的 dependencies 和 devDependencies 的差异

差异 其实不严格的话&#xff0c;没有特别的差异&#xff1b;若是严格&#xff0c;遵循官方的理解。 dependencies&#xff1a;存放线上或者业务能访问的核心代码模块&#xff0c;比如 vue、vue-routerdevDependencies&#xff1a;处于开发模式下所依赖的开发模块&#xff0c…

界面组件DevExpress Blazor UI v23.2 - 支持.NET 8、全新的项目模版

DevExpress Blazor UI组件使用了C#为Blazor Server和Blazor WebAssembly创建高影响力的用户体验&#xff0c;这个UI自建库提供了一套全面的原生Blazor UI组件&#xff08;包括Pivot Grid、调度程序、图表、数据编辑器和报表等&#xff09;。 DevExpress Blazor控件目前已经升级…

HarmonyOS-静态库(SDK)的创建和使用

文章目录 一、静态库&#xff08;SDK&#xff09;二、创建静态库1.新建静态库模块2. 开发静态库内容3. 编译静态库 三、使用静态库1. 配置项目依赖2. 在应用中使用静态库3. 注意事项 四、打包错误1. library引用本地har包错误 一、静态库&#xff08;SDK&#xff09; 在Harmon…

【AI面试】工作和面试过程中,经常遇到的其他问题汇总一(持续更新)

在与面试官在面对面进行交流的过程中,面试官不仅仅会针对简历中记录的内容进行深入的了解,还会进行一些发散性的提问。 目前也就很明显,就是要看看对方: 对于常见的问题是如何思考的?有没有在持续性的学习本领域的新知识?对于不知道的问题,是如何思考的?迁移能力咋样。…