android canvas中rotate()和translate()两个方法详解

rotate()和translate()

1.看到这个题目的时候,有人会觉得这不就是一个对画布的旋转和平移的嘛,但是其中的细节的地方还是需要深究一下的。

例如:有个需求将TextView的文字竖直显示

  首先想到的方法就是将画布旋转90度,代码如下:

 1 public class RotateTextView extends TextView {
 2     public RotateTextView(Context context) {
 3         super(context);
 4     }
 5 
 6     public RotateTextView(Context context, AttributeSet attrs) {
 7         super(context, attrs);
 8     }
 9 
10     public RotateTextView(Context context, AttributeSet attrs, int defStyle) {
11         super(context, attrs, defStyle);
12     }
13 
14     @Override
15     protected void onDraw(Canvas canvas) {
16         canvas.rotate(90);
17         super.onDraw(canvas);
18     }
19 
20 }

在利用这个自定义的View

 1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     xmlns:tools="http://schemas.android.com/tools"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent"
 5     android:orientation="vertical"
 6     tools:context=".MainActivity" >
 7 
 8     <com.example.verticleseekbar.RotateTextView
 9         android:id="@+id/rotate"
10         android:layout_width="wrap_content"
11         android:layout_height="100dip" >
12     </com.example.verticleseekbar.RotateTextView>
13 
14 </LinearLayout>

运行后的显示是:

什么内容都没有。

查找相关资料后发现后引用别人的一段话:

这里先来插上一句我自己的体会,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数值都为正的那个区间里面的,

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

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

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

 

 

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 public class MyTextView extends TextView {
 2    
 3     public MyTextView(Context context, AttributeSet attrs) {
 4         super(context, attrs);
 5     }
 6    
 7     @Override
 8     protected void onDraw(Canvas canvas) {
 9         canvas.rotate(-90);
10         canvas.translate(-getHeight(), 0);
11         super.onDraw(canvas);
12     }
13 }

 

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

 

结果如下:

在左下方显示出了我们想要的竖直TextView。

现在附上一个完整的demo:

RoateTextView:

 1 public class RotateTextView extends TextView {
 2     public RotateTextView(Context context) {
 3         super(context);
 4     }
 5 
 6     public RotateTextView(Context context, AttributeSet attrs) {
 7         super(context, attrs);
 8     }
 9 
10     public RotateTextView(Context context, AttributeSet attrs, int defStyle) {
11         super(context, attrs, defStyle);
12     }
13 
14     @Override
15     protected void onDraw(Canvas canvas) {
16         canvas.rotate(90);
17 
18         canvas.translate( 0,-getWidth());
19         super.onDraw(canvas);
20     }
21 
22 }

 

MainActivity:

1 public class MainActivity extends Activity {
2 
3     @Override
4     protected void onCreate(Bundle savedInstanceState) {
5         super.onCreate(savedInstanceState);
6         setContentView(R.layout.activity_main);
7     }
8 
9 }

 

activity_main.xml:

 1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     xmlns:tools="http://schemas.android.com/tools"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent"
 5     android:orientation="vertical"
 6     tools:context=".MainActivity" >
 7 
 8     <Button
 9         android:id="@+id/btn"
10         android:layout_width="wrap_content"
11         android:layout_height="wrap_content"
12         android:text="占一个位置" />
13 
14     <LinearLayout
15         android:layout_width="match_parent"
16         android:layout_height="wrap_content"
17         android:background="#FFB6C1"
18         android:orientation="horizontal" >
19 
20         <com.example.verticleseekbar.RotateTextView
21             android:id="@+id/rotate"
22             android:layout_width="wrap_content"
23             android:layout_height="100dip"
24             android:text="测试文字" />
25     </LinearLayout>
26 
27     <com.example.verticleseekbar.RotateTextView
28         android:id="@+id/rotate"
29         android:layout_width="wrap_content"
30         android:layout_height="100dip"
31         android:text="测试文字" 
32         android:layout_marginLeft="150dp"
33         />
34 
35 </LinearLayout>

 

运行后的效果是:

相关知识参考地址:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2013/0304/957.html

posted @ 2014-11-27 11:32  perfect亮  阅读(5712)  评论(0编辑  收藏  举报