Lesson 183. ConstraintSet. ConstraintLayout software setup

Lesson 183. ConstraintSet. ConstraintLayout software setup


With ConstraintSet you can programmatically create bindings, chains, barriers and customize them.

For a complete list of operations, see the official documentation. I’ll look at some of them.

For examples I will use the following code:

import android.os.Bundle;
import android.support.constraint.ConstraintLayout;
import android.support.constraint.ConstraintSet;
import android.support.transition.TransitionManager;
import android.support.v7.app.AppCompatActivity;

import butterknife.BindDimen;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;

public class MainActivity extends AppCompatActivity {

   @BindView(R.id.container)
   ConstraintLayout constraintLayout;

   @BindDimen(R.dimen.some_margin)
   int someMargin;

   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);
       ButterKnife.bind(this);
   }

   @OnClick(R.id.button)
   void onButtonClick() {
       ConstraintSet set = new ConstraintSet();

       // copy constraints settings from current ConstraintLayout to set
       set.clone(constraintLayout);

       // change constraints settings
       changeConstraints(set);

       // enable animation
       TransitionManager.beginDelayedTransition(constraintLayout);

       // apply constraints settings from set to current ConstraintLayout
       set.applyTo(constraintLayout);
   }

   private void changeConstraints(ConstraintSet set) {

   }

}

The code uses a little bit of the ButterKnife library. If you haven’t heard of it, I recommend reading the review. But overall, it’s pretty clear what she’s doing.

The onButtonClick method will be called when the button is clicked. We create ConstraintSet in it and use the clone method to read the settings of the current ConstraintLayout, which is now displayed on the screen. In the changeConstraints method, we will change the settings, and then use the applyTo method to apply these settings to the current ConstraintLayout.

That is, they considered the settings, changed something, and recorded it back. The changes we make will be immediately displayed on the screen. And TransitionManager will add animation to these changes.

Some_margin variable was created in values.xml


   32dp

ButterKnife puts its value in someMargin variable. Sometimes I will use this value for indentation.

Creating a bind (connect)

Consider the following screen

TextView3 is tied to TextView1.

Let’s programmatically detach TextView3 from TextView1 and bind to TextView2.

private void changeConstraints(ConstraintSet set) {
   set.clear(R.id.textView3, ConstraintSet.LEFT);
   set.clear(R.id.textView3, ConstraintSet.TOP);

   set.connect(R.id.textView3, ConstraintSet.LEFT, R.id.textView2, ConstraintSet.LEFT);
   set.connect(R.id.textView3, ConstraintSet.BOTTOM, R.id.textView2, ConstraintSet.TOP, someMargin);
}

The clear method removes the left and top bindings for TextView3. The connect method first binds the left boundary of TextView3 to the left boundary of TextView2 and then the lower boundary of TextView3 to the upper boundary of TextView2. For vertical binding, we specify the indentation immediately.

run

TextView3 got rid of TextView1 and tied to TextView2.

In principle, the clear method for the left TextView3 bind could be called because we would then create a new left bind and the old bind (to TextView1) would go it alone.

In the connect method, we specified the id View they worked with. You can use the ConstraintSet constant instead of id to create a parent or mother attachment.PARENT_ID.

set.connect(R.id.textView3, ConstraintSet.LEFT, ConstraintSet.PARENT_ID, ConstraintSet.LEFT, 0);
set.connect(R.id.textView3, ConstraintSet.RIGHT, ConstraintSet.PARENT_ID, ConstraintSet.RIGHT, 0);

Width adjustment (constrainWidth)

Consider the following screen

Set the Button2 button to full screen width. To do this, you must create a two-sided horizontal binding to the edges of the parent and set match_constraint width.

The Button2 button on the left is already tied to the parent. Therefore, only the right binding will need to be created.

set.setMargin(R.id.button2, ConstraintSet.START, 0);
set.connect(R.id.button2, ConstraintSet.RIGHT, ConstraintSet.PARENT_ID, ConstraintSet.RIGHT, 0);
set.constrainWidth(R.id.button2, ConstraintSet.MATCH_CONSTRAINT);

The setMargin method Zeroes the indentation on the left, the connect method creates the right binding to the father or mother, and the constrainWidth method sets the width of match_constraint.

run

Similarly, there is a method for height adjustment – constrainHeight.

bias

bias is the same scroll at the top of Properties that allows you to specify which side will be closer to View when double-sided.

We use the same example from Button2. Let’s create the right binding to the father or mother to get a two-sided horizontal binding and set the value bias = 75%.

set.setMargin(R.id.button2, ConstraintSet.START, 0);
set.connect(R.id.button2, ConstraintSet.RIGHT, ConstraintSet.PARENT_ID, ConstraintSet.RIGHT, 0);
set.setHorizontalBias(R.id.button2, 0.7f);

