How to programmatically add views and constraints to a ConstraintLayout?
I think you should clone the layout after adding your ImageView.
ConstraintLayout parentLayout = (ConstraintLayout)findViewById(R.id.mainConstraint); ConstraintSet set = new ConstraintSet(); ImageView childView = new ImageView(this); // set view id, else getId() returns -1 childView.setId(View.generateViewId()); parentLayout.addView(childView, 0); set.clone(parentLayout); // connect start and end point of views, in this case top of child to top of parent. set.connect(childView.getId(), ConstraintSet.TOP, parentLayout.getId(), ConstraintSet.TOP, 60); // ... similarly add other constraints set.applyTo(parentLayout);
Merging this How do I add elements dynamically to a view created with XML with https://stackoverflow.com/a/40527407/4991437
I have discovered an 'easier' solution. This works best for adding multiple consistent views that uses Viewbinding and ViewModel
- Create the fragment_home.xml
- Add a LinearLayout to the bottom of fragment_home.xml
- Create an dynamic_view.xml that you will inflate
- Get elements from ViewModel/Array or whatever source of data available
- Inflate and add elements
In this case I am creating a textview(title) with a recyclerview[there are libs for this, however, I found more control doing this]
Step 1,2
<?xml version="1.0" encoding="utf-8"?><androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".ui.hometab.HomeFragment"> <androidx.constraintlayout.widget.ConstraintLayout android:id="@+id/constraint_parent" android:layout_width="match_parent" android:layout_height="match_parent"> <!-- otherviews here --> <LinearLayout android:id="@+id/dynamic_linear_layout" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginTop="@dimen/margin_large" android:orientation="vertical" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/curated_recycler" /> </androidx.constraintlayout.widget.ConstraintLayout></androidx.core.widget.NestedScrollView>
Step 3
<?xml version="1.0" encoding="utf-8"?><androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/dynamic_constraint" xmlns:app="http://schemas.android.com/apk/res-auto"> <androidx.constraintlayout.widget.Guideline android:id="@+id/guideline" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" app:layout_constraintGuide_begin="@dimen/margin_large" app:layout_constraintStart_toStartOf="parent" /> <View android:id="@+id/title_view" android:layout_width="0dp" android:layout_height="40dp" android:layout_gravity="center" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/shop_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/diary" android:textAppearance="@style/TextAppearance.AppCompat.Medium" android:textColor="@android:color/black" android:textStyle="bold" app:layout_constraintBottom_toBottomOf="@+id/title_view" app:layout_constraintStart_toStartOf="@id/guideline" app:layout_constraintTop_toTopOf="@+id/title_view" /> <androidx.recyclerview.widget.RecyclerView android:id="@+id/shop_recycler" android:layout_width="0dp" android:layout_height="wrap_content" android:clipToPadding="false" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="@id/guideline" app:layout_constraintTop_toBottomOf="@+id/title_view" /></androidx.constraintlayout.widget.ConstraintLayout>
Step 4,5
binding = FragmentHomeBinding.inflate(getLayoutInflater()); ShopViewModel shopViewModel = new ViewModelProvider(this).get(ShopViewModel.class); shopViewModel.getAllShops(false).observe(getViewLifecycleOwner(), shopEntities -> { List<ConstraintLayout> shopConstraints = new ArrayList<>(); for (ShopEntity shopEntity : shopEntities) { // get an instance of the dynamic_view.xml DynamicViewBinding dynamicViewBinding = DynamicViewBinding.inflate(getLayoutInflater()); // add text view content dynamicViewBinding.shopName.setText(shopEntity.getName()); // initialize the recycler layout adapter dynamicViewBinding.shopRecycler.setLayoutManager(new ProductCardLayoutManager(getContext(), 1, GridLayoutManager.HORIZONTAL, false, 80)); // get all products and add them to recycler view productViewModel.getAllProductsByShop(shopEntity.getShopId(), 10).observe(getViewLifecycleOwner(), productEntities -> dynamicViewBinding.shopRecycler.setAdapter(new ProductAdapter(getActivity(), productEntities))); // attach dynamic view to list of dynamic constraint layouts shopConstraints.add(dynamicViewBinding.getRoot()); } // remove all previous views from the linear layout binding.dynamicLinearLayout.removeAllViews(); // add the new views for (ConstraintLayout shopConstraint : shopConstraints) { binding.dynamicLinearLayout.addView(shopConstraint); } });