如何以编程方式向 ConstraintLayout 添加视图和约束?

How to programmatically add views and constraints to a ConstraintLayout?

我在以编程方式向 ConstraintLayout 添加视图并设置布局工作所需的所有约束时遇到问题。

我目前的方法不起作用:

ConstraintLayout layout = (ConstraintLayout) findViewById(R.id.mainConstraint);
ConstraintSet set = new ConstraintSet();
set.clone(layout);

ImageView view = new ImageView(this);
layout.addView(view,0);
set.connect(view.getId(), ConstraintSet.TOP, layout.getId(), ConstraintSet.TOP, 60);
set.applyTo(layout);

ImageView 甚至没有出现在布局上。当添加到 RelativeLayout 时,它就像一个魅力。

我可以做些什么来创建我需要的约束,以便我的布局再次起作用?

我认为您应该在添加 ImageView 后克隆布局。

ConstraintLayout layout = (ConstraintLayout)findViewById(R.id.mainConstraint);
ConstraintSet set = new ConstraintSet();

ImageView view = new ImageView(this);
view.setId(View.generateViewId());  // cannot set id after add
layout.addView(view,0);
set.clone(layout);
set.connect(view.getId(), ConstraintSet.TOP, layout.getId(), ConstraintSet.TOP, 60);
set.applyTo(layout);```

合并这个How do I add elements dynamically to a view created with XML with https://whosebug.com/a/40527407/4991437

我发现了一个 'easier' 解决方案。这最适合添加使用 ViewbindingViewModel

的多个一致视图
  1. 创建 fragment_home.xml
  2. fragment_home.xml
  3. 的底部添加一个LinearLayout
  4. 创建一个dynamic_view.xml,您将对其充气
  5. 从 ViewModel/Array 或任何可用数据源获取元素
  6. 膨胀并添加元素

在这种情况下,我正在创建一个带有回收视图的文本视图(标题)[有用于此的库,但是,我发现这样做有更多控制权]

步骤 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>

第 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>

步骤 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);
        }
    });