【问题标题】:Fill remaining space with fixed aspect ratio surfaceview用固定纵横比surfaceview填充剩余空间
【发布时间】:2017-09-26 00:28:19
【问题描述】:

我想布局如下视图,但我不知道如何去做:

  • 屏幕底部是常规视图,具有固定大小(填充宽度和一些 dp 数作为高度)
  • 填充剩余的垂直空间,我想放置一个继承自 glSurfaceView 的自定义视图,限制它必须具有固定的纵横比,这将通过编程设置,但在创建活动之前已知。 (在这种情况下,假设它是 2:3 w:h)。

这是我想象的小图:

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

至于设置 MySurfaceView,我认为正常的 layout_width 和 layout_height 对我没有帮助,因为直到屏幕部分布局后我才知道可用的屏幕尺寸,并且SomeOtherView 有被放置。

MySurfaceView 中是否有一些我想覆盖的函数,例如将作为参数传递可用的屏幕空间,让我决定如何设置视图的宽度和高度?

“通货膨胀”是我在这里寻找的正确术语吗?我认为这与我正在寻找的内容有关,但我并不真正了解术语。

Updated below 与我的研究结果,我认为可能是正确的解决方案。

【问题讨论】:

    标签: android


    【解决方案1】:

    做了更多的研究,我想我知道我需要做什么:

    我想要覆盖的函数是onMeasure(int widthSpec, int heightSpec),它由父级调用并提供宽度和高度建议(请参阅View.MeasureSpec)。我还将MySurfaceView 设置为在xml 中有wrap_content 的layout_width/height。然后当onMeasure 被调用时,我可以计算可用的纵横比并根据需要设置视图的宽度和高度。

    我为完成这项工作所做的第二件事是将我的MySurfaceView 作为唯一的孩子放在 FrameLayout 中。我最初在RelativeLayout 中有MySurfaceView,而我的图像中的SomeOtherView。 RelativeLayout 的问题在于,它不会以允许我修复纵横比的方式协商宽度/高度。

    onMeasure 在测量期间被多次调用,RelativeLayout 的工作方式是它首先询问自定义视图的宽度而不告诉它可用的高度,然后返回并询问高度,而宽度锁定到您在第一遍中指定的内容 (MeasureSpec.EXACTLY)。这使得无法生成特定比例的视图,因为您必须在知道可用高度之前确认宽度。

    一旦进入 FrameLayout,我就没有这个问题,因为传递给 onMeasure 的 MeasureSpecs 只有 AT_MOST 的限制。这意味着我可以在每次通过 onMeasure 期间随意更改宽度和高度,因此我最终可以根据可用区域的需要计算我的纵横比。

    尚未确认这适用于所有情况,但希望这会对某人有所帮助。

    【讨论】:

    【解决方案2】:

    要设置 SurfaceView 的大小,您应该使用:

        // 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);
    }
    

    如果你想知道屏幕的大小:

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

    希望对你有帮助

    【讨论】:

    • 你从哪里调用 setVideoSize? onCreate 目标视图本身?另外,我不需要屏幕的大小,而是想知道其他视图尚未声明的可用空间的大小。我想它可以查询其他所有视图的大小,并尝试在事先了解其方向的情况下构建可用空间,但这似乎有点笨拙。
    • 您可以从任何地方调用它。如果要填充剩余部分,可以使用match_parent(LayoutParams.MATCH_PARENT)
    • 事情是我不想匹配父母,我想知道父母的大小。根据要填充的区域的大小,我可能想要匹配宽度并在顶部和底部留下空白空间,或者我可能想要匹配高度并在左侧和右侧留下空白空间。我不能仅通过填充父级来做到这一点,否则我将失去所需的固定纵横比。不过,我非常感谢您的建议!
    • 嗯。那你应该照你之前说的做。获取整个屏幕尺寸并将其缩小到另一个视图的尺寸。
    【解决方案3】:

    随着ConstraintLayout 和布局编辑器的引入,处理比率变得更加容易。

    看下面的 XML sn-p:

    <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>
    

    这足以达到您要求的结果。请看下面的截图:

    【讨论】:

      【解决方案4】:

      我已经测试过了。

      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();
          }
      }
      

      这是我创建的布局。

      <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>
      

      希望能帮你解决。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-02-12
        • 1970-01-01
        • 2021-10-29
        • 2018-09-01
        相关资源
        最近更新 更多