android - 为什么我没有明确声明 Android 会选择 AppCompat 组件?

标签 android android-appcompat

我在调试我的应用程序时发现,当鼠标悬停在 ImageView 引用上时,它是一个 AppCompatImageView 而不是 ImageViewTextView(使用 AppCompatTextView)也是如此。

enter image description here

虽然我对这种行为没有特别的问题,因为它毕竟是 AppCompat,但在检查其他开发人员的代码时,我看到,extends Activity 而不是 AppCompatActivity 我几乎将其标记为“不良做法”。

另一方面,在处理矢量图像时,我使用了 ImageView 并且出现了问题,因为我没有使用 AppCompatImageView 而使用它是解决方案:

ImageView not displaying correctly in the device

这种不一致的行为确实让我对我应该遵循的做法感到困惑。我是否应该从现在开始扩展 Activity?

最佳答案

对“我应该从现在开始扩展 Activity 吗?”的简短回答不,您应该继续扩展 AppCompatActivity,因为它向旧设备提供向后兼容的功能。在AppCompatImageView的情况下:

A ImageView which supports compatible features on older versions of the platform, including:

  • Allows dynamic tint of its background via the background tint methods in ViewCompat.
  • Allows setting of the background tint using backgroundTint and backgroundTintMode.
  • Allows dynamic tint of its image via the image tint methods in ImageViewCompat.
  • Allows setting of the image tint using tint and tintMode.

此外,它还增加了与适用于旧版 Android 的矢量绘图的兼容性。

关于不一致的解释

AppCompatImageView 中所述:

This will automatically be used when you use ImageView in your layouts and the top-level activity / dialog is provided by appcompat.

所以,这并不意外。

工作原理

AppCompatActivity 安装一个 LayoutInflater.Factory2 来拦截某些 View 的膨胀。这个充气机的代码可以在AppCompatViewInflater.java中看到.

负责创建 View 的函数是AppCompatViewInflater#createView(View, String, Context, AttributeSet, boolean, boolean, boolean, boolean),你可以看到这里它检查简单的 View 名称(没有包前缀),并创建 AppCompat* 版本:

public final View createView(View parent, final String name, @NonNull Context context,
        @NonNull AttributeSet attrs, boolean inheritContext,
        boolean readAndroidTheme, boolean readAppTheme, boolean wrapContext) {
    final Context originalContext = context;

    // ...

    View view = null;

    // We need to 'inject' our tint aware Views in place of the standard framework versions
    switch (name) {
        case "TextView":
            view = new AppCompatTextView(context, attrs);
            break;
        case "ImageView":
            view = new AppCompatImageView(context, attrs);
            break;
        case "Button":
            view = new AppCompatButton(context, attrs);
            break;
        case "EditText":
            view = new AppCompatEditText(context, attrs);
            break;
        case "Spinner":
            view = new AppCompatSpinner(context, attrs);
            break;
        case "ImageButton":
            view = new AppCompatImageButton(context, attrs);
            break;
        case "CheckBox":
            view = new AppCompatCheckBox(context, attrs);
            break;
        case "RadioButton":
            view = new AppCompatRadioButton(context, attrs);
            break;
        case "CheckedTextView":
            view = new AppCompatCheckedTextView(context, attrs);
            break;
        case "AutoCompleteTextView":
            view = new AppCompatAutoCompleteTextView(context, attrs);
            break;
        case "MultiAutoCompleteTextView":
            view = new AppCompatMultiAutoCompleteTextView(context, attrs);
            break;
        case "RatingBar":
            view = new AppCompatRatingBar(context, attrs);
            break;
        case "SeekBar":
            view = new AppCompatSeekBar(context, attrs);
            break;
    }

    if (view == null && originalContext != context) {
        // If the original context does not equal our themed context, then we need to manually
        // inflate it using the name so that android:theme takes effect.
        view = createViewFromTag(context, name, attrs);
    }

    // ...

    return view;
}

强制使用非 AppCompat View

因此,为了在仍然使用 AppCompatActivity 的同时强制创建常规 ImageView(没有 AppCompatImageView),您需要指定完整的类名,例如:

    <android.widget.ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@mipmap/test"/>

有关布局膨胀如何工作的更多信息,请参阅 LayoutInflater: Friend or Foe? 的精彩演讲“Chris Jenx” ,Calligraphy 的作者.

关于android - 为什么我没有明确声明 Android 会选择 AppCompat 组件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45710962/

相关文章:

android - 未调用 fragment onResume

java - 安卓测试: verify onClickListener using private anonymous class

android - RecyclerView notifyDataSetChanged 滚动到顶部位置

list 中的 Android appcompat 工具栏标题

android - 在不重新创建 Activity 的情况下更改应用程序主题

android - MapFragment 的 onCreateView 中的 StackOverFlowError

android - JodaTime - 如何将 ISO 8601 时间字符串解析为 DateTime?

android - 如何将存储在设备中的图像与使用相机扫描的帧值进行比较?

android - TextInputLayout 错误文本填充

java - Android 启动时崩溃 : Styling the ActionBar Theme App. 兼容