俄罗斯贵宾会-俄罗斯贵宾会官网
做最好的网站

俄罗斯贵宾会R语言grid包just参数如何just图形位置

代码

library(grid)

grid.newpage()  # new page
pushViewport(viewport(layout = grid.layout(2,2))) # 2 *2 layout
# just top
pushViewport(viewport(layout.pos.col = 1, layout.pos.row = 1))
grid.rect()
r1 <- rectGrob(0.5, 0.5, width = 0.2, height = 0.2, name = "r1")
r2 <- rectGrob(0.5, 0.5, width = 0.2, height = 0.2, just = c("top"),gp=gpar(col="blue"), name = "r2")
grid.draw(r1)
grid.draw(r2)
grid.segments(0.5,0.5,grobX(r2, 90), grobY(r2, 0), arrow=arrow(angle=15, type="closed"), gp=gpar(fill="black"))
grid.text("just: top" ,0.6, 0.8)
upViewport()
# just left and top
pushViewport(viewport(layout.pos.col = 1, layout.pos.row = 2))
grid.rect()
r1 <- rectGrob(0.5, 0.5, width = 0.2, height = 0.2, name="r1")
r2 <- rectGrob(0.5, 0.5, width = 0.2, height = 0.2, just = c("left", "top"), gp=gpar(col="blue"), name="r2")
grid.draw(r1)
grid.draw(r2)
grid.segments(0.5, 0.5, grobX(r2, 90), grobY(r2, 0), arrow=arrow(angle=15, type="closed",), gp=gpar(fill="black"))
grid.text("just: left and top", 0.6, 0.8)
upViewport()
# just left and bottom
pushViewport(viewport(layout.pos.col = 2, layout.pos.row = 1))
grid.rect()
r1 <- rectGrob(0.5, 0.5, width = 0.2, height = 0.2, name="r1")
r2 <- rectGrob(0.5, 0.5, width = 0.2, height = 0.2, just = c("left", "bottom"), gp=gpar(col="blue"), name="r2")
grid.draw(r1)
grid.draw(r2)
grid.segments(0.5, 0.5,grobX(r2, 90), grobY(r2, 0), arrow=arrow(angle=15, type="closed",), gp=gpar(fill="black"))
grid.text("just: left and bottom", 0.6, 0.8)
upViewport()
# just right bottom
pushViewport(viewport(layout.pos.col = 2, layout.pos.row = 2))
grid.rect()
r1 <- rectGrob(0.5, 0.5, width = 0.2, height = 0.2, name="r1")
r2 <- rectGrob(0.5, 0.5, width = 0.2, height = 0.2, just = c("right", "bottom"), gp=gpar(col="blue"), name = "r2")
grid.draw(r1)
grid.draw(r2)
grid.segments(0.5,0.5,grobX(r2, 90), grobY(r2, 0), arrow=arrow(angle=15, type="closed",), gp=gpar(fill="black"))
grid.text("just: right and bottom", 0.6, 0.8)
upViewport()

自定义view首先要自定义属性:

在values下面创建attrs.xml:

    <!--画图板-->
    <declare-styleable name="DrawImg">
        <attr name="PaintColor" />            //画笔颜色
        <attr name="PaintWidth" />           // 画笔宽度
        <attr name="CanvasImg" />           //画板图片
    </declare-styleable>

    <!--指定单位-->
    <attr name="PaintColor" format="color" />        
    <attr name="PaintWidth" format="dimension" />          
    <attr name="CanvasImg" format="reference" />          

对于下面3行指定单位的代码可以放出来,可以让多个自定义view 都能使用。

思路

  grid的画图函数都含有just,但是just参数的是怎么调节图形位置的总是让人非常费解,于是便写了代码来一探究竟。
  思路非常简单:放一个2*2的布局viewport,每个布局里面放一个viewport,每个viewport都用了不同的just参数。just之后的矩形用蓝色显示,中心点的移动用箭头表示出来, 这样每个参数对应图形怎么移动的都能一目了然。从以下的代码也能学到如何安排布局, 如何使用grobX和grobY获得grob对象的坐标, 如何进行基本的viewport切换等。

