The Concept of Full Screen
Why explain the full screen first, because the word is now a false proposition. Full screen literally means that the front of the mobile phone is all screen, 100% of the screen. But nowadays, none of the manufacturers that launch so-called "full screen" mobile phones can achieve full scale.
So let's talk about the understanding and definition of the full screen in Android development.
The screen aspect ratio of general mobile phones is 16:9, such as 1080x1920, 1440x2560, etc. Its ratio is 1.77. Before the appearance of full-screen mobile phones, the default maximum aspect ratio of Android is 1.86, which is compatible with 16:9 screen.
In the pursuit of larger screen space and more extreme user experience, some mobile phone manufacturers have improved the aspect ratio of the screen. 17:9, 19:10, 18:9 and 18.5:9 mobile phones have entered the market. The aspect ratio of these mobile phones is much higher than 1.86. These mobile phones are called full-screen mobile phones.
Why do you need to adapt
We change the value of targetSdkVersion to less than or equal to 23. When we run the program, we will find a black bar at the bottom of the screen.
How to fit
Target SdkVersion <=23, larger aspect ratio of screen
After the release of Galaxy S8, Android officially provided an adaptation solution, that is, to increase the aspect ratio of the maximum screen supported by App. The implementation is simple. The following configuration can be made in Android Manifest. xml:
<meta-data android:name="android.max_aspect" android:value="ratio_float"/>
Among them, ratio_float is a floating point number, and the official recommendation is 2.1 or larger, because 18.5:9 = 2.0555555... If there are more vertical and horizontal mobile phones in the future, the value will be larger.
<meta-data android:name="android.max_aspect" android:value="2.1" />
The max_aspect value can also be set dynamically in Java code by the following methods:
public void setMaxAspect() { ApplicationInfo applicationInfo = null; try { applicationInfo = getPackageManager().getApplicationInfo(getPackageName(), PackageManager.GET_META_DATA); } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } if(applicationInfo == null){ throw new IllegalArgumentException(" get application info = null "); } applicationInfo.metaData.putString("android.max_aspect", "2.1"); }
If the value of targetSdkVersion is greater than 23, then max_aspect should not be set.
View the adapted screenshots:
https://android-developers.googleblog.com/2017/03/update-your-app-to-take-advantage-of.html
Image resource adaptation
Let's take a look at the startup page. The images that fit on the 16:9 screen will be stretched on the 18:9 screen.
16:9 screen display | 18:9 screen display |
---|---|
image
|
image
|
There are only two ways to solve this problem: changing pictures or changing layout.
Change pictures
You can't rely on a single vendor's solution, you can only start with Android system attributes. Considering that most of the full-screen mobile phones are only stretched in height, mostly about 6.0 inches, and the pixel density is not much different from xxhdpi, we can add a group of resources drawable-xhdpi-2160x1080, drawable-long to solve the problem of image stretching. Of course, such a method is certainly not very good, which will increase the capacity of app. I won't show you here.
Optimal layout
Of course, the best way is to use XML for relative layout, or the solution of. 9 graph.
What I have concluded is a small amount of multi-cut, minimizing the impact of size on the layout. Here, for example, using a square cut, let him center the display, regardless of how the screen is vertical and horizontal, will not stretch the picture, stretching only the background.
<ImageView android:layout_width="fill_parent" android:layout_height="fill_parent" android:scaleType="fitCenter" android:src="@drawable/bz002"/>
Before adaptation | After adaptation |
---|---|
image
|
image
|
Full Screen Height Problem Adaptation
First, explain the concepts of window, decorview, rootview.
Windows Official Document: Window
public abstract class Window. Abstract base class for a top-level window look and behavior policy. An instance of this class should be used as the top-level view added to the window manager. It provides standard UI policies such as a background, title area, default key processing, etc.
The only existing implementation of this abstract class is android.view.PhoneWindow, which you should instantiate when needing a Window.
Every activity has a Windows object, but Windows is an abstract class, where Android provides Windows with the only implementation class, PhoneWindow. That is to say, the Windows instance in Activity is a PhoneWindow object.
But Phone Windows is Windows after all, and it doesn't have much View-related capabilities. But Phone Windows has a very important view object in Android, DecorView.
Now the relationship is very clear, each activity holds a PhoneWindow object, and a PhoneWindow object holds an instance of DecorView, so most of the View-related operations in Activity are actually done through DecorView.
DecorView can be understood as the inside screen of the mobile phone, which is the glass that can emit light.
Here, through the code, we print out the height of the various data in our page.
int decorviewHeight = decorView.getHeight(); int screenHeight = FullScreenManager.getScreenHeight(); int nativeBarHeight = FullScreenManager.getNativeBarHeight(); int contentViewHeight = rootView.getHeight(); int navigationBarHeight1 = FullScreenManager.getNavigationBarHeight(); Log.d("shijiacheng","======================================="); Log.d("shijiacheng","DecorView height: " + decorviewHeight + " px"); Log.d("shijiacheng","Screen height: " + screenHeight + " px"); Log.d("shijiacheng","NativeBar height: " + nativeBarHeight + " px"); Log.d("shijiacheng","ContentView height: " + contentViewHeight + " px"); Log.d("shijiacheng","NavigationBar height: " + navigationBarHeight + " px"); Log.d("shijiacheng","---------------------------------------");
Get the height of decorView
final View decorView = getWindow().getDecorView(); int decorviewHeight = decorView.getHeight();
Get screen height
/** * Get screen height * @return */ public static int getScreenHeight() { Resources resource = AppContext.getInstance().getResources(); DisplayMetrics displayMetrics = resource.getDisplayMetrics(); return displayMetrics.heightPixels; }
Get the height of the status bar
/** * Get the height of the status bar * * @return */ public static int getNativeBarHeight() { Resources resource = AppContext.getInstance().getResources(); int result = 0; int resourceId = resource.getIdentifier("status_bar_height", "dimen", "android"); if (resourceId > 0) { result = resource.getDimensionPixelSize(resourceId); } return result; }
Get the height of contentView
LinearLayout contentView = findViewById(R.id.root); int contentViewHeight = contentView.getHeight();
Get the height of Navigation Bar
public static int getNavigationBarHeight() { Resources resources = AppContext.getInstance().getResources(); int resourceId = resources.getIdentifier("navigation_bar_height","dimen", "android"); int height = resources.getDimensionPixelSize(resourceId); return height; }
In order to display the data more intuitively, we use the layout method to display the data. The layout code is relatively simple, but it is not shown here.
Let's start by showing the normal height of the screen.
10-08 09:52:03.636 23818-23818/? D/shijiacheng: ========================= 10-08 09:52:03.637 23818-23818/? D/shijiacheng: DecorView height: 1280 px 10-08 09:52:03.637 23818-23818/? D/shijiacheng: Screen height: 1280 px 10-08 09:52:03.637 23818-23818/? D/shijiacheng: NativeBar height: 50 px 10-08 09:52:03.637 23818-23818/? D/shijiacheng: ContentView height: 1230 px 10-08 09:52:03.637 23818-23818/? D/shijiacheng: NavigationBar height: 96 px 10-08 09:52:03.637 23818-23818/? D/shijiacheng: -------------------------
DecorView = Screen height = NativeBar height + ContentView height
Look at the full screen of millet mix
2018-10-08 09:54:15.640 /? D/shijiacheng: ========================= 2018-10-08 09:54:15.640 /? D/shijiacheng: DecorView height: 2160 px 2018-10-08 09:54:15.641 /? D/shijiacheng: RootView height: 2094 px 2018-10-08 09:54:15.641 /? D/shijiacheng: Screen height: 2030 px 2018-10-08 09:54:15.641 /? D/shijiacheng: NativeBar height: 66 px 2018-10-08 09:54:15.641 /? D/shijiacheng: ContentView height: 2094 px 2018-10-08 09:54:15.641 /? D/shijiacheng: NavigationBar height: 130 px 2018-10-08 09:54:15.641 /? D/shijiacheng: -------------------------
The problem arises. We can find that the height of contentView is higher than that of screen screen. We can't help but wonder that our method of getting the height of screen is wrong under the full screen.
Question 1: Inaccurate calculation of screen height acquisition method
We always use the following methods to measure the height of the screen:
public static int getScreenHeight() { Resources resource = AppContext.getInstance().getResources(); DisplayMetrics displayMetrics = resource.getDisplayMetrics(); return displayMetrics.heightPixels; }
But this method is a very old one, not keeping pace with the times. Although this method is not a problem on the ordinary screen, it is not effective on the full screen mobile phone.
Now let's look at the evolution of the method of getting screen size.
Get screen width and height
Getting the screen width is a problem we often encounter in our development, and I believe that everyone is very familiar with it. The most commonly used are the following two kinds:
public static int getScreenHeight1(Activity activity) { return activity.getWindowManager().getDefaultDisplay().getHeight(); } public static int getScreenHeight2(Activity activity) { DisplayMetrics displayMetrics = new DisplayMetrics(); activity.getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); return displayMetrics.heightPixels; }
In fact, the above two ways are the same, but the second way is to encapsulate information into DesplayMetrics and get data from DesplayMetrics.
After Android 3.2(Api 13), the following method is provided to encapsulate data into Point and return width and height information.
@TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2) public static int getScreenHeight3(Activity activity) { Point point = new Point(); activity.getWindowManager().getDefaultDisplay().getSize(point); return point.y; }
After Android 4.2(Api17), the following method is provided. Similar to the third method, the data is encapsulated in a Point and the height information of the payment is returned.
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) public static int getScreenHeight4(Activity activity) { Point realSize = new Point(); activity.getWindowManager().getDefaultDisplay().getRealSize(realSize); return realSize.y; }
In fact, getRealSize was added when Android Api15, but it was hidden, we can see by looking at the source code.
The getRealSize() method in the Android Api15 Display.java source code is marked as @hide
Therefore, we can rewrite the method of Height Acquisition and adapt it to all models and systems.
A Method of Getting Screen Size by Adapting All Screens
public static int[] getScreenSize(Context context) { int[] size = new int[2]; WindowManager w = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); Display d = w.getDefaultDisplay(); DisplayMetrics metrics = new DisplayMetrics(); d.getMetrics(metrics); // since SDK_INT = 1; int widthPixels = metrics.widthPixels; int heightPixels = metrics.heightPixels; // includes window decorations (statusbar bar/menu bar) if (Build.VERSION.SDK_INT >= 14 && Build.VERSION.SDK_INT < 17) try { widthPixels = (Integer) Display.class.getMethod("getRawWidth").invoke(d); heightPixels = (Integer) Display.class.getMethod("getRawHeight").invoke(d); } catch (Exception ignored) { } // includes window decorations (statusbar bar/menu bar) if (Build.VERSION.SDK_INT >= 17) try { Point realSize = new Point(); Display.class.getMethod("getRealSize", Point.class).invoke(d, realSize); widthPixels = realSize.x; heightPixels = realSize.y; } catch (Exception ignored) { } size[0] = widthPixels; size[1] = heightPixels; return size; }
By using the new method of Height Acquisition and re-running the program, the running results have been displayed normally.
2018-10-08 13:19:32.389 /? D/shijiacheng: ========================== 2018-10-08 13:19:32.390 /? D/shijiacheng: DecorView height: 2160 px 2018-10-08 13:19:32.390 /? D/shijiacheng: Screen height: 2160 px 2018-10-08 13:19:32.390 /? D/shijiacheng: NativeBar height: 66 px 2018-10-08 13:19:32.390 /? D/shijiacheng: ContentView height: 2094 px 2018-10-08 13:19:32.390 /? D/shijiacheng: NavigationBar height: 130 px 2018-10-08 13:19:32.390 /? D/shijiacheng: --------------------------
Question 2: Computation of Millet mix Cut into Classical Navigation Key Mode
In MIUI settings, we changed the full-screen navigation style to the "classic navigation key" style.
Rerun the program and the results are as follows:
You can see another problem, DecorView = Screen height > NativeBar height + ContentView height
It's not hard to find that Screen height also counts the height of the virtual navigation bar at the bottom.
In many cases, we use the following methods to get the height of the navigation bar:
public static int getNavigationBarHeight() { Resources resources = AppContext.getInstance().getResources(); int resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android"); int height = resources.getDimensionPixelSize(resourceId); return height; }
The height of the navigation bar obtained by this method is not a problem, but the height of the navigation bar can be obtained even if the navigation bar is hidden on the full screen mobile phone. From the logcat log above, you can see that even without the navigation bar, the height calculation of the navigation bar is valuable.
Adapt the Millet mix Virtual Navigation Bar
In the millet mix model, we can "force_fsg_nav_bar" to determine whether the millet mobile phone has opened the full screen gesture.
public static int getHeightOfNavigationBar(Context context) { //Return to 0 if the Millet mobile phone opens a full screen gesture and hides the navigation bar. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { if (Settings.Global.getInt(context.getContentResolver(), "force_fsg_nav_bar", 0) != 0) { return 0; } } int realHeight = getScreenSize(context)[1]; Display d = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)) .getDefaultDisplay(); DisplayMetrics displayMetrics = new DisplayMetrics(); d.getMetrics(displayMetrics); int displayHeight = displayMetrics.heightPixels; return realHeight - displayHeight; }
Therefore, this method can be used to determine whether the bottom navigation bar is displayed, and the height of the navigation bar can be calculated.
int navigationBarHeight = FullScreenManager.getHeightOfNavigationBar(MainActivity.this); if (navigationBarHeight > 0){ container_navigationview.setVisibility(View.VISIBLE); }else { container_navigationview.setVisibility(View.GONE); }
The normal display effect is as follows:
Virtual navigation bar | No virtual navigation bar |
---|---|
image
|
image
|
No Virtual Navigation Bar Log
2018-10-08 13:19:32.389 /? D/shijiacheng: ========================== 2018-10-08 13:19:32.390 /? D/shijiacheng: DecorView height: 2160 px 2018-10-08 13:19:32.390 /? D/shijiacheng: Screen height: 2160 px 2018-10-08 13:19:32.390 /? D/shijiacheng: NativeBar height: 66 px 2018-10-08 13:19:32.390 /? D/shijiacheng: ContentView height: 2094 px 2018-10-08 13:19:32.390 /? D/shijiacheng: NavigationBar height: 0 px 2018-10-08 13:19:32.390 /? D/shijiacheng: --------------------------
Log with Virtual Navigation Bar
2018-10-08 13:38:03.229 /? D/shijiacheng: ========================== 2018-10-08 13:38:03.230 /? D/shijiacheng: DecorView height: 2160 px 2018-10-08 13:38:03.230 /? D/shijiacheng: Screen height: 2160 px 2018-10-08 13:38:03.230 /? D/shijiacheng: NativeBar height: 66 px 2018-10-08 13:38:03.230 /? D/shijiacheng: ContentView height: 1964 px 2018-10-08 13:38:03.230 /? D/shijiacheng: NavigationBar height: 130 px 2018-10-08 13:38:03.230 /? D/shijiacheng: --------------------------