为什么Android在我没有明确声明它们时会选择AppCompat组件?

时间:2017-08-16 10:20:44

标签: android android-appcompat

我正在调试我的应用程序,并在ImageView引用时发现,它是AppCompatImageView而不是ImageViewTextViewAppCompatTextView)也是如此。

enter image description here

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

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

ImageView not displaying correctly in the device

这种不一致的行为让我对我应该遵循的做法感到困惑。我应该从现在开始延伸一个活动吗?

3 个答案:

答案 0 :(得分:6)

简短回答“我应该从现在开始延伸活动吗?”不,你应该继续扩展AppCompatActivity,因为它为旧设备提供了向后兼容的功能。如果是AppCompatImageView

  

ImageView支持旧版平台上的兼容功能,包括:

     
      
  • 允许通过ViewCompat中的背景色调方法动态显示其背景色。
  •   
  • 允许使用backgroundTint和backgroundTintMode设置背景色调。
  •   
  • 允许通过ImageViewCompat中的图像色调方法动态着色其图像。
  •   
  • 允许使用tint和tintMode设置图像色调。
  •   

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

有关不一致的说明

正如AppCompatImageView中所述:

  

当您在布局中使用ImageView并且appcompat提供顶级活动/对话框时,将自动使用此选项。

所以,这并不意外。

工作原理

AppCompatActivity安装LayoutInflater.Factory2来拦截某些观点的通胀。可以在AppCompatViewInflater.java中看到此inflater的代码。

负责创建Views的函数是AppCompatViewInflater#createView(View, String, Context, AttributeSet, boolean, boolean, boolean, boolean),正如您在此处所看到的,它检查简单的视图名称(没有前缀的包),并创建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视图

因此,为了在使用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”。

答案 1 :(得分:1)

  

我应该从现在开始延伸一个活动吗?

否。普通组件(Activity)或Compat组件(AppCompatActivity)之间的区别在于Compat组件旨在支持旧设备中的最新UI组件。它提供了向后兼容性,因此如果您支持各种各样的设备,则需要它。

  

虽然我对这种行为没有特别的问题,因为它的AppCompat毕竟是

是的,你是对的,当在AppCompatActivity中使用Image视图时,普通的图像视图将被转换为AppCompatImageView。

AppCompatImageView

请点击此链接阅读有关AppCompatImageView的更多信息。

答案 2 :(得分:-1)

AppCompatImageView的工作方式与ImageView相同。支持库AppCompat仅用于向后兼容。因此,如果您希望您的应用程序向后兼容,则应扩展AppCompat类。