本文重在对自定义view,以及其常用类,常用方法的初步了解,提供一个思路,效果是其次,画板只是例子。

结果

俄罗斯贵宾会 1

顺带还有一个刮刮卡效果,只需要改一个参数:

结论

  • just参数对图形进行相反的调节,比如想向上调节图形,就得调节just="bottom",也可以理解为真实位置相对于画图位置,比如真实位置要比画图位置要低,就用just="bottom“
  • grobX角度为90时, grobY 角度为0时,可获得图形的中心位置, grobX 为0时X位置在图形的最右, grobY 为0时Y位置在图形的中间

重写自定义view关键方法onMeasure(),onDraw()。onMeasure()用来指定这个自定义view 的大小,onDraw()用来进行实时绘图

  • 最重要的3个东西:画布Canvas,画笔Paint,路径Path
  • 看代码中的注释,超级详细,把需要注意的提出来

在newPaint()方法中,paint有一个setXfermode()方法,这个表示图形混合方式,有18种 (比下图多了ADD和OVERLAY)。给张图看一下。这里我们用到2种 SRC_IN和 DST_OUT。

  • SRC_IN:取两层交集部分,显示上层
  • DST_OUT:取两层非交集部分,显示下层
    说实话这么说也很难懂,还是要自己动手试一试,不过这里只要知道:
    使用SRC_IN就会有一个画图板的效果
    使用DST_OUT就会有一个刮刮卡的效果

俄罗斯贵宾会 2

