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

mqxuamgl  于 2023-02-10  发布在  Android
关注(0)|答案(3)|浏览(165)

我遇到了一个问题,即如何以编程方式向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中时,它就像一个魅力。
如何创建所需的约束,以便布局再次工作?

jvlzgdj9

jvlzgdj91#

我认为您应该在添加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);```
but5z9lq

but5z9lq2#

正在将此How do I add elements dynamically to a view created with XMLhttps://stackoverflow.com/a/40527407/4991437合并
我发现了一个“更简单”的解决方案。这对于添加使用ViewbindingViewModel的多个一致视图效果最好
1.创建 fragment_home.xml
1.将线性布局添加到 fragment_home.xml 的底部
1.创建一个要扩展的 dynamic_view.xml
1.从ViewModel/Array或任何可用的数据源获取元素
1.充气并添加元素
在本例中,我使用recyclerview创建了一个textview(title)[有一些库可以实现这个功能,但是我发现有更多的控件可以实现这个功能]
步骤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>

第三步

<?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);
        }
    });
fnvucqvd

fnvucqvd3#

运动布局解决方案

MotionLayout比较复杂,因为它有多个约束集,需要特殊处理。如果使用针对ConstraintLayout的解决方案,由于某种原因,它会将视图定位在右下角的某个位置。在MotionLayout中添加视图的正确方法是使用updateState而不是applyTo

/* ...up until this point the steps are the same: create constraint set,
set view's id, clone, connect, etc. */

layout.updateState(R.id.start, set)

为了使您的视图在其他定义的约束集中可见(在本例中为end约束集,又名R.id.end),请使用专用的cloneConstraintSet方法并设置视图的大小:

// Clone the constraint set using MotionLayout's `cloneConstraintSet`
val setEnd = layout.cloneConstraintSet(R.id.end)
// Set the view's width and height
setEnd.constrainWidth(view.id, ConstraintLayout.LayoutParams.WRAP_CONTENT)
setEnd.constrainHeight(view.id, ConstraintLayout.LayoutParams.WRAP_CONTENT)
// Update state
layout.updateState(R.id.end, setEnd)

相关问题