高级UI

作者: Lucky胡 | 来源:发表于2019-11-03 14:55 被阅读0次

一、Android 布局添加流程

二、View的绘制流程

1、view绘制流程

2、具体3大绘制过程

1.测量过程performMeasure()

2.布局过程performLayout()
调用ViewRootImpl里的

performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,
            int desiredWindowHeight)

在这个方法里又调用了view的layout()方法

view.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
//在该方法中,计算了view的相对父布局的位置,即left/right/top/bottom
//如果是viewgroup,则还需要实现onLayout(boolean changed, int left, int top, int right, int bottom),来计算其子view的位置,这样来算出每个view的位置

比如FrameLayout作为一个ViewGroup,就实现了自己的onLayout()方法来计算子view的位置。

    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        layoutChildren(left, top, right, bottom, false /* no force left gravity */);
    }
//在layoutChilden()里计算了所有子view的位置,然后子view调用自己的layout()方法将位置放入自身

总结:
ViewGroup
确定自己的位置:layout(),调用onLayout()进行子view的布局。
对于自定义的ViewGroup,需要重写onLayout()来计算子view的位置。

View
调用layout()确定自己的位置即可。

3.绘制过程performDraw()
里面调用了ViewRootImpl.draw()方法,然后调动drawSoftware(),里面调用了view的draw()方法

public void draw(Canvas canvas) {

        /*
         * Draw traversal performs several drawing steps which must be executed
         * in the appropriate order:
         *
         *      1. Draw the background
         *      2. If necessary, save the canvas' layers to prepare for fading
         *      3. Draw view's content
         *      4. Draw children
         *      5. If necessary, draw the fading edges and restore layers
         *      6. Draw decorations (scrollbars for instance)
         */

        // Step 1, draw the background, if needed
        int saveCount;

        if (!dirtyOpaque) {
            drawBackground(canvas);
        }

        // skip step 2 & 5 if possible (common case)
        final int viewFlags = mViewFlags;
        boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0;
        boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0;
        if (!verticalEdges && !horizontalEdges) {
            // Step 3, draw the content
            if (!dirtyOpaque) onDraw(canvas);

            // Step 4, draw the children
            dispatchDraw(canvas);

            drawAutofilledHighlight(canvas);

            // Overlay is part of the content and draws beneath Foreground
            if (mOverlay != null && !mOverlay.isEmpty()) {
                mOverlay.getOverlayView().dispatchDraw(canvas);
            }

            // Step 6, draw decorations (foreground, scrollbars)
            onDrawForeground(canvas);

            // Step 7, draw the default focus highlight
            drawDefaultFocusHighlight(canvas);

            if (debugDraw()) {
                debugDrawFocus(canvas);
            }

            // we're done...
            return;
}

如果View是ViewGroup,其重写了dispatchDraw()方法。
在dispatchDraw()里遍历其子view,调用子view的draw()方法绘制自身。

总结绘制过程:
1.绘制背景drawBackground(canvas)
2.绘制自己onDraw(canvas)
3.绘制子view dispatchDraw(canvas) -->如果是ViewGroup,子view该方法为空
4.绘制前景、滚动条等装饰onDrawForeground(canvas)

额外知识、Android系统UI卡顿原理及VSync信号机制

1、卡顿原因分析及常见解决方式

1.过度绘制
去除不必要的背景色;

布局视图扁平化:避免过度嵌套布局,每次测量都需要测量父布局、子布局的所有位置,尽量采取扁平布局,例如ConstrainLayout,减少ReletiveLayout、LinearLayout嵌套布局。

减少透明色的使用;

2.UI线程里复杂运算

3.频繁GC
尽可能减少在for循环里new对象;减少在onDraw里new对象
尽量不要在循环中大量使用局部变量。

2、VSync机制

1.概念

1.屏幕刷新率
2.帧率 FPS
3.VSync
屏幕产生的硬件VSync
由SurfaceFlinger将其转换成软件VSync信号

2.VSync的作用

Vertical Synchronization 垂直同步的缩写
主要是为了解决“Tearing”撕裂的现象
同步UI绘制和动画,是的可以达到60fps的固定帧率。

VSync工作原理示意图 双重缓存模型

GPU计算结果放到Buffer里,屏幕从另一个Buffer里取数据。在VSync信号触发交换读写缓存。

三重缓存模型

3、Choreographer机制

三、高级绘制:Paint/Canvas/Path详解

1、Paint详解

概念:画笔,保存了绘制几何图形、文本和位图的样式和颜色信息。
(1)常用API:


Paint常用API Paint.setStrokCap()效果 Paint.setStrokeJoin()效果 setFilterBitmap()设置双线性过滤 字体的度量
//字体的度量,paint.getFontMetrics()
    public static class FontMetrics {
        /**
         * The maximum distance above the baseline for the tallest glyph in
         * the font at a given text size.
         */
        public float   top;
        /**
         * The recommended distance above the baseline for singled spaced text.
         */
        public float   ascent;
        /**
         * The recommended distance below the baseline for singled spaced text.
         */
        public float   descent;
        /**
         * The maximum distance below the baseline for the lowest glyph in
         * the font at a given text size.
         */
        public float   bottom;
        /**
         * The recommended additional space to add between lines of text.
         */
        public float   leading;
    }

(2)颜色相关


    private void setColor(){
        mPaint = new Paint();
        mPaint.setColor(Color.RED);   //设置颜色,16进制数值,0xFFFF0000
        mPaint.setARGB(0,0,0,0); //分别表示透明度,RGB三原色,0~255数值
        Shader shader = new Shader();
        //一般由以下几种着色器
        shader = new LinearGradient(); 
        shader = new RadialGradient();
        shader = new SweepGradient();
        shader = new BitmapShader();
        shader = new ComposeShader();
        mPaint.setShader(shader);   //着色器
        //
    }

1.线性着色器:

//float x0, float y0, float x1, float y1, @NonNull @ColorInt int colors[],@Nullable float positions[], @NonNull TileMode tile
//colors[]颜色数组
// positions[]数值范围[0,1],指定某个位置的颜色值,个数应该和colors[]个数一样,否则报错。默认为null,线性渐变。
mShader = new LinearGradient(0,0,500,500,new int[]{Color.RED,Color.BLUE},null, Shader.TileMode.CLAMP);
线性着色器效果

2.环形渲染


        //RadialGradient()构造方法:
        //float centerX, float centerY, float radius,
        //            @NonNull @ColorInt int colors[], @Nullable float stops[],
        //            @NonNull TileMode tileMode

        //float centerX, float centerY, float radius,
        //            @ColorInt int centerColor, @ColorInt int edgeColor, @NonNull TileMode tileMode


        mShader = new RadialGradient(250,250,250,new int[]{Color.GREEN,Color.YELLOW,Color.RED},null, Shader.TileMode.CLAMP);
        
环形渲染

3.扫描渲染

        //SweepGradient()构造方法:
        //float cx, float cy, @NonNull @ColorInt int colors[], @Nullable float positions[]
        //float cx, float cy, @ColorInt int color0, @ColorInt int color1

mShader  = new SweepGradient(250,250,Color.RED,Color.GREEN);

扫描渲染

4.位图渲染


        mBitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.liuyifei);
        mShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);

