我创建了一些自定义元素,我想以编程方式将它们放置在右上角(距离上边缘 n
个像素,距离右边缘 m
个像素)。因此我需要获取屏幕宽度和屏幕高度,然后设置位置:
int px = screenWidth - m;
int py = screenHeight - n;
如何在主 Activity 中获取 screenWidth
和 screenHeight
?
getMetrics
,而不是 getSize 和已弃用的 getWidth/getHeight 组合(忽略错误)。 Nik 在他的回答中的评论甚至解释了 getDisplayMetrics
以考虑系统/状态栏的大小。您也可以使用 density 作为 jmaculate 和 LoungeKatt 解释为具有 EXACT 值:DisplayMetrics dm = getResources().getDisplayMetrics(); float fwidth = dm.density * dm.widthPixels;
在 Android v2.2 (API 8) 和 v4.0 中测试,结果良好并且没有错误/警告。
Resources.getSystem().getDisplayMetrics()
。您不需要 Context
即可获得它们。
如果您想要以像素为单位的显示尺寸,您可以使用 getSize
:
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = size.x;
int height = size.y;
如果您不在 Activity
中,您可以通过 WINDOW_SERVICE
获得默认的 Display
:
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
如果您在片段中并且想要完成此操作,只需使用 Activity.WindowManager(在 Xamarin.Android 中)或 getActivity().getWindowManager()(在 java 中)。
在引入 getSize
之前(在 API 级别 13 中),您可以使用现已弃用的 getWidth
和 getHeight
方法:
Display display = getWindowManager().getDefaultDisplay();
int width = display.getWidth(); // deprecated
int height = display.getHeight(); // deprecated
但是,对于您所描述的用例,布局中的边距/填充似乎更合适。
另一种方法是:DisplayMetrics
描述有关显示的一般信息的结构,例如其大小、密度和字体缩放。要访问 DisplayMetrics 成员,请像这样初始化一个对象:
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
我们可以使用 widthPixels
获取以下信息:
“显示的绝对宽度,以像素为单位。”
例子:
Log.d("ApplicationTagName", "Display width in px is " + metrics.widthPixels);
API 级别 30 更新
final WindowMetrics metrics = windowManager.getCurrentWindowMetrics();
// Gets all excluding insets
final WindowInsets windowInsets = metrics.getWindowInsets();
Insets insets = windowInsets.getInsetsIgnoringVisibility(WindowInsets.Type.navigationBars()
| WindowInsets.Type.displayCutout());
int insetsWidth = insets.right + insets.left;
int insetsHeight = insets.top + insets.bottom;
// Legacy size that Display#getSize reports
final Rect bounds = metrics.getBounds();
final Size legacySize = new Size(bounds.width() - insetsWidth,
bounds.height() - insetsHeight);
一种方法是:
Display display = getWindowManager().getDefaultDisplay();
int width = display.getWidth();
int height = display.getHeight();
它已被弃用,您应该尝试以下代码。前两行代码为您提供 DisplayMetrics
对象。该对象包含 heightPixels
、widthPixels
等字段。
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
int height = metrics.heightPixels;
int width = metrics.widthPixels;
API 30 级更新
final WindowMetrics metrics = windowManager.getCurrentWindowMetrics();
// Gets all excluding insets
final WindowInsets windowInsets = metrics.getWindowInsets();
Insets insets = windowInsets.getInsetsIgnoringVisibility(WindowInsets.Type.navigationBars()
| WindowInsets.Type.displayCutout());
int insetsWidth = insets.right + insets.left;
int insetsHeight = insets.top + insets.bottom;
// Legacy size that Display#getSize reports
final Rect bounds = metrics.getBounds();
final Size legacySize = new Size(bounds.width() - insetsWidth,
bounds.height() - insetsHeight);
它可能无法回答您的问题,但如果您需要 View 的尺寸但您的代码在其布局尚未布局时正在执行,那么了解(当我遇到这个问题时我自己正在寻找它)可能会很有用(例如在 onCreate()
中)您可以使用 View.getViewTreeObserver().addOnGlobalLayoutListener()
设置 ViewTreeObserver.OnGlobalLayoutListener
并将需要视图尺寸的相关代码放在那里。布局布局后,将调用侦听器的回调。
View.post()
不能保证工作?我很好奇,因为我也依靠这种方法在布局后获取视图的大小并且不知道它不可靠。
View
获得 ViewTreeObserver
重要吗?还是他们都共享同一个?
(2012 回答,可能已过时)如果您想支持 pre Honeycomb,则需要在 API 13 之前提供向后兼容性。例如:
int measuredWidth = 0;
int measuredHeight = 0;
WindowManager w = getWindowManager();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
Point size = new Point();
w.getDefaultDisplay().getSize(size);
measuredWidth = size.x;
measuredHeight = size.y;
} else {
Display d = w.getDefaultDisplay();
measuredWidth = d.getWidth();
measuredHeight = d.getHeight();
}
当然,不推荐使用的方法最终会从最新的 SDK 中删除,但是虽然我们仍然依赖于大多数用户拥有 Android 2.1、2.2 和 2.3,但这就是我们剩下的。
我尝试了所有可能的“解决方案”均未成功,我注意到 Elliott Hughes 的“Dalvik Explorer”应用程序始终在任何 Android 设备/操作系统版本上显示正确的尺寸。我最终查看了他的开源项目,可以在这里找到:https://code.google.com/p/enh/
以下是所有相关代码:
WindowManager w = activity.getWindowManager();
Display d = w.getDefaultDisplay();
DisplayMetrics metrics = new DisplayMetrics();
d.getMetrics(metrics);
// since SDK_INT = 1;
widthPixels = metrics.widthPixels;
heightPixels = metrics.heightPixels;
try {
// used when 17 > SDK_INT >= 14; includes window decorations (statusbar bar/menu bar)
widthPixels = (Integer) Display.class.getMethod("getRawWidth").invoke(d);
heightPixels = (Integer) Display.class.getMethod("getRawHeight").invoke(d);
} catch (Exception ignored) {
}
try {
// used when SDK_INT >= 17; includes window decorations (statusbar bar/menu bar)
Point realSize = new Point();
Display.class.getMethod("getRealSize", Point.class).invoke(d, realSize);
widthPixels = realSize.x;
heightPixels = realSize.y;
} catch (Exception ignored) {
}
编辑:略微改进的版本(避免在不支持的操作系统版本上触发异常):
WindowManager w = activity.getWindowManager();
Display d = w.getDefaultDisplay();
DisplayMetrics metrics = new DisplayMetrics();
d.getMetrics(metrics);
// since SDK_INT = 1;
widthPixels = metrics.widthPixels;
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) {
}
最简单的方法:
int screenHeight = getResources().getDisplayMetrics().heightPixels;
int screenWidth = getResources().getDisplayMetrics().widthPixels;
为了访问 Android 设备的状态栏高度,我们更喜欢以编程方式获取它:
示例代码
int resId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resId > 0) {
result = getResources().getDimensionPixelSize(resId);
}
变量 result
给出了像素的高度。
为了快速访问
https://i.stack.imgur.com/1HxlM.png
有关 Title bar
、Navigation bar
和 Content View
高度的更多信息,请查看 Android Device Screen Sizes。
getResources().getDisplayMetrics().heightPixels + result
给出实际的全屏高度。 Dragan Marjanović 的回答也有效,但我更喜欢这个更短更简单的解决方案。
OnApplyWindowInsetsListener
。
首先获取视图(例如通过 findViewById()
),然后您可以在视图本身上使用 getWidth()。
我有两个函数,一个用于发送上下文,另一个以像素为单位获取高度和宽度:
public static int getWidth(Context mContext){
int width=0;
WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
if(Build.VERSION.SDK_INT>12){
Point size = new Point();
display.getSize(size);
width = size.x;
}
else{
width = display.getWidth(); // Deprecated
}
return width;
}
和
public static int getHeight(Context mContext){
int height=0;
WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
if(Build.VERSION.SDK_INT>12){
Point size = new Point();
display.getSize(size);
height = size.y;
}
else{
height = display.getHeight(); // Deprecated
}
return height;
}
@SuppressLint("NewApi")
才能编译。
对于使用 XML 进行动态缩放,有一个名为“android:layout_weight”的属性
下面的示例根据 synic 对 this thread 的响应进行了修改,显示了一个占据 75% 屏幕(权重 = .25)的按钮和一个占据剩余 25% 屏幕(权重 = .75)的文本视图。
<LinearLayout android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight=".25"
android:text="somebutton">
<TextView android:layout_width="fill_parent"
android:layout_height="Wrap_content"
android:layout_weight=".75">
</LinearLayout>
这是我用于该任务的代码:
// `activity` is an instance of Activity class.
Display display = activity.getWindowManager().getDefaultDisplay();
Point screen = new Point();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
display.getSize(screen);
} else {
screen.x = display.getWidth();
screen.y = display.getHeight();
}
看起来足够干净,但要注意弃用。
这不是更好的解决方案吗? DisplayMetrics 包含您需要的一切,并且可以通过 API 1 工作。
public void getScreenInfo(){
DisplayMetrics metrics = new DisplayMetrics();
getActivity().getWindowManager().getDefaultDisplay().getMetrics(metrics);
heightPixels = metrics.heightPixels;
widthPixels = metrics.widthPixels;
density = metrics.density;
densityDpi = metrics.densityDpi;
}
您还可以使用 getRealMetrics 获得实际显示(包括屏幕装饰,例如状态栏或软件导航栏),但这仅适用于 17+。
我错过了什么吗?
只是添加到弗朗切斯科的答案。如果您想找出窗口中的位置或屏幕中的位置,另一个更合适的观察者是 ViewTreeObserver.OnPreDrawListener()
这也可用于查找在 onCreate() 时大部分未知的视图的其他属性,例如滚动位置、缩放位置。
在活动中使用以下代码。
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
int height = metrics.heightPixels;
int wwidth = metrics.widthPixels;
查找屏幕的宽度和高度:
width = getWindowManager().getDefaultDisplay().getWidth();
height = getWindowManager().getDefaultDisplay().getHeight();
使用它,我们可以获得最新及以上的 SDK 13。
// New width and height
int version = android.os.Build.VERSION.SDK_INT;
Log.i("", " name == "+ version);
Display display = getWindowManager().getDefaultDisplay();
int width;
if (version >= 13) {
Point size = new Point();
display.getSize(size);
width = size.x;
Log.i("width", "if =>" +width);
}
else {
width = display.getWidth();
Log.i("width", "else =>" +width);
}
DisplayMetrics dimension = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dimension);
int w = dimension.widthPixels;
int h = dimension.heightPixels;
我发现这可以解决问题。
Rect dim = new Rect();
getWindowVisibleDisplayFrame(dim);
需要说明的是,如果您不在 Activity
中,而是在 View
中(或在您的范围内有 View
类型的变量),则不需要使用 WINDOW_SERVICE
。那么你至少可以使用两种方式。
第一的:
DisplayMetrics dm = yourView.getContext().getResources().getDisplayMetrics();
第二:
DisplayMetrics dm = new DisplayMetrics();
yourView.getDisplay().getMetrics(dm);
我们在这里调用的所有这些方法都没有被弃用。
public class AndroidScreenActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
String str_ScreenSize = "The Android Screen is: "
+ dm.widthPixels
+ " x "
+ dm.heightPixels;
TextView mScreenSize = (TextView) findViewById(R.id.strScreenSize);
mScreenSize.setText(str_ScreenSize);
}
}
要获取屏幕尺寸,请使用显示指标
DisplayMetrics displayMetrics = new DisplayMetrics();
if (context != null)
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display defaultDisplay = windowManager.getDefaultDisplay();
defaultDisplay.getRealMetrics(displayMetrics);
}
以像素为单位获取高度和宽度
int width =displayMetrics.widthPixels;
int height =displayMetrics.heightPixels;
这不是 OP 的答案,因为他想要以真实像素显示尺寸。我想要“设备无关像素”中的尺寸,并将此处https://stackoverflow.com/a/17880012/253938和此处https://stackoverflow.com/a/6656774/253938的答案放在一起,我想出了这个:
DisplayMetrics displayMetrics = Resources.getSystem().getDisplayMetrics();
int dpHeight = (int)(displayMetrics.heightPixels / displayMetrics.density + 0.5);
int dpWidth = (int)(displayMetrics.widthPixels / displayMetrics.density + 0.5);
您可以使用以下方法获取高度大小:
getResources().getDisplayMetrics().heightPixels;
和宽度大小使用
getResources().getDisplayMetrics().widthPixels;
使用 DisplayMetrics (API 1) 有一种不被弃用的方法,可以避免 try/catch 混乱:
// initialize the DisplayMetrics object
DisplayMetrics deviceDisplayMetrics = new DisplayMetrics();
// populate the DisplayMetrics object with the display characteristics
getWindowManager().getDefaultDisplay().getMetrics(deviceDisplayMetrics);
// get the width and height
screenWidth = deviceDisplayMetrics.widthPixels;
screenHeight = deviceDisplayMetrics.heightPixels;
我会像这样包装 getSize 代码:
@SuppressLint("NewApi")
public static Point getScreenSize(Activity a) {
Point size = new Point();
Display d = a.getWindowManager().getDefaultDisplay();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
d.getSize(size);
} else {
size.x = d.getWidth();
size.y = d.getHeight();
}
return size;
}
对于谁正在搜索没有状态栏和操作栏的可用屏幕尺寸(也感谢 Swapnil 的回答):
DisplayMetrics dm = getResources().getDisplayMetrics();
float screen_w = dm.widthPixels;
float screen_h = dm.heightPixels;
int resId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resId > 0) {
screen_h -= getResources().getDimensionPixelSize(resId);
}
TypedValue typedValue = new TypedValue();
if(getTheme().resolveAttribute(android.R.attr.actionBarSize, typedValue, true)){
screen_h -= getResources().getDimensionPixelSize(typedValue.resourceId);
}
科特林
fun getScreenHeight(activity: Activity): Int {
val metrics = DisplayMetrics()
activity.windowManager.defaultDisplay.getMetrics(metrics)
return metrics.heightPixels
}
fun getScreenWidth(activity: Activity): Int {
val metrics = DisplayMetrics()
activity.windowManager.defaultDisplay.getMetrics(metrics)
return metrics.widthPixels
}
首先加载 XML 文件,然后编写以下代码:
setContentView(R.layout.main);
Display display = getWindowManager().getDefaultDisplay();
final int width = (display.getWidth());
final int height = (display.getHeight());
根据您的屏幕分辨率显示宽度和高度。
请遵循以下方法:
public static int getWidthScreen(Context context) {
return getDisplayMetrics(context).widthPixels;
}
public static int getHeightScreen(Context context) {
return getDisplayMetrics(context).heightPixels;
}
private static DisplayMetrics getDisplayMetrics(Context context) {
DisplayMetrics displayMetrics = new DisplayMetrics();
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
wm.getDefaultDisplay().getMetrics(displayMetrics);
return displayMetrics;
}
在活动的 onCreate 中,有时您需要知道布局可用空间的精确尺寸。经过一番思考,我想出了这种方法。
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
startActivityForResult(new Intent(this, Measure.class), 1);
// Return without setting the layout, that will be done in onActivityResult.
}
@Override
protected void onActivityResult (int requestCode, int resultCode, Intent data) {
// Probably can never happen, but just in case.
if (resultCode == RESULT_CANCELED) {
finish();
return;
}
int width = data.getIntExtra("Width", -1);
// Width is now set to the precise available width, and a layout can now be created. ...
}
}
public final class Measure extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// Create a LinearLayout with a MeasureFrameLayout in it.
// Just putting a subclass of LinearLayout in works fine, but to future proof things, I do it this way.
LinearLayout linearLayout = new LinearLayout(this);
LinearLayout.LayoutParams matchParent = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT);
MeasureFrameLayout measureFrameLayout = new MeasureFrameLayout(this);
measureFrameLayout.setLayoutParams(matchParent);
linearLayout.addView(measureFrameLayout);
this.addContentView(linearLayout, matchParent);
// measureFrameLayout will now request this second activity to finish, sending back the width.
}
class MeasureFrameLayout extends FrameLayout {
boolean finished = false;
public MeasureFrameLayout(Context context) {
super(context);
}
@SuppressLint("DrawAllocation")
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (finished) {
return;
}
finished = true;
// Send the width back as the result.
Intent data = new Intent().putExtra("Width", MeasureSpec.getSize(widthMeasureSpec));
Measure.this.setResult(Activity.RESULT_OK, data);
// Tell this activity to finish, so the result is passed back.
Measure.this.finish();
}
}
}
如果出于某种原因您不想在 Android 清单中添加其他活动,您可以这样做:
public class MainActivity extends Activity {
static Activity measuringActivity;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Bundle extras = getIntent().getExtras();
if (extras == null) {
extras = new Bundle();
}
int width = extras.getInt("Width", -2);
if (width == -2) {
// First time in, just start another copy of this activity.
extras.putInt("Width", -1);
startActivityForResult(new Intent(this, MainActivity.class).putExtras(extras), 1);
// Return without setting the layout, that will be done in onActivityResult.
return;
}
if (width == -1) {
// Second time in, here is where the measurement takes place.
// Create a LinearLayout with a MeasureFrameLayout in it.
// Just putting a subclass of LinearLayout in works fine, but to future proof things, I do it this way.
LinearLayout linearLayout = new LinearLayout(measuringActivity = this);
LinearLayout.LayoutParams matchParent = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
MeasureFrameLayout measureFrameLayout = new MeasureFrameLayout(this);
measureFrameLayout.setLayoutParams(matchParent);
linearLayout.addView(measureFrameLayout);
this.addContentView(linearLayout, matchParent);
// measureFrameLayout will now request this second activity to finish, sending back the width.
}
}
@Override
protected void onActivityResult (int requestCode, int resultCode, Intent data) {
// Probably can never happen, but just in case.
if (resultCode == RESULT_CANCELED) {
finish();
return;
}
int width = data.getIntExtra("Width", -3);
// Width is now set to the precise available width, and a layout can now be created.
...
}
class MeasureFrameLayout extends FrameLayout {
boolean finished = false;
public MeasureFrameLayout(Context context) {
super(context);
}
@SuppressLint("DrawAllocation")
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (finished) {
return;
}
finished = true;
// Send the width back as the result.
Intent data = new Intent().putExtra("Width", MeasureSpec.getSize(widthMeasureSpec));
MainActivity.measuringActivity.setResult(Activity.RESULT_OK, data);
// Tell the (second) activity to finish.
MainActivity.measuringActivity.finish();
}
}
如果您不想要 WindowManagers、Points 或 Displays 的开销,您可以获取 XML 中最顶层 View 项的 height 和 width 属性,前提是它的 height 和 width 设置为 match_parent。 (只要您的布局占据整个屏幕,情况就是如此。)
例如,如果您的 XML 以这样的开头:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/entireLayout"
android:layout_width="match_parent"
android:layout_height="match_parent" >
然后 findViewById(R.id.entireLayout).getWidth()
将返回屏幕的宽度,而 findViewById(R.id.entireLayout).getHeight()
将返回屏幕的高度。
不定期副业成功案例分享
try/catch
进行此类检查?为什么不简单地使用if (android.os.Build.VERSION.SDK_INT >= 13)
而不抛出任何异常?我认为正常应用流程中的try/catch
是不好的做法。