I'm trying to add a unique floating action button to every item in a recycler grid view. I tried changing the theme to MaterialComponent
but that didn't work. The error tells me the crash is occurring during inflation and that my theme is not AppCompat
even though it is in styles. I think I might just have to add something into the XML but I am unsure. Does anyone know how to fix this?
Error:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.imagegridactivity, PID: 17829
android.view.InflateException: Binary XML file line #36 in com.example.imagegridactivity:layout/custom_view: Binary XML file line #36 in com.example.imagegridactivity:layout/custom_view: Error inflating class com.google.android.material.floatingactionbutton.FloatingActionButton
Caused by: android.view.InflateException: Binary XML file line #36 in com.example.imagegridactivity:layout/custom_view: Error inflating class com.google.android.material.floatingactionbutton.FloatingActionButton
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Constructor.newInstance0(Native Method)
at java.lang.reflect.Constructor.newInstance(Constructor.java:343)
at android.view.LayoutInflater.createView(LayoutInflater.java:854)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:1006)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:961)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:1123)
at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:1084)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:1126)
at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:1084)
at android.view.LayoutInflater.inflate(LayoutInflater.java:682)
at android.view.LayoutInflater.inflate(LayoutInflater.java:534)
at com.example.imagegridactivity.AnimalsAdapter.onCreateViewHolder(AnimalsAdapter.java:135)
at com.example.imagegridactivity.AnimalsAdapter.onCreateViewHolder(AnimalsAdapter.java:29)
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.GridLayoutManager.layoutChunk(GridLayoutManager.java:561)
at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1587)
at androidx.recyclerview.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:665)
at androidx.recyclerview.widget.GridLayoutManager.onLayoutChildren(GridLayoutManager.java:170)
at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:4134)
at androidx.recyclerview.widget.RecyclerView.onMeasure(RecyclerView.java:3540)
at android.view.View.measure(View.java:25086)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6872)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1552)
at android.widget.LinearLayout.measureHorizontal(LinearLayout.java:1204)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:723)
at android.view.View.measure(View.java:25086)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6872)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1552)
at android.widget.LinearLayout.measureHorizontal(LinearLayout.java:1204)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:723)
at android.view.View.measure(View.java:25086)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6872)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
at androidx.appcompat.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.java:143)
at android.view.View.measure(View.java:25086)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6872)
at androidx.appcompat.widget.ActionBarOverlayLayout.onMeasure(ActionBarOverlayLayout.java:403)
at android.view.View.measure(View.java:25086)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6872)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
at android.view.View.measure(View.java:25086)
E/AndroidRuntime: at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6872)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1552)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:842)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:721)
at android.view.View.measure(View.java:25086)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6872)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
at com.android.internal.policy.DecorView.onMeasure(DecorView.java:742)
at android.view.View.measure(View.java:25086)
at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:3083)
at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1857)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2146)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1745)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7768)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:967)
at android.view.Choreographer.doCallbacks(Choreographer.java:791)
at android.view.Choreographer.doFrame(Choreographer.java:726)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:952)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
Caused by: java.lang.IllegalArgumentException: The style on this component requires your app theme to be Theme.AppCompat (or a descendant).
at com.google.android.material.internal.ThemeEnforcement.checkTheme(ThemeEnforcement.java:248)
at com.google.android.material.internal.ThemeEnforcement.checkAppCompatTheme(ThemeEnforcement.java:218)
at com.google.android.material.internal.ThemeEnforcement.checkCompatibleTheme(ThemeEnforcement.java:153)
at com.google.android.material.internal.ThemeEnforcement.obtainStyledAttributes(ThemeEnforcement.java:81)
at com.google.android.material.floatingactionbutton.FloatingActionButton.<init>(FloatingActionButton.java:212)
at com.google.android.material.floatingactionbutton.FloatingActionButton.<init>(FloatingActionButton.java:201)
Adapter:
public class AnimalsAdapter extends RecyclerView.Adapter<AnimalsAdapter.ViewHolder> {
ImageView imageView;
FloatingActionButton floatingActionButton;
private Uri imageUri;
private ArrayList<animal_item> mDataSet;
private Context mContext;
private OnItemClickListener mListener;
public ArrayList<animal_item> getDataSet() {
return mDataSet;
}
public void setDataSet(ArrayList<animal_item> mDataSet) {
this.mDataSet = mDataSet;
}
public ImageView getImageView() {
return imageView;
}
public void setImageView(ImageView imageView) {
this.imageView = imageView;
}
public Context getContext() {
return mContext;
}
public void setContext(Context mContext) {
this.mContext = mContext;
}
public Uri getImageUri() {
return imageUri;
}
public void setImageUri(Uri imageUri) {
this.imageUri = imageUri;
}
public interface OnItemClickListener {
void onItemClick(int position);
}
public void setOnItemClickListener(OnItemClickListener listener) {
mListener = listener;
}
public AnimalsAdapter(Context context, ArrayList<animal_item> DataSet) {
mDataSet = DataSet;
mContext = context;
}
public ArrayList<animal_item> DataSet() {
return mDataSet;
}
public static class ViewHolder extends RecyclerView.ViewHolder {
public ImageView mImageView;
public FloatingActionButton mFloatingActionButton;
public RelativeLayout mLinearLayout;
public ViewHolder(View v, final OnItemClickListener listener) {
super(v);
mImageView = (ImageView) v.findViewById(R.id.tv);
mFloatingActionButton = (FloatingActionButton) v.findViewById(R.id.floatingActionButton);
mImageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (listener != null) {
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) ;
listener.onItemClick(position);
}
}
});
mLinearLayout = (RelativeLayout) v.findViewById(R.id.ll);
}
public ImageView getImageView() {
return mImageView;
}
public void setImageView(ImageView mImageView) {
this.mImageView = mImageView;
}
}
@Override
public AnimalsAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(mContext).inflate(R.layout.custom_view, parent, false);
ViewHolder vh = new ViewHolder(v, (OnItemClickListener) mListener);
return vh;
}
@Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
final animal_item animalItem = mDataSet.get(position);
holder.mImageView.setImageResource(animalItem.getImageResource());
imageView = holder.mImageView;
}
@Override
public int getItemCount() {
return mDataSet.size();
}
}
Custom view:
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="@+id/card_view"
android:layout_width="123dp"
android:layout_height="123dp"
card_view:cardElevation="0dp"
card_view:cardMaxElevation="0dp"
card_view:contentPadding="0dp">
<RelativeLayout
android:id="@+id/ll"
android:layout_width="110dp"
android:layout_height="110dp"
android:padding="0dp"
android:orientation="horizontal">
<ImageButton
android:id="@+id/tv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:layout_margin="0dp"
android:gravity="center"
android:padding="0dp"
android:textColor="#000"
android:textSize="25dp"
android:textStyle="bold"
/>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/floatingActionButton"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginStart="95dp"
android:layout_marginLeft="95dp"
android:layout_marginTop="96dp"
android:layout_weight="1"
android:clickable="true"
android:background="@drawable/image_background_base"/>
</RelativeLayout>
</androidx.cardview.widget.CardView>
Styles:
<resources>
<style name="AppTheme" parent="@style/Theme.AppCompat.Light">">
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
</resources>
Manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.imagegridactivity">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".PickImageActivity"></activity>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Gradle:
apply plugin: 'com.android.application'
android {
compileSdkVersion 29
buildToolsVersion "29.0.2"
defaultConfig {
applicationId "com.example.imagegridactivity"
minSdkVersion 16
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
implementation 'androidx.recyclerview:recyclerview:1.1.0'
implementation 'androidx.recyclerview:recyclerview-selection:1.1.0-rc01'
implementation "androidx.cardview:cardview:1.0.0"
implementation 'com.github.bumptech.glide:glide:4.11.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
implementation 'com.google.android.material:material:1.1.0'
}
Main Activity:
public class MainActivity extends AppCompatActivity {
private Context mContext;
//RelativeLayout mRelativeLayout;
private RecyclerView mRecyclerView;
private AnimalsAdapter mAdapter;
private RecyclerView.LayoutManager mLayoutManager;
private ArrayList<animal_item> arrayList;
private Uri imageUri;
private int imagePosition;
@Override
protected void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_ACTION_BAR);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mContext = getApplicationContext();
//mRelativeLayout = findViewById(R.id.rl);
mRecyclerView = findViewById(R.id.recycler_view);
final int[] imageArray = new int[9];
for (int i = 0; i < imageArray.length; i++) {
imageArray[i] = R.drawable.image_background_base;
}
arrayList = new ArrayList<>();
for (int i = 0; i < imageArray.length; i++) {
int image = imageArray[i];
arrayList.add(new animal_item(image));
}
mLayoutManager = new GridLayoutManager(mContext, 3);
mRecyclerView.setLayoutManager(mLayoutManager);
mAdapter = new AnimalsAdapter(mContext, arrayList);
mRecyclerView.setAdapter(mAdapter);
mAdapter.setOnItemClickListener(new AnimalsAdapter.OnItemClickListener() {
@Override
public void onItemClick(int position) {
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(intent, 1);
imagePosition = position;
}
});
ItemTouchHelper helper = new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT, 0) {
final ArrayList aL = new ArrayList<>();
@Override
public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder dragged, @NonNull RecyclerView.ViewHolder target) {
int position_dragged = dragged.getAdapterPosition();
int position_target = target.getAdapterPosition();
Collections.swap(arrayList, position_dragged, position_target);
mAdapter.notifyItemMoved(position_dragged, position_target);
//Collections.copy(mQuestion11List, aL);
return false;
}
@Override
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
}
});
helper.attachToRecyclerView(mRecyclerView);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
imageUri = data.getData();
//mAdapter.getDataSet().get(imagePosition).setImageResource();
mLayoutManager.findViewByPosition(imagePosition).findViewById(R.id.tv);
Glide.with(MainActivity.this).load(imageUri).centerCrop().into((ImageView) mLayoutManager.findViewByPosition(imagePosition).findViewById(R.id.tv));
}
}
Main Activity XML:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/rl"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#c2dbfd"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
</androidx.recyclerview.widget.RecyclerView>
</LinearLayout>
Caused by: java.lang.IllegalArgumentException: The style on this component requires your app theme to be Theme.AppCompat (or a descendant).
There is an issue with the context
used to instantiate the Adapter
. You need to pass in the Activity
, not an ApplicationContext
.
The application context doesn't have your app theme.
In your Activity change
mContext = getApplicationContext();
mAdapter = new AnimalsAdapter(mContext, arrayList);
to
mAdapter = new AnimalsAdapter(this, arrayList);
Also pay attention since with the Material Components 1.1.0 your app theme should inherit from a Material Components theme.