2010-08-09 230 views
33

我正在研究FrameLayout的子類,它應該將其所有子級旋轉90度。我這樣做是爲了克服android 2.1及其以下版本中的風景相機限制,通過讓活動處於橫向模式,但將相機覆蓋層放入此framelayout覆蓋層,使其看起來好像是縱向(this is how Layar does it)。完成這個,我正在修改Jeff Sharkey's code來旋轉視圖。我的問題是我可以旋轉Framelayout,但我無法調整它的大小來匹配新的尺寸。所以在我的g1上,取代了橫向480x320相機視圖上的320x480縱向視圖,在中間顯示了一個320x320的盒子,顯示了我的肖像視圖,並且兩邊被切掉了。旋轉視圖層次結構90度

這是到目前爲止我的代碼:

public class RotateLayout extends FrameLayout { 
    private Matrix mForward = new Matrix(); 
    private Matrix mReverse = new Matrix(); 
    private float[] mTemp = new float[2]; 

    public RotateLayout(Context context) { 
     super(context); 
    } 

    public RotateLayout(Context context, AttributeSet attrs) { 
     super(context, attrs); 

    } 


    /* (non-Javadoc) 
    * @see android.widget.FrameLayout#onMeasure(int, int) 
    */ 
    @Override 
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
     super.onMeasure(widthMeasureSpec, heightMeasureSpec); 
     //This didn't work: 
     //super.onMeasure(heightMeasureSpec, widthMeasureSpec); 
    } 

    /* (non-Javadoc) 
    * @see android.widget.FrameLayout#onSizeChanged(int, int, int, int) 
    */ 
    @Override 
    protected void onSizeChanged(int w, int h, int oldw, int oldh) { 
     super.onSizeChanged(w, h, oldw, oldh); 
    } 

    @Override 
    protected void dispatchDraw(Canvas canvas) { 
     canvas.rotate(270, getWidth()/2, getHeight()/2); 
     //This code will stretch the canvas to accommodate the new screen size. This is not what I want. 
     //float scaleX=(float)getHeight()/getWidth(); 
     //float scaleY=(float)getWidth()/getHeight(); 
     //canvas.scale(scaleX, scaleY, getWidth()/2, getHeight()/2); 
     mForward = canvas.getMatrix(); 
     mForward.invert(mReverse); 
     canvas.save(); 
     canvas.setMatrix(mForward); //This is the matrix we need to use for proper positioning of touch events 
     super.dispatchDraw(canvas); 
     canvas.restore(); 
    } 

    @Override 
    public boolean dispatchTouchEvent(MotionEvent event) { 
     final float[] temp = mTemp; 
     temp[0] = event.getX(); 
     temp[1] = event.getY(); 

     mReverse.mapPoints(temp); 

     event.setLocation(temp[0], temp[1]); 
     return super.dispatchTouchEvent(event); 
    } 
} 

我試圖重寫OnMeasure切換X和查看的Y尺寸,但一直沒能得到那個工作。 任何幫助,您可以提供非常感謝。

+0

嗨,你有沒有解決這個問題? – fhucho 2010-09-05 13:41:55

+0

不 - 最終的解決方案是按原樣使用上述代碼,並通過將各個按鈕包裝在其中之一中來單獨旋轉按鈕,文本瀏覽等。這不是很優雅,但它的作品。 – QRohlf 2010-09-06 22:50:51

+2

我相信'dispatchTouchEvent()'裏面應該使用getRawX()和getRawY()來代替getX()和getY()。無論如何,這對我來說效果更好。我的觀點是方形的,fww。 – 2011-04-27 23:21:40

回答

39

我有同樣的問題,並設法解決它。 而不是手動旋轉每個視圖或佈局,我使用了一個LayoutAnimationController。

首先將文件/ RES /動畫/被叫rotation.xml

<?xml version="1.0" encoding="utf-8"?> 
<rotate 
xmlns:android="http://schemas.android.com/apk/res/android" 
    android:fromDegrees="0" 
    android:toDegrees="-90" 
    android:pivotX="50%" 
    android:pivotY="50%" 
    android:duration="0" android:fillAfter="true"> 
</rotate> 

然後,在你活動的onCreate,做

@Override 
    public void onCreate(Bundle icicle) { 
    super.onCreate(icicle); 

    setContentView(R.layout.myscreen); 

    Animation rotateAnim = AnimationUtils.loadAnimation(this, R.anim.rotation); 
    LayoutAnimationController animController = new LayoutAnimationController(rotateAnim, 0); 
    FrameLayout layout = (FrameLayout)findViewById(R.id.MyScreen_ContentLayout); 
    layout.setLayoutAnimation(animController); 
} 

