为RecyclerView中Button添加渐变背景时出现Inflation错误
在使用MaterialComponents主题、最低SDK为API 21的环境中,为RecyclerView书籍列表项的Button设置带渐变效果的自定义背景(roundbutton.xml)时,出现android.view.InflateException布局加载错误。
相关代码
book_item.xml(列表项布局)
. . . <Button android:id="@+id/read_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="12dp" android:text="Start Reading" android:background="@drawable/roundbutton" app:backgroundTint="@null" /> . . .
roundbutton.xml(自定义背景Drawable)
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <gradient android:endColor="@color/dark_orange" android:startColor="@color/orange" android:angle="200" /> <corners android:bottomRightRadius="100px" android:bottomLeftRadius="100px" android:topRightRadius="100px" android:topLeftRadius="100px"/> </shape>
BookAdapterOne.kt(RecyclerView适配器)
class BookAdapterOne( private val context: Context, private var data: List<Book>, private val bookClickListener: BookClickListener ) : RecyclerView.Adapter<BookAdapterOne.ItemViewHolder>() { class ItemViewHolder(private val view: View) : RecyclerView.ViewHolder(view) { val title: TextView = view.findViewById(R.id.book_title) val author: TextView = view.findViewById(R.id.book_author) val description: TextView = view.findViewById(R.id.book_description) val read_btn: Button = view.findViewById(R.id.read_btn) } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder { val adapterLayout = LayoutInflater.from(parent.context) .inflate(R.layout.book_item, parent, false) return ItemViewHolder(adapterLayout) } override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { val item = data[position] holder.title.text = item.title holder.author.text = item.author holder.description.text = item.description holder.read_btn.setOnClickListener { bookClickListener.onBookClickListener(item) } } }
错误日志
E/AndroidRuntime: FATAL EXCEPTION: main Process: com.sapphire.littlered, PID: 5920 android.view.InflateException: Binary XML file line #51: Error inflating class Button at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:770) at android.view.LayoutInflater.rInflate(LayoutInflater.java:813) at android.view.LayoutInflater.rInflate(LayoutInflater.java:821) at android.view.LayoutInflater.inflate(LayoutInflater.java:511) at android.view.LayoutInflater.inflate(LayoutInflater.java:415) at com.sapphire.littlered.adapter.BookAdapterOne.onCreateViewHolder(BookAdapterOne.kt:33) at com.sapphire.littlered.adapter.BookAdapterOne.onCreateViewHolder(BookAdapterOne.kt:18) at androidx.recyclerview.widget.RecyclerView$Adapter.createViewHolder(RecyclerView.java:7078) at androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:6235) at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6118) at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6114) at androidx.recyclerview.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2303) at androidx.recyclerview.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1627) at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1587) at androidx.recyclerview.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:665) at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:4134) at androidx.recyclerview.widget.RecyclerView.dispatchLayout(RecyclerView.java:3851) at androidx.recyclerview.widget.RecyclerView.onLayout(RecyclerView.java:4404) at android.view.View.layout(View.java:16992) at android.view.ViewGroup.layout(ViewGroup.java:5409) at android.widget.RelativeLayout.onLayout(RelativeLayout.java:1077) at android.view.View.layout(View.java:16992) at android.view.ViewGroup.layout(ViewGroup.java:5409) at android.widget.FrameLayout.layoutChildren(FrameLayout.java:579) at android.widget.FrameLayout.onLayout(FrameLayout.java:514) at android.view.View.layout(View.java:16992) at android.view.ViewGroup.layout(ViewGroup.java:5409) at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1702) at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1556) at android.widget.LinearLayout.onLayout(LinearLayout.java:1465) at android.view.View.layout(View.java:16992) at android.view.ViewGroup.layout(ViewGroup.java:5409) at android.widget.FrameLayout.layoutChildren(FrameLayout.java:579) at android.widget.FrameLayout.onLayout(FrameLayout.java:514) at android.view.View.layout(View.java:16992) at android.view.ViewGroup.layout(ViewGroup.java:5409) at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1702) at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1556) at android.widget.LinearLayout.onLayout(LinearLayout.java:1465) at android.view.View.layout(View.java:16992) at android.view.ViewGroup.layout(ViewGroup.java:5409) at android.widget.FrameLayout.layoutChildren(FrameLayout.java:579) at android.widget.FrameLayout.onLayout(FrameLayout.java:514) at android.view.View.layout(View.java:16992) at android.view.ViewGroup.layout(ViewGroup.java:5409) at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2483) at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2185) at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1314) at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7057) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:829) at android.view.Choreographer.doCallbacks(Choreographer.java:606) at android.view.Choreographer.doFrame(Choreographer.java:576) at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:815) at android.os.Handler.handleCallback(Handler.java:739) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:145) at android.app.ActivityThread.main( I/Process: Sending signal. PID: 5920 SIG: 9
解决方案
核心原因
使用MaterialComponents主题时,系统会自动将默认Button替换为MaterialButton,而MaterialButton对自定义android:background的兼容性较差——即使设置了app:backgroundTint="@null",在API21这类低版本系统中仍会因内部视图逻辑冲突导致Inflate失败。
修复步骤
替换Button为AppCompatButton
将布局中的Button改为androidx.appcompat.widget.AppCompatButton,它兼容API21+,且能正常加载自定义shape背景,无需额外设置backgroundTint:<androidx.appcompat.widget.AppCompatButton android:id="@+id/read_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="12dp" android:text="Start Reading" android:background="@drawable/roundbutton" />统一单位为dp
将roundbutton.xml中的px单位改为dp,保证不同分辨率设备显示一致,同时简化圆角写法:<corners android:radius="100dp"/>验证颜色资源
确认@color/orange和@color/dark_orange已在res/values/colors.xml中正确定义,避免因资源缺失导致加载错误:<color name="orange">#FF9800</color> <color name="dark_orange">#F57C00</color>
备选方案(若坚持用MaterialButton)
如果必须使用MaterialButton,可以通过代码动态设置背景:
// 在Adapter的onBindViewHolder中添加 val drawable = ContextCompat.getDrawable(context, R.drawable.roundbutton) holder.read_btn.background = drawable
但此方法在API21上的兼容性仍不如AppCompatButton稳定。
内容的提问来源于stack exchange,提问作者Luke Wardford
相关产品推荐
相关产品推荐

