Android Canvas编程:对rotate()和translate()两个方法的研究

(转载)http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2013/0304/957.html

编辑推荐:稀土掘金,这是一个针对技术开发者的一个应用,你可以在掘金上获取最新最优质的技术干货,不仅仅是Android知识、前端、后端以至于产品和设计都有涉猎,想成为全栈工程师的朋友不要错过!

首先我们来看这样一个需求:显示一个竖向显示的TextView。说白了,就是把我们日常使用的TextView让丫的旋转90度。

怎么样?是不是很多人会说这有什么难得嘛,不就是用canvas让丫的旋转90度嘛。

别急,我们一点点引申。

对于很多没有接触过太多游戏开发的android程序员或者接触应用开发不久的程序员(我这样的)来说,或许都听过canvas这个东西,

也都知道这个东西有一个rotate()方法,也知道这个方法可”好像“以让”画布“旋转。

好的,我们先跟着上面的思路来走一下,看一看。

看下面的代码:

1
2
3
4
5
6
7
8
9
10
11
12
public class MyTextView extends TextView {
   
     public MyTextView(Context context, AttributeSet attrs) {
         super (context, attrs);
     }
   
     @Override
     protected void onDraw(Canvas canvas) {
         canvas.rotate(-90);
         super .onDraw(canvas);
     }
}

看起来好像是我们在绘制TextView之前把画布逆时针旋转了90度是么?那么是不是说我们得到的就是一个竖向的TextView了呢?

布局文件很简单:

1
2
3
4
5
6
7
8
9
10
11
12
<?xml version= "1.0" encoding= "utf-8" ?>
<LinearLayout xmlns:android= "http://schemas.android.com/apk/res/android"
     android:layout_width= "fill_parent"
     android:layout_height= "fill_parent"
     android:orientation= "vertical" >
       
     <com.carrey.demo.myTextView.MyTextView 
         android:layout_width= "wrap_content"
         android:layout_height= "100dip"
         android:text= "测试文字" />
   
</LinearLayout>

测试结果如下:


没错,什么都没看见,“似乎”没画出什么东西。

我开始的时候被这个问题困惑了很久,在网上查了很多资料,也没有想明白为什么会这样,因为稍早一些看过一本有点小名气的牛人专家写的

一本关于游戏开发的书里面介绍rotate(float degrees)这个方法的时候说:这个方法默认的旋转画布的旋转中心是屏幕的中心,一直都

按照这个思路来思考,后来才发现书里说的是错的。(这里也没别的意思,但是牛人也会犯错,不能尽信书,要多方面思考尝试)

这里我可以很肯定的告诉大家rotate(float degrees)这个方法的旋转中心是坐标的原点,在这个例子里就是屏幕的左上角了,怎么样是不是明白

过来为什么会什么都没有显示出来了呢?

这里先来插上一句我自己的体会,canvas的这个rotate方法不管是一个参数还是三个参数的那个,从字面上来看旋转的是“画布”,但是我们最好是

理解成旋转的是画布的坐标轴。好的我们继续向下,按照我们上面的那个例子,我们在旋转之前的屏幕坐标系如下:


按照我们之前的结论,rotate(float degrees)这个方法旋转的是画布的坐标轴,-90度是逆时针旋转(90是顺时针旋转),旋转之后的坐标轴状况

如下所示:


这里来做一下解释,“画控件的画布的区域”的意思就是我们在main.xml中添加一个空间的时候不是要设置layout_widths和layout_height这两个属性么?这里的这个

layout_widths和layout_height组成的矩形就是我们的这个“画控件的画布的区域”,当然,这个区域的左上角原点的位置在main.xml中对应的那个位置,就要按照其

所在的ViewGroup来决定了,比如这个控件在LinearLayout里面,那么就看LinearLayout的orientation是vertical?还是horizontal?,如果这个控件在RelativeLayout

里面,那么就看这个控件他在父容器的左边?右边?等等。。。这样就能确定“画控件的画布”的左上角的那个原点在布局文件中的位置了。

“旋转坐标系之后画控件的实际区域”,就是我们旋转后的坐标系的x,y轴正向的交集的区域,不管坐标系怎么转,我们的控件都是画在x,y数值都为正的那个区间里面的,

通过上面的那个图,可以看出坐标系旋转之后,实际画控件的区域并没有画布,所以也就画不出什么来了,因此我们的程序结果就什么都没有画出来了。

这里可能有人会说了,你怎么知道没画出来?这个例子里面的画控件的画布区域的原点和屏幕的原点是重合的,或许我们的控件画在了屏幕区域的外面只是没有看到

罢了。

对这种情况我们做一个验证,将main.xml修改如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version= "1.0" encoding= "utf-8" ?>
<RelativeLayout xmlns:android= "http://schemas.android.com/apk/res/android"
     android:layout_width= "fill_parent"
     android:layout_height= "fill_parent"
     android:orientation= "vertical" >
       
     <com.carrey.demo.myTextView.MyTextView 
         android:layout_width= "wrap_content"
         android:layout_height= "100dip"
         android:text= "测试文字"
         android:layout_alignParentBottom= "true"
         />
   
</RelativeLayout>

运行结果如下:

怎么样?什么都没画出来,所以我们的结论是正确的,我们自定义的控件没有画在任何一张可以看见的画布上。

接下来问题就是:我们如何实现一个竖直的TextView呢?

我们按照前面的思路来思考:

按照前面我们得到的结论,我们要把控件画到画布上面,就要让我们的坐标系的x,y正向区域在”画控件的画布区域“上。

这里,我们就要用到canvas的translate(float dx,float dy)这个方法了,关于这个方法的作用,我研究的时候看了网上不少资料,发现有一些人的理解

是错误的,我也被引导的走了不少弯路。这个方法的作用就是移动我们画图的坐标系的原点,比如我们现在的原点是(0,0),然后我们调用canvas(-1,-1),

我们的原点x,y坐标就会分别变化-1,变化之后的原点就是(-1,-1)了。

那么回头来看我们上面的例子,我们希望变化我们的坐标系,让”画控件的画布的区域“处在x,y轴的正向区域中,这样我们就能把我们的控件画在画布上了,

示意图如下:

也就是说,我们只要让原点的位置向下移动”画控件的画布的区域“的高度就可以了,在代码中体现就是:

canvas.translate(-getHeight(),0);

这里的getHeight()获得的数值就是我们在main.xml中为我们的控件分配的layout_height有关,要注意的是我们要给layout_height分配一个确定值或者fill_parent

所谓确定值就是100dip这种值,如果我们用wrap_content,返回的getHeight()是很小的,我测试的结果是19,这个高度不能显示很多内容的,用兴趣的朋友可以

试一下。

我们把代码修改如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class MyTextView extends TextView {
   
     public MyTextView(Context context, AttributeSet attrs) {
         super (context, attrs);
     }
   
     @Override
     protected void onDraw(Canvas canvas) {
         canvas.rotate(-90);
         canvas.translate(-getHeight(), 0);
         super .onDraw(canvas);
     }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version= "1.0" encoding= "utf-8" ?>
<RelativeLayout xmlns:android= "http://schemas.android.com/apk/res/android"
     android:layout_width= "fill_parent"
     android:layout_height= "fill_parent"
     android:orientation= "vertical" >
       
     <com.carrey.demo.myTextView.MyTextView 
         android:layout_width= "wrap_content"
         android:layout_height= "100dip"
         android:text= "测试文字"
         android:layout_alignParentBottom= "true"
         />
   
</RelativeLayout>

结果如下:

在左下方显示出了我们想要的竖直TextView,怎么样?是不是很简单?


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值