如果你想旋轉,上面躺元素您的相機預覽視圖(SurfaceHolder),只需將一個FrameLayout放置在SurfaceHolder上方,將所有元素放置在該FrameLayout中並調用佈局「MyScreen_ContentLayout」。完成。

希望幫助別人,讓我花了相當長的時間把所有的東西放在一起。

+0

這是一個有趣的解決方案。我遇到的唯一問題是旋轉的佈局不能展開。舉例來說,如果您的佈局有2張圖片 - 其中1張位於屏幕的最上方,1張位於最底部。旋轉佈局後,兩幅圖像之間的距離將保持不變 - 而不是擴大到旋轉視圖的頂部/底部,它們將位於中間的某處。 – 2011-02-01 01:10:12

+0

感謝您的想法/可以說更多的細節「只需在SurfaceHolder上方放置一個FrameLayout」我該怎麼做? – LTEHUB 2011-04-11 13:04:38

+1

在您的佈局xml文件中,創建一個框架佈局並將它放置在水平面之上(框架佈局完全覆蓋了水邊框)。 – Georg 2011-04-14 15:34:36

0

我想你在onMeasure中忘了一行。

@Override 
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
    super.onMeasure(heightMeasureSpec, widthMeasureSpec); 
    setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth()); 
} 

從代碼兩者這裏垂直搜索條: How can I get a working vertical SeekBar in Android?

您可能需要與getMeasuredHeight()擺弄,使其屏幕的正確尺寸。

6

使用API​​級別11及更高版本,您可以使用方法setRotation(degreesFloat);以編程方式更改視圖的旋轉角度,也可以使用XML屬性android:rotation=""在XML中對其進行更改。還有一些方法/屬性僅用於更改視圖旋轉的X或Y值:Android Docs - View (setRotation)

因此,只要您使用的API級別爲11或以上,您應該可以將旋轉應用到包裝佈局節點。但是,您可能還必須更改頂層佈局的尺寸以匹配旋轉後所需的尺寸。即如果您有一個尺寸爲800x1280的縱向視圖,您必須將它們更改爲1280x800,以便在旋轉到橫向後排列它們。

0

嘗試關閉兒童裁剪視圖根:你的RotateLayout的父母和你的RotateLayout的onMeasure方法調用setClipChildren(false)把這幾行:

super.onMeasure(heightMeasureSpec, widthMeasureSpec); 
setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth()); 

我有基本相同的問題,因爲你和我仍然沒有測試過我的解決方案 - 我明天會做,並告訴它是否正常工作。

+0

看起來'setClipChildren(false)'不起作用。我想知道爲什麼... – DoDo 2013-05-31 09:51:58

1

這是什麼,一般爲我工作。

private void init() { 
    setRotation(90f); 
} 

public YourViewOrViewGroup(final Context context) { 
    super(context); 
    init(); 
} 

... (all the View/ViewGroup constructors) ... 

@Override 
protected void onLayout(final boolean changed, final int l, final int t, final int r, final int b) { 
    super.onLayout(changed, l, t, r, b); 

    final int width = getWidth(); 
    final int height = getHeight(); 
    final int offset = Math.abs(width - height)/2; 
    setTranslationX(-offset); 
    setTranslationY(offset); 
} 

@Override 
protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) { 
    super.onMeasure(heightMeasureSpec, widthMeasureSpec); 
} 

你想要做什麼是交換與高度寬度,然後把X & Y偏移量,以使視圖旋轉後變爲全屏顯示。

以上是'風景'旋轉的版本。要實現一個倒轉的景觀只適用於270度的旋轉。您可以修改代碼段中的代碼或外部應用旋轉在一個更通用的方法,即

final YourViewOrViewGroup layout = inflater.inflate(...); 
if (currentOrientation.isInverted()) { 
    layout.setRotation(layout.getRotation + 180f); 
} 

這樣您就可以在XML定義中嵌入旋轉視圖/ ViewGroup中和膨脹「端口」和'陸地'版本,而屏幕方向變化,但這似乎超出了這個話題。

編輯:實際上推遲偏移設置要好得多,直到至少一個佈局過程結束。 這是因爲,在我的情況下,第一次onMeasure()後,將繪製視圖(在設置偏移量之前)。最終它可能會被視爲有問題,因爲視圖/佈局一開始就不會被繪製在最終的範圍內。 (更新了片段)