I need to raise the activation up by 15% of the height of the screen (regardless of which screen, the element should rise by 15%) beyond the screen's visibility ... I do it this way

Here I have a custom view

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> /.../ <com.example.android.camera2basic.AutoFitTextureView android:id="@+id/texture" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_alignParentBottom="false" android:layout_alignParentStart="true"> </com.example.android.camera2basic.AutoFitTextureView> /.../ </RelativeLayout> 

here I set the parameters to do it

 private void initVar() { // Margin set in % of the screen int marginLeft = 0; ------> int marginTop = 15; вот здесь я указываю процент от высоты экрана int marginRight = 0; int marginBottom = 0; // Здесь мы получаем высоту и ширину экрана Display display = getWindowManager().getDefaultDisplay(); Point size = new Point(); display.getSize(size); screenWidth = size.x; screenHeight = size.y; // Здесь мы устанавливаем параметры для нашего вью RelativeLayout.LayoutParams param = new RelativeLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); param.setMargins((screenHeight * marginLeft) / 100, -((screenHeight * marginTop) / 100), (screenHeight * marginRight) / 100, (screenHeight * marginBottom) / 100); mTextureView = (AutoFitTextureView) findViewById(R.id.texture); mTextureView.setLayoutParams(param); 

and this is what happens when I upload this whole thing to the Samsung S5 1980x1080, then it looks like I’m counting, exactly 15% is busy (the white bar below is the default color of the screen that opens when we twist the view)

enter image description here

But when I upload the same project to the 1280x800 emulator, then for some reason the screen does not rise by 15% but by 25-30% (definitely not by 15%)

enter image description here

And if you try on an emulator with a resolution of 1440 * 2560, it turns out like this

enter image description here

In the first screenshot, the white bar does not reach the inscription "Front picture", and in the second it captures it and even more, and on the third it is generally 50% of the screen ...

Very strange it turns out because the formula for which the calculation is made implies that I take the height of the screen and get exactly 15% from it ...

Why on one device is 15%, and on the other it is more and on the third it is generally 50% of the screen

What am I doing wrong??

Here is a screenshot of which the margin set to 0 and there should not be a white band on the screen, but it is there, although it does not exist on a real device ...

enter image description here

  • There is a PercentRelativeLayout class and support: percent support library - it allows you to set dimensions directly in percent, maybe it will help you. - pavlofff
  • The @pavlofff seems to me the reason is that I use AutoFitTextureView to display the image from the camera on the screen, which automatically selects the best sizes and aspect ratios for myself and when the sizes are dynamically calculated, then the preview (picture) from the camera is set ... I think that the whole problem is that with AutoFitTextureView at a screen resolution of 2550 * 1280, it simply cannot evenly stretch to the full extent while maintaining the correct aspect ratio ... What do you think? Could this be right? I don’t know how to test this truth ... - Aleksey Timoshchenko

3 answers 3

You need to consider the density of the screen. The data (width and height) of the display from the system is given to you in pixels and they are real. But when you specify дополнительные numbers in the code, they need to be recalculated for the screen density. For example, you want to add 15 pixels of height for a view. You take view.getHeight() and get the size in pixels and when you add just the number view.getHeight() + 15 , on screens with different densities, the effect will look different, where it's normal, where it's less. But by doing view.getHeight() + dpToPx(getActivity(), 15) . Your 15 pixels are converted to real pixels for your screen.

  public static int dpToPx(Context context, float dp) { // add 0.5 to round up return (int) ((dp * context.getResources().getDisplayMetrics().density) + 0.5); } public static int pxToDp(Context context, int px) { // add 0.5 to round up return (int) ((px / context.getResources().getDisplayMetrics().density) + 0.5); } 

UPD Technically your calculations are correct. Except that you take the calculation of the height of the entire screen. You do not take into account the height of the soft buttons (back / home / task) take the height of your container, not the height of the screen. Since the height of the container is known only after its creation, hang the observer (see onCreate).

  ViewTreeObserver viewTreeObserver = mViewRoot.getViewTreeObserver(); viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { int viewHeight = mViewRoot.getHeight(); mViewRoot.getViewTreeObserver().removeGlobalOnLayoutListener(this); // тут все ваши расчеты } }); 

mViewRoot is your root container. Still, in the calculations in% you will have different numbers, which means it will not look the same on all devices (do I understand correctly? That the photo button is of a static size :)). I would recommend mTextureView desired height in xml in for the lower view ( mTextureView ), and changing in proportions the size of the camera preview (for the rest of the height);)

  • sorry my thoughts while writing messed up, I updated my answer - Chaynik
  • Ok, but I don’t add anything to my example ... I just get the height (say 100) and find out how much this number will be 15%, I end up with the number 15 and set it to setMargins() ... Or do you mean at this very moment when I set the setMargins() to convert? It turns out I got 15% of 100 = 15, converted to pixels and set to setMargins() ? Right? - Aleksey Timoshchenko
  • It still doesn’t work, your method returns too large a value ... It turns out that screenHeight is : 1920 , then what my method calculate is : -288 - and this is really 15% and returns your dpToPx is : -863 method dpToPx is : -863 this is definitely not 15% ... - Aleksey Timoshchenko
  • I hope the update in the answer will be more useful;) - Chaynik

