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