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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM