如何找到下拉菜单视图的显示部分

huangapple go评论72阅读模式
英文:

How to find a spinner's displayed drop down views

问题

我的公司的应用支持在运行时动态更改主题,而无需重新启动当前活动。它通过遍历视图层次结构,并对每个配置为支持主题更改的视图应用样式来实现此功能。然而,我遇到的问题是,在遍历视图层次结构时,永远无法找到显示在下拉框中的下拉视图(drop down Views)。以下是从活动中查找每个视图的代码:

void applyTheme(final int resourceId) {
    setTheme(resourceId);

    // 将主题应用于活动的视图。
    styleView(findViewById(android.R.id.content));

    // 将主题应用于任何对话框片段。
    final List<Fragment> fragments = getSupportFragmentManager().getFragments();
    for (final Fragment fragment : fragments) {
        if (fragment instanceof DialogFragment) {
            final Dialog dialog = ((DialogFragment)fragment).getDialog();
            if (dialog != null) {
                final Window window = dialog.getWindow();
                if (window != null) {
                    styleView(window.getDecorView());
                }
            }
        }
    }
}

void styleView(final View view) {
    // 在这里应用样式。
    ...

    // 递归查找所有子视图并对其应用主题。
    if (view instanceof ViewGroup) {
        final ViewGroup viewGroup = (ViewGroup)view;
        for (int i = 0; i < viewGroup.getChildCount(); i++) {
            styleView(viewGroup.getChildAt(i));
        }
    }
}

无论父级 Spinner 是否在活动、片段或对话框片段中定义,都无法找到下拉视图(drop down Views)。如果下拉视图对用户可见,是否有办法实际检索到它们的引用?

英文:

My company's app supports changing the theme dynamically at runtime without having to restart the current Activity. It does this by walking the View tree and applying styles to each View that is configured to support it. The issue I'm running into, however, is that the drop down Views that are displayed for Spinners are never found when walking the View tree. This is the code for finding each View from the Activity:

void applyTheme(final int resourceId) {
	setTheme(resourceId);

	// Apply the theme to the activity&#39;s view.
	styleView(findViewById(android.R.id.content));

	// Apply the theme to any dialog fragments.
	final List&lt;Fragment&gt; fragments = getSupportFragmentManager().getFragments();
	for (final Fragment fragment : fragments) {
		if (fragment instanceof DialogFragment) {
			final Dialog dialog = ((DialogFragment)fragment).getDialog();
			if (dialog != null) {
				final Window window = dialog.getWindow();
				if (window != null) {
					styleView(window.getDecorView());
				}
			}
		}
	}
}

void styleView(final View view) {
	// Apply styling here.
	...

	// Recursively find all children and apply the theme to them.
	if (view instanceof ViewGroup) {
		final ViewGroup viewGroup = (ViewGroup)view;
		for (int i = 0; i &lt; viewGroup.getChildCount(); i++) {
			styleView(viewGroup.getChildAt(i));
		}
	}
}

The drop down views are not found no matter if the parent Spinner is defined in the Activity, a Fragment, or a DialogFragment. If the drop down Views are visible to the user, is there any way to actually retrieve references to them?

答案1

得分: 0

private Object wmgInstance = null;
private Method getViewRootNames = null;
private Method getRootView = null;

private void applyTheme(final int resourceId) {
    setTheme(resourceId);

    try {
        // Find all possible root views (the Activity, any PopupWindows, and Dialogs). This logic should work with APIs 17-28.
        if (wmgInstance == null) {
            final Class wmgClass = Class.forName("android.view.WindowManagerGlobal");
            wmgInstance = wmgClass.getMethod("getInstance").invoke(null, (Object[])null);

            getViewRootNames = wmgClass.getMethod("getViewRootNames");
            getRootView = wmgClass.getMethod("getRootView", String.class);
        }

        final String[] rootViewNames = (String[])getViewRootNames.invoke(wmgInstance, (Object[])null);

        for (final String viewName : rootViewNames) {
            final View rootView = (View)getRootView.invoke(wmgInstance, viewName);
            styleView(rootView);
        }
    } catch (Exception e) {
        // Log the exception.
    }
}

This logic successfully allowed me to update the Spinner's drop down Views when they were visible during a theme change. However, there still remained an issue that if the Spinner's drop down Views were created before the theme change occurred, but the drop down was closed at the time of the theme change, then re-opening the Spinner showed the Views using the old theme. The way I handled this was just to call `styleView()` on the View within my adapter's `getDropDownView()`.
英文:

This answer provided me a means to find all Views, including those of PopupWindows. Unfortunately, it makes use of reflection and is not guaranteed to work on all API versions, but it appears to work on the APIs that our app supports (I tested on APIs 19 and 28). This is the result of the changes to applyTheme():

private Object wmgInstance = null;
private Method getViewRootNames = null;
private Method getRootView = null;

private void applyTheme(final int resourceId)
{
	setTheme(resourceId);

	try
	{
		// Find all possible root views (the Activity, any PopupWindows, and Dialogs). This logic should work with APIs 17-28.
		if (wmgInstance == null)
		{
			final Class wmgClass = Class.forName(&quot;android.view.WindowManagerGlobal&quot;);
			wmgInstance = wmgClass.getMethod(&quot;getInstance&quot;).invoke(null, (Object[])null);

			getViewRootNames = wmgClass.getMethod(&quot;getViewRootNames&quot;);
			getRootView = wmgClass.getMethod(&quot;getRootView&quot;, String.class);
		}

		final String[] rootViewNames = (String[])getViewRootNames.invoke(wmgInstance, (Object[])null);

		for (final String viewName : rootViewNames)
		{
			final View rootView = (View)getRootView.invoke(wmgInstance, viewName);
			styleView(rootView);
		}
	}
	catch (Exception e)
	{
		// Log the exception.
	}
}

This logic successfully allowed me to update the Spinner's drop down Views when they were visible during a theme change. However, there still remained an issue that if the Spinner's drop down Views were created before the theme change occurred, but the drop down was closed at the time of the theme change, then re-opening the Spinner showed the Views using the old theme. The way I handled this was just to call styleView() on the View within my adapter's getDropDownView().

huangapple
  • 本文由 发表于 2020年4月10日 06:04:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/61130974.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定