...

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawRect(0,0,mBitmap.getWidth(),mBitmap.getHeight(),mPaint);
    }


位图渲染

不同Shader.TileMode

// draw的区域超过shader的大小时,如何绘制。有以下三种绘制方法:
    public enum TileMode {
        /**
         * replicate the edge color if the shader draws outside of its
         * original bounds
         */
        CLAMP   (0),
        /**
         * repeat the shader's image horizontally and vertically
         */
        REPEAT  (1),
        /**
         * repeat the shader's image horizontally and vertically, alternating
         * mirror images so that adjacent images always seam
         */
        MIRROR  (2);
    
        TileMode(int nativeInt) {
            this.nativeInt = nativeInt;
        }
        final int nativeInt;
    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawRect(0,0,mBitmap.getWidth()*1.5f,mBitmap.getHeight()*1.5f,mPaint);
    }
TileMode.CLAMP TileMode.MIRROR TileMode.REPEAT

5.组合渲染



         //ComposeShader()的构造方法:
        //@NonNull Shader shaderA, @NonNull Shader shaderB, @NonNull PorterDuff.Mode mode
        //@NonNull Shader shaderA, @NonNull Shader shaderB, @NonNull Xfermode mode

        mBitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.liuyifei);
        BitmapShader bitmapShader = new BitmapShader(mBitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
        LinearGradient linearGradient = new LinearGradient(0,0,500,500,new int[]{Color.RED,Color.BLUE,Color.GREEN},null, Shader.TileMode.CLAMP);

        mShader = new ComposeShader(bitmapShader,linearGradient, PorterDuff.Mode.MULTIPLY);

组合渲染

其中PorterDuff.Mode是组合渲染中两个Shader进行混合的规则,PorterDuff.Mode.MULTIPLY是相乘。

2、利用Paint绘制滤镜Xfermode

PorterDuff.Mode图层混合模式
一共有18种模式。

//有三个地方用到图层混合
//1、ComposeShader
//2、mPaint.setXfermode
//3、PorterDuffColorFilter
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
        mShader = new ComposeShader(bitmapShader,linearGradient, new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
        mPaint.setShader(mShader);
        //由于某些图层混合在硬件加速下不能用
        //所以需要禁止硬件加速
        setLayerType(View.LAYER_TYPE_SOFTWARE,null);

相关文章

  • Android 高级UI 目录

    Android 高级UI开发 目录 Android 高级UI1 Material Design概述Android ...

  • 高级UI和初级UI的区别

    几张简单的图片对比了初级UI与高级UI在工作态度和工作方式的差异, 向大家阐明了初级UI与高级UI之间的差距。 值...

  • 为何他是资深设计师,你却只能是新手设计师?这五点必看

    几张简单的图片对比了初级UI与高级UI在工作态度和工作方式的差异, 向大家阐明了初级UI与高级UI之间的差距。 值...

  • 高级UI

    一、Android 布局添加流程 二、View的绘制流程 1、view绘制流程 2、具体3大绘制过程 1.测量过程...

  • Android 高级UI6 高级渲染

    Android 高级UI 目录Paint 画笔的高级技能渲染 Shader:BitmapShader位图的图象渲染...

  • UI高级组件

    事件响应 子视图如果绑定了事件即优先级最高 如果没有则触发父视图的事件 子视图接收到了事件后可以放弃事件响应 触发...

  • UICollectionView嵌套

    场景 UICollectionView是继UITableView后的高级视图,可用来搭建复杂的UI.很多复杂的UI...

  • 源码分析_Android UI何时刷新_Choreographe

    @(Android源码解析)高级UI系列:setContentView源码分析_看AppCompatActivit...

  • Android高级开发

    一:高级UI 自定义控件 UI绘制流程 绘图 特效 事件传递机制 事件冲突 Material Design 兼容s...

  • 与高级初级ui高效沟通

    与我合作过的ui设计师粗略算下来有7个,能明显感受到高级与初级的区别。最大的区别是高级ui更能理解并表达产品要传达...

网友评论

      本文标题:高级UI

      本文链接:https://www.haomeiwen.com/subject/lwakbctx.html