run

The changes on the screen appear small, but previously the button had a fixed indentation from the left edge, and now it is located three-quarters of the width of the screen from the left edge. We changed the absolute indentation to relative.

ConstraintSet contains centerHorizontally and centerVertically methods. They allow you to immediately create two-sided bindings and specify bias values. They are designed to make you write less code. Under the hood, there will be calls to the connect and setHorizontalBias methods.

Chains

Consider the following screen

Programmatically connect Button2 and Button3 in a horizontal chain, stretch them to the full screen, and show them weight 3 and 2, respectively.

   set.setMargin(R.id.button2, ConstraintSet.START, 0);
   set.setMargin(R.id.button3, ConstraintSet.START, 0);
   set.constrainWidth(R.id.button2, ConstraintSet.MATCH_CONSTRAINT);
   set.constrainWidth(R.id.button3, ConstraintSet.MATCH_CONSTRAINT);
   int[] chainViews = {R.id.button2, R.id.button3};
   float[] chainWeights = {3, 2};
   set.createHorizontalChain(ConstraintSet.PARENT_ID, ConstraintSet.LEFT,
           ConstraintSet.PARENT_ID, ConstraintSet.RIGHT,
           chainViews, chainWeights,
           ConstraintSet.CHAIN_SPREAD);

First, we remove the left indents by the setMargin method. Then we adjust the width of match_constraint so that the weight can be applied.

In the chainViews array we specify View, which must be merged into a chain. In the chainWeights array, we specify scales for View from chainViews.

In the createHorizontalChain method, we specify that the leash must be tied to the parent left and right, and the leash type should be spread.

If you do not need to specify the weight, then pass null instead of chainWeights. Well, in this case it is not necessary to put width in match_constraint

run

A little clarification. There is an error in the createHorizontalChain method that causes the chainviews to not be weighted for the first View from the chainViews array. It may be corrected in future versions. In the meantime, you can simply set the weight manually with the setHorizontalWeight method

set.setHorizontalWeight(R.id.button2, 3);

To remove or add View to existing threads, use the removeFromHorizontalChain and addToHorizontalChain methods.

Guides (guideline)

Consider the following screen

Let’s create a vertical guide and tie all three TextViews to it

set.create(R.id.guideline, ConstraintSet.VERTICAL_GUIDELINE);
set.setGuidelinePercent(R.id.guideline, 0.2f);

set.connect(R.id.textView, ConstraintSet.LEFT, R.id.guideline, ConstraintSet.RIGHT, 0);
set.connect(R.id.textView2, ConstraintSet.LEFT, R.id.guideline, ConstraintSet.RIGHT, 0);
set.connect(R.id.textView3, ConstraintSet.LEFT, R.id.guideline, ConstraintSet.RIGHT, 0);

set.setMargin(R.id.textView, ConstraintSet.START, 0);
set.setMargin(R.id.textView2, ConstraintSet.START, 0);
set.setMargin(R.id.textView3, ConstraintSet.START, 0);

With the create method, we create a vertical guide and setGuidelinePercent specifies that it will be indented at 20% of the screen width.

Next, the connect method binds all TextView and the setMargin method.

Guideline variable created in values.xml


   1

run

clone

With the clone method, we can read the settings not only from the current ConstrainLayout but also from the layout file.

Suppose we have two layout files

1) activity_main


This is the basic layout that will be used at startup.

2) activity_main2

We will read this screen from the layout file and apply it programmatically to the current screen.

Activity code:

public class MainActivity extends AppCompatActivity {

   private final ConstraintSet set = new ConstraintSet();
   private final ConstraintSet set2 = new ConstraintSet();
   private ConstraintLayout constraintLayout;
   private ConstraintSet currentSet;

   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);

       constraintLayout = (ConstraintLayout) findViewById(R.id.container);

       // copy constraints settings from current ConstraintLayout to set
       set.clone(constraintLayout);

       // copy constraints settings from activity_main2 to set2
       set2.clone(MainActivity.this, R.layout.activity_main2);

       currentSet = set;

       findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View v) {

               // change current set
               currentSet = (currentSet == set ? set2 : set);

               // enable animation
               TransitionManager.beginDelayedTransition(constraintLayout);

               // apply settings to current ConstraintLayout
               currentSet.applyTo(constraintLayout);
           }
       });

   }
}

In the set variable, we read the settings of the current ConstraintLayout that was created with activity_main. In set2, we read the ConstraintLayout settings from the activity_main2 layout file.

At the push of a button we place current or set2 in the currentSet, and apply these settings to the current ConstraintLayout. That is, the screen will switch between the initial settings and the settings with activity_main2.

run

To use TransitionManager for API <19, use the support version

compile 'com.android.support:transition:25.3.1'




Discuss in the forum [1 reply]

Leave a Comment