Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fill remaining space with fixed aspect ratio surfaceview

Tags:

android

I'd like to layout a view like the following, but I'm not sure how to go about doing so:

  • At the bottom of the screen is a regular view, with a fixed size (fill-width and some number of dp for height)
  • Filling the remaining vertical space, I would like to place a custom view which inherits from glSurfaceView, with the restriction that it must have a fixed aspect ratio, which will be programatically set, but known before the activity is created. (In this case assume it with be 2:3 w:h).

Here's a little picture of what I'm imagining:

 .----------------------. 
 |   .--------------.   |  
 | b |              | b |  
 | g |              | g | 
 |   |              |   |  
 | i |  MySurface   | i | 
 | m |     View     | m | 
 | a |              | a | 
 | g |  (2:3 w:h)   | g | 
 | e |              | e | 
 |   *--------------*   | 
 |.--------------------.| 
 ||                    || 
 ||   SomeOtherView    || 
 ||                    || 
 |*--------------------*| 
 *----------------------* 

As far as setting up the MySurfaceView, I assume that normal layout_width and layout_height are not going to help me, because I don't know the available screen size until after the screen has been partially laid out, and SomeOtherView has been placed.

Is there some function in MySurfaceView that I want to override, that for example will pass as arguments the available screen space, and let me decide how to set the width and height of the view?

Is 'inflation' the right term I'm looking for here? I think that has something to do with what I'm looking for, but I don't really know the terminology.

Updated below with the result of my research, and I think a possible correct solution.

like image 601
Tim Avatar asked May 09 '12 05:05

Tim


People also ask

What is SurfaceView in android?

Provides a dedicated drawing surface embedded inside of a view hierarchy. You can control the format of this surface and, if you like, its size; the SurfaceView takes care of placing the surface at the correct location on the screen.

What is Layout_constraintdimensionratio?

A ConstraintLayout is a ViewGroup which allows you to Position and size Views in a flexible way. It is basically RelativeLayout on Steriods. The Views will be positioned and sized w.r.t other Views with the Use of Constraints.


3 Answers

With the introduction of ConstraintLayout and Layout Editor, it becomes much easier to handle ratios.

Look at the XML snippet below:

<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:scaleType="centerCrop"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:srcCompat="@drawable/bckg" />

    <FrameLayout
        android:id="@+id/mySurfaceView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="#99000000"
        app:layout_constraintTop_toTopOf="@+id/imageView"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintBottom_toTopOf="@+id/someOtherView"
        app:layout_constraintDimensionRatio="W,2:3" />

    <FrameLayout
        android:id="@+id/someOtherView"
        android:layout_width="0dp"
        android:layout_height="100dp"
        android:background="#AAFFFFFF"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintBottom_toBottomOf="parent" />

</android.support.constraint.ConstraintLayout>

That's quite enough to achieve results you asked for. See screenshots below:

enter image description here

enter image description here

like image 191
Eugene Brusov Avatar answered Oct 05 '22 18:10

Eugene Brusov


Did more research and I think I figured out what I need to do:

The function I was looking to override is onMeasure(int widthSpec, int heightSpec), which is called by the parent with suggestions for width and height (see View.MeasureSpec). I also set MySurfaceView to have a layout_width/height of wrap_content in the xml. Then when onMeasure gets called I can compute the available aspect ratio and set the width and height of my view as desired.

The second thing I did to make this work was to put my MySurfaceView inside of a FrameLayout as the only child. I originally had MySurfaceView in a RelativeLayout with the SomeOtherView from my image. The problem with the RelativeLayout, is that it would not negotiate the width/height in a way that allowed me to fix the aspect ratio.

onMeasure gets called multiple times during measuring, and the way RelativeLayout works is that it first asks the custom view for it's width without telling it the available height, and then later comes back and asks for the height, while the width is locked to what you specified in the first pass (MeasureSpec.EXACTLY). This makes it impossible to generate a view of a certain ratio, as you must confirm the width before knowing the available height.

Once inside of the FrameLayout, I didn't have this problem, as the MeasureSpecs passed to onMeasure only ever had the restriction AT_MOST. This means I was free to change the width and height during every pass of onMeasure, and so I could end up calculating my aspect ratio as desired given the available area.

Haven't confirmed yet that this works for all cases, but hopefully this will help someone.

like image 42
Tim Avatar answered Oct 05 '22 17:10

Tim


To set the size of the SurfaceView you should use:

    // Set surfaceview size in px
private void setVideoSize(int width, int height) {
    LayoutParams params = (LayoutParams) mYourSurfaceView.getLayoutParams();
    params.height = height;
    params.width = width;
    mYourSurfaceView.setLayoutParams(params);
}

And if you want to know the size of the screen:

Display display = ((WindowManager) getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); 
int width = display.getWidth(); 
int heigth = display.getHeight(); 

Hope this helps

like image 32
Ion Aalbers Avatar answered Oct 05 '22 17:10

Ion Aalbers