You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android平台下Python/Kivy/Pyjnius获取屏幕分辨率方法问询

在Kivy Android应用中正确获取屏幕分辨率的方法

你遇到的问题主要有两个核心原因:一是DisplayMetrics实例没有被正确填充设备数据,二是获取屏幕信息的时机过早,另外getDeviceDensity()确实不是DisplayMetrics的官方方法,应该用density属性来替代。下面给你几个可行的解决方案:

一、修复Pyjnius的DisplayMetrics调用方式

直接实例化DisplayMetrics不会自动填充设备的真实显示数据,你需要通过Android的WindowManager来获取当前显示的Metrics信息。修改后的代码如下:

from kivy.app import App
from kivy.uix.button import Button
from kivy.utils import platform
from kivy.core.window import Window

myheight = -100
mywidth = -100
myDPI = -100
gDPI = -100
Window.fullscreen = True

if platform == 'android':
    from jnius import autoclass, cast
    # 获取Android核心类
    Activity = autoclass('android.app.Activity')
    DisplayMetrics = autoclass('android.util.DisplayMetrics')
    WindowManager = autoclass('android.view.WindowManager')
    
    # 获取当前Activity实例
    activity = cast('android.app.Activity', Activity.mActivity)
    # 获取WindowManager服务
    window_manager = activity.getSystemService(WindowManager.WINDOW_SERVICE)
    # 获取默认Display对象
    display = window_manager.getDefaultDisplay()
    
    metrics = DisplayMetrics()
    # 关键步骤:调用getMetrics填充真实数据
    display.getMetrics(metrics)
    
    # 正确获取属性值
    gDPI = metrics.density  # 设备密度系数(如1.0、2.0等)
    myheight = metrics.heightPixels
    mywidth = metrics.widthPixels
    myDPI = metrics.densityDpi

class MainApp(App):
    def build(self):
        b = Button(
            text=f"Height: {myheight}\nWidth: {mywidth}\nDPI: {myDPI}\ndensity: {gDPI}\nWindow.size: {Window.size}",
            color=[0,0,0,1]
        )
        return b

MainApp().run()

二、利用Kivy自身Window获取(推荐)

Kivy的Window其实可以获取真实分辨率,但要注意获取时机——不能在App启动前直接获取,应该在App的on_start方法或者build方法之后执行,因为Window需要时间完成初始化。示例代码:

from kivy.app import App
from kivy.uix.button import Button
from kivy.core.window import Window
from kivy.utils import platform

class MainApp(App):
    def build(self):
        Window.fullscreen = True
        self.button = Button(color=[0,0,0,1])
        return self.button

    def on_start(self):
        # 此时Window已完成初始化,可获取真实尺寸
        window_width, window_height = Window.size
        dpi = None
        density = None

        if platform == 'android':
            # 结合Pyjnius获取DPI信息
            from jnius import autoclass, cast
            Activity = autoclass('android.app.Activity')
            DisplayMetrics = autoclass('android.util.DisplayMetrics')
            activity = cast('android.app.Activity', Activity.mActivity)
            metrics = DisplayMetrics()
            activity.getWindowManager().getDefaultDisplay().getMetrics(metrics)
            dpi = metrics.densityDpi
            density = metrics.density
        else:
            dpi = Window.dpi
            density = Window.density

        self.button.text = (
            f"Window Size: {window_width}x{window_height}\n"
            f"DPI: {dpi}\n"
            f"Density: {density}"
        )

MainApp().run()

三、直接调用SDL2获取屏幕信息

Kivy底层基于SDL2,你可以用ctypes直接调用SDL2的API获取显示模式信息,这种方法更贴近底层,适合对精度要求高的场景:

from kivy.app import App
from kivy.uix.button import Button
from kivy.utils import platform
import ctypes

class MainApp(App):
    def build(self):
        self.button = Button(color=[0,0,0,1])
        return self.button

    def on_start(self):
        if platform != 'android':
            self.button.text = "此方法仅适用于Android平台"
            return

        # 加载SDL2动态库
        sdl2 = ctypes.CDLL('libSDL2.so')

        # 定义SDL_DisplayMode结构体
        class SDL_DisplayMode(ctypes.Structure):
            _fields_ = [
                ("format", ctypes.c_uint32),
                ("w", ctypes.c_int),
                ("h", ctypes.c_int),
                ("refresh_rate", ctypes.c_int),
                ("driverdata", ctypes.c_void_p)
            ]

        # 获取主显示器的桌面显示模式
        mode = SDL_DisplayMode()
        result = sdl2.SDL_GetDesktopDisplayMode(0, ctypes.byref(mode))
        if result == 0:
            width = mode.w
            height = mode.h
            # 获取DPI相关数据
            ddpi = ctypes.c_float()
            hdpi = ctypes.c_float()
            vdpi = ctypes.c_float()
            sdl2.SDL_GetDisplayDPI(0, ctypes.byref(ddpi), ctypes.byref(hdpi), ctypes.byref(vdpi))
            
            self.button.text = (
                f"SDL2 Screen Size: {width}x{height}\n"
                f"DDPI: {ddpi.value}\n"
                f"HDPI: {hdpi.value}\n"
                f"VDPI: {vdpi.value}"
            )
        else:
            self.button.text = "SDL2获取屏幕信息失败"

MainApp().run()

关键注意事项

  • 获取时机:所有获取屏幕信息的操作都应该在App的on_start方法中执行,或者在build方法之后,因为此时应用已经完成初始化,Window/Android系统的显示信息才会被正确加载。
  • 全屏模式:务必设置Window.fullscreen = True,否则Kivy可能会使用默认的窗口尺寸(比如800x480),导致获取的尺寸不准确。

内容的提问来源于stack exchange,提问作者lokapal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 23:57:35