Try to get the height / width of the screen like this:

 public static int getWidth(AppCompatActivity act) { DisplayMetrics displaymetrics = new DisplayMetrics(); act.getWindowManager().getDefaultDisplay().getMetrics(displaymetrics); return displaymetrics.widthPixels; } public static int getHeight(AppCompatActivity act) { DisplayMetrics displaymetrics = new DisplayMetrics(); act.getWindowManager().getDefaultDisplay().getMetrics(displaymetrics); return displaymetrics.heightPixels; } 
  • The same thing turns out ... Here's a more interesting question, how does it turn out when I check the height on a real device which is equal to 1920, then my method returns 1920 and my method returns 1920, but when I do the same on the emulator, let's say to a device with a height of 2560, then for some reason it returns to me in any case 2392 ... 168 it does not count ... When I checked on the emulator with a height of 1280 I returned 1184 ... again I did not count 96 ... with what in the first case this is 6.5% of the shortfall, and in the second 7.5 ... I don’t understand what kind of dependence ... - Aleksey Timoshchenko
  • And Yuri, the question is off topic, how did you make the pictures smaller? I did not find this function ... - Aleksey Timoshchenko
  • @AlekseyTimoshchenko, well, maybe a problem in the emulator ... which one do you use? GenyMotion or standard studio? Does it work on real devices everywhere? - Yuriy SPb
  • 3
    @AlekseyTimoshchenko 168px (96px - depending on the screen) is the height of the soft control buttons (home, back, menu) for devices with no hardware buttons - they are not counted in the size available to the application. - pavlofff
  • @AlekseyTimoshchenko, and the pictures are reduced by adding a letter to the end of the link, just before the file extension. There are several options. In this case, I just put m - YuriySPb

If I were you, I probably would have acted the same way. But now there is a ready- made solution out of the appcompat box .
This is a PercentRelativeLayout which allows you to set the sizes of child views as a percentage.

  • Yes, but if I set the fixed dimensions in this way, then my image will be stretched in one direction or another, depending on the screen ... Or am I not sure what I understand? - Aleksey Timoshchenko
  • will not happen if scaleType is set correctly - andreich
  • I understand that in our case, you need to set fitStart , so that the picture takes place in the correct proportions ... But no matter how you fitStart , the picture will not take up the whole screen and you will still have an empty space, if you make the picture occupy the entire screen, this will mean that it needs to be pulled up to some edge and it will stretch ... It seems so ... - Aleksey Timoshchenko