Fill remaining space with fixed aspect ratio surfaceview

前端 未结 4 554
生来不讨喜
生来不讨喜 2020-12-11 03:14

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 (fi
相关标签:
4条回答
  • 2020-12-11 03:57

    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:

    0 讨论(0)
  • 2020-12-11 04:01

    This will work i have tested.

    public class Test_stflowActivity extends Activity {
        SurfaceView sv = null;
        RelativeLayout rl = null;
        int current_width = 0;
        int current_height   = 0;
        boolean already_created = false;
        /** Called when the activity is first created. */
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            sv = (SurfaceView) findViewById(R.id.SurfaceView1);
            rl = (RelativeLayout) findViewById(R.id.relativeLayout3);
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    current_height = rl.getHeight();
                    while (current_height == 0) {
                        current_height = rl.getHeight();
                    }
                    current_width  = rl.getWidth();
                    runOnUiThread(new Runnable() {
    
                        @Override
                        public void run() {
                            update_surface(current_height, current_width);
                        }
                    });
                }
            });
            thread.start();
            already_created = false;
        }
    
        void update_surface(int current_height,int current_width) {
            if (already_created == false){
    
                // CALCULATE ASPECTED RATIO ACCORDING TO ABOVE HEIGHT AND WIDTH.
                int calculated_height = current_height/2;
                int calculated_width = current_width /2;
                RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(calculated_height,
                                                                                 calculated_width);
                lp.addRule(RelativeLayout.CENTER_IN_PARENT);
                sv.setLayoutParams(lp);
                sv.setVisibility(View.VISIBLE);
                already_created = true;
            }
            super.onResume();
        }
    }
    

    Here is layout which i have created.

    <RelativeLayout
        android:id="@+id/relativeLayout2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentRight="true" >
    
        <Button
            android:id="@+id/button1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_alignParentTop="true"
            android:layout_marginLeft="87dp"
            android:text="Button" />
    
    </RelativeLayout>
    
    
    
    
    
    <RelativeLayout
        android:id="@+id/relativeLayout3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@+id/relativeLayout2"
        android:layout_alignParentLeft="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true" >
    
        <android.view.SurfaceView
            android:id="@+id/SurfaceView1"
            android:layout_width="match_parent"
            android:layout_height="match_parent" android:layout_centerInParent="true" android:background="#ff0000" android:visibility="invisible"/>
    
    </RelativeLayout>
    

    Hope help you to solve.

    0 讨论(0)
  • 2020-12-11 04:04

    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

    0 讨论(0)
  • 2020-12-11 04:08

    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.

    0 讨论(0)
提交回复
热议问题