如何设置AutoCompleteTextView下拉框高度为距屏幕底部60dp?
Hey there! Let's tackle that AutoCompleteTextView dropdown height compatibility issue once and for all. Your current code works on the Huawei P9 Lite (Android 7.0) but breaks on other devices for a few key reasons: you're mixing up dp and pixel values, not accounting for system UI elements like status/navigation bars, and not waiting for the view to fully layout before calculating dimensions. Here's a robust, cross-device solution:
First, Fix the DP-to-Pixel Conversion
The setDropDownHeight() method expects a pixel value, but your original code calculates a dp value and passes it directly—this is a critical mistake. Let's start with a helper method to safely convert dp to pixels:
private int dpToPx(int dp) { return Math.round(dp * getResources().getDisplayMetrics().density); }
Get the Real Available Screen Height
To avoid issues with status bars, navigation bars, or different Android versions, we need to calculate the actual usable screen space the app can access:
private int getAvailableScreenHeight() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { // Android 11+ uses WindowMetrics for accurate window bounds WindowMetrics windowMetrics = getWindowManager().getCurrentWindowMetrics(); Insets insets = windowMetrics.getWindowInsets() .getInsetsIgnoringVisibility(WindowInsets.Type.systemBars()); return windowMetrics.getBounds().height() - insets.top - insets.bottom; } else { // Legacy method for older Android versions DisplayMetrics displayMetrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); return displayMetrics.heightPixels - getStatusBarHeight() - getNavigationBarHeight(); } } // Helper to get status bar height private int getStatusBarHeight() { int result = 0; int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android"); if (resourceId > 0) { result = getResources().getDimensionPixelSize(resourceId); } return result; } // Helper to get navigation bar height (only if it exists) private int getNavigationBarHeight() { int result = 0; int resourceId = getResources().getIdentifier("navigation_bar_height", "dimen", "android"); if (resourceId > 0 && hasNavigationBar()) { result = getResources().getDimensionPixelSize(resourceId); } return result; } // Check if navigation bar is present on the device private boolean hasNavigationBar() { boolean hasNavBar = false; Resources res = getResources(); int configId = res.getIdentifier("config_showNavigationBar", "bool", "android"); if (configId > 0) { hasNavBar = res.getBoolean(configId); } // Override for emulator scenarios try { Class<?> systemProps = Class.forName("android.os.SystemProperties"); Method getProp = systemProps.getMethod("get", String.class); String navOverride = (String) getProp.invoke(systemProps, "qemu.hw.mainkeys"); if ("1".equals(navOverride)) hasNavBar = false; else if ("0".equals(navOverride)) hasNavBar = true; } catch (Exception e) { e.printStackTrace(); } return hasNavBar; }
Set Dropdown Height Properly
If you want the dropdown's bottom edge to be 60dp above the screen bottom (regardless of where the AutoCompleteTextView is placed), use this:
int availableHeight = getAvailableScreenHeight(); int bottomMarginPx = dpToPx(60); int dropdownHeight = availableHeight - bottomMarginPx; edtSeach.setDropDownHeight(dropdownHeight);
Even Better: Account for the AutoCompleteTextView's Position
If you want the dropdown to expand from the bottom of the input field to 60dp above the screen bottom (the more common use case), use a ViewTreeObserver to wait for the view to finish layout before calculating:
edtSeach.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { // Remove the listener to avoid repeated calls if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { edtSeach.getViewTreeObserver().removeOnGlobalLayoutListener(this); } else { edtSeach.getViewTreeObserver().removeGlobalOnLayoutListener(this); } // Get the bottom position of the AutoCompleteTextView on screen int[] viewLocation = new int[2]; edtSeach.getLocationOnScreen(viewLocation); int viewBottomY = viewLocation[1] + edtSeach.getHeight(); // Get the screen's bottom edge (minus navigation bar) DisplayMetrics displayMetrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); int screenBottomY = displayMetrics.heightPixels - getNavigationBarHeight(); // Calculate maximum dropdown height int bottomMarginPx = dpToPx(60); int dropdownHeight = screenBottomY - viewBottomY - bottomMarginPx; // Ensure we don't set a negative height if (dropdownHeight > 0) { edtSeach.setDropDownHeight(dropdownHeight); } } });
Why This Works Across All Devices
- Correct unit conversion: No more mixing dp and pixels—every dimension is properly scaled for the device's screen density.
- System UI awareness: We subtract status and navigation bar heights so the dropdown doesn't get hidden or overflow off-screen.
- Layout safety: Using
ViewTreeObserverensures we only calculate dimensions after the view has fully rendered, avoiding incorrect values. - Version compatibility: We use modern APIs for Android 11+ and fallback to reliable legacy methods for older devices.
内容的提问来源于stack exchange,提问作者user2872856

