我在调试我的应用程序时,将鼠标悬停在ImageView引用上时发现,它是AppCompatImageView而不是ImageViewTextView(带有AppCompatTextView)也发生了同样的情况。

android - 当我没有明确声明它们时,为什么Android选择AppCompat组件?-LMLPHP

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

另一方面,在处理矢量图像时,我使用的是ImageView,但由于没有使用AppCompatImageView而使用了解决方案,因此出现了问题:

ImageView not displaying correctly in the device

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

最佳答案

简短的回答:“从现在开始,我应该只是从一个 Activity 中扩展吗?”是,您应该继续扩展AppCompatActivity,因为它为较旧的设备提供了向后兼容的功能。如果是 AppCompatImageView :



此外,它还为旧版Android增加了与矢量可绘制对象的兼容性。

有关不一致的说明

AppCompatImageView 中所述:



因此,这并不意外。

工作原理
AppCompatActivity安装LayoutInflater.Factory2来拦截某些 View 的膨胀。该充气机的代码可以在AppCompatViewInflater.java中看到。

负责创建Views的函数是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

因此,为了在仍然使用ImageView的情况下强制创建常规AppCompatImageView(无AppCompatActivity),您需要指定完整的类名,例如:
    <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/

10-08 21:08