绘制方式.jpg

    /**
     * onMeasure常见方法
     * 1)  getChildCount():获取子View的数量;
     * 2)  getChildAt(i):获取第i个子控件;
     * 3)  subView.getLayoutParams().width/height:设置或获取子控件的宽或高;
     * 4)  measureChild(child, widthMeasureSpec, heightMeasureSpec):测量子View的宽高;
     * 5)  child.getMeasuredHeight/width():执行完measureChild()方法后就可以通过这种方式获取子View的宽高值;
     * 6)  getPaddingLeft/Right/Top/Bottom():获取控件的四周内边距;
     * 7)  setMeasuredDimension(width, height):重新设置控件的宽高。如果写了这句代码,就需要删除
     * “super. onMeasure(widthMeasureSpec, heightMeasureSpec);”这行代码。
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        /**
         *  getMode获取测量模式(下面3种) 和 getSize获取测量值
         *
         *  EXACTLY:当宽高值设置为具体值时使用,如100dp、match_parent等,此时取出的size是精确的尺寸;
         *  AT_MOST:当宽高值设置为wrap_content时使用,此时取出的size是控件最大可获得的空间;
         *  UNSPECIFIED:当没有指定宽高值时使用(很少见)。
         *
         * */
        //测量模式_宽
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        //测量模式_高
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        //宽度
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        //高度
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        //设置view宽度
        //如果布局中给出了准确的宽度,直接使用宽度,否则设置图片宽度为view宽度
        if (widthMode == MeasureSpec.EXACTLY) {
            width = widthSize;
        } else {
            if (hasCanvasImg != -1) {
                //如果设置了图片,使用图片宽
                width = bitmap.getWidth();
            } else {
                //没有设置图片并且也没给准确的view宽高  设置一个宽默认值
                width = 500;
            }
        }
        //设置view高度同上
        if (heightMode == MeasureSpec.EXACTLY) {
            height = heightSize;
        } else {
            if (hasCanvasImg != -1) {
                height = bitmap.getHeight();
            } else {
                height = 500;
            }
        }
        //重新设置view的宽高
        setMeasuredDimension(width, height);

        //设置画布以及画笔
        newPaint();
    }
    private void newPaint() {
        //根据参数创建一个新的bitmap  最后一个参数为为储存形式
        newBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        //保存bitmap中所有像素点的数组  
        bmPixels = new int[newBitmap.getWidth() * newBitmap.getHeight()];
        //new带参的Canvas,其中的bitmap参数 必须通过createBitmap得到;
        //否则会报错:IllegalStateException : Immutable bitmap passed to Canvas constructor
        canvas = new Canvas(newBitmap);
        if (hasCanvasImg == -1) {
            //如果没有设置图片,则默认用灰色覆盖
            canvas.drawColor(Color.GRAY);
        } else {
            //把设置的图片缩放到view大小
            bitmap = zoomBitmap(this.bitmap, width, height);
            canvas.drawBitmap(bitmap, 0, 0, null);
        }
        // 准备绘制刮卡线条的画笔
        paint = new Paint();
        paint.setColor(paintColor);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(paintWidth);
        //设置是否使用抗锯齿功能,抗锯齿功能会消耗较大资源,绘制图形的速度会减慢
        paint.setAntiAlias(true);
        //设置是否使用图像抖动处理,会使图像颜色更加平滑饱满,更加清晰
        paint.setDither(true);
        //当设置画笔样式为STROKE或FILL_OR_STROKE时,设置笔刷的图形样式
        paint.setStrokeCap(Paint.Cap.ROUND);
        //设置绘制时各图形的结合方式
        paint.setStrokeJoin(Paint.Join.ROUND);
        //设置图形重叠时的处理方式
        /**
         * SRC_IN:取两层绘制交集。显示上层
         */
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
    }

    //这个onDraw方法只有一句代码,意思是在手指移动的同时把画板图片绘制出来
    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawBitmap(newBitmap, 0, 0, null);
        super.onDraw(canvas);
    }

    //将指定图片缩放到指定宽高,返回新的图片Bitmap对象
    public static Bitmap zoomBitmap(Bitmap bm, int newWidth, int newHeight) {
        // 获得图片的宽高
        int width = bm.getWidth();
        int height = bm.getHeight();
        // 计算缩放比例
        float scaleWidth = ((float) newWidth) / width;
        float scaleHeight = ((float) newHeight) / height;
        // 取得想要缩放的matrix参数
        Matrix matrix = new Matrix();
        matrix.postScale(scaleWidth, scaleHeight);
        // 得到新的图片
        return Bitmap.createBitmap(bm, 0, 0, width, height, matrix, true);
    }
  • 这是一堆对于这个view来说比较复杂的代码,但是功能很简单,我们做了2件事:
    1.通过MeasureSpec.getMode(测量模式),计算出整个控件的宽高
    2.通过canvas.drawBitmap在画布上画出bitmap,同时 new 出画笔 Paint 给它设置颜色,粗细等属性
  • 注意:
    1.onDraw()方法在每次调用invalidate(),或者视图变化时都会重走,所以不能在里面 new 东西.
    2.有一个int[]类型的数组 bmPixels,这里大概说一下是个什么意思,具体的解释在Bitmap类getPixels和createBitmap方法详解中有说道。
    bmPixels: 我们通过bitmap的宽度乘以高度,可以的到一个int[]类型的数组,这个数组就是组成bitmap的所有像素点,某一个像素点为0的时候就说明他是没有颜色,!0就说明是有颜色的。

既然是画图,那肯定要监听手指移动,onTouchEvent()方法:

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int currX = (int) event.getX();
        int currY = (int) event.getY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                //按下时,设置线条的起始点准备绘制
                path.moveTo(currX, currY);
                break;
            case MotionEvent.ACTION_MOVE:
                //滑动时,绘制路径
                path.lineTo(currX, currY);
                break;
            case MotionEvent.ACTION_UP:
        }
        // 绘制线条,请求重绘整个控件
        canvas.drawPath(path, paint);
        //请求View树进行重绘,即draw()方法,如果视图的大小发生了变化,还会调用layout()方法。
        invalidate();
        return true;
    }

这个就很简单,手指按下时记录位置,path.moveTo给path设置起始点位置,移动时通过path.lineTo()方法记录路径,同时使用 canvas.drawPath(path, paint)直接绘制出来,invalidate()通知视图更新。

看效果:
中间一个画图板
上方小控件用来显示实时画出的图形
下方小控件用来做一些画图的控制
2个小控件都能移动

本文由俄罗斯贵宾会发布于编程,转载请注明出处:俄罗斯贵宾会R语言grid包just参数如何just图形位置

您可能还会对下面的文章感兴趣: