summaryrefslogtreecommitdiff
path: root/constraintlayout/src/main/java/android/support/constraint/Barrier.java
blob: e3e28b1be61b56d477b184f2684204d447e009a2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.support.constraint;

import android.content.Context;
import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;

/**
 * <b>Added in 1.1</b>
 * <p>
 * A Barrier references multiple widgets as input, and creates a virtual guideline based on the most
 * extreme widget on the specified side. For example, a left barrier will align to the left of all the referenced views.
 * </p>
 * <p>
 * <h2>Example</h2>
 *     <p><div align="center" >
 *       <img width="325px" src="resources/images/barrier-buttons.png">
 *     </div>
 *     Let's have two buttons, @id/button1 and @id/button2. The constraint_referenced_ids field will reference
 *     them by simply having them as comma-separated list:
 *     <pre>
 *     {@code
 *         <android.support.constraint.Barrier
 *              android:id="@+id/barrier"
 *              android:layout_width="wrap_content"
 *              android:layout_height="wrap_content"
 *              app:barrierDirection="start"
 *              app:constraint_referenced_ids="button1,button2" />
 *     }
 *     </pre>
 *     <p>
 *         With the barrier direction set to start, we will have the following result:
 *     <p><div align="center" >
 *       <img width="325px" src="resources/images/barrier-start.png">
 *     </div>
 *     <p>
 *         Reversely, with the direction set to end, we will have:
 *     <p><div align="center" >
 *       <img width="325px" src="resources/images/barrier-end.png">
 *     </div>
 *     <p>
 *         If the widgets dimensions change, the barrier will automatically move according to its direction to get
 *         the most extreme widget:
 *     <p><div align="center" >
 *       <img width="325px" src="resources/images/barrier-adapt.png">
 *     </div>
 *
 *     <p>
 *         Other widgets can then be constrained to the barrier itself, instead of the individual widget. This allows a layout
 *         to automatically adapt on widget dimension changes (e.g. different languages will end up with different length for similar worlds).
 *     </p>
 * <h2>GONE widgets handling</h2>
 * <p>If the barrier references GONE widgets, the default behavior is to create a barrier on the resolved position of the GONE widget.
 * If you do not want to have the barrier take GONE widgets into account, you can change this by setting the attribute <i>barrierAllowsGoneWidgets</i>
 * to false (default being true).</p>
 *     </p>
 * </p>
 *
 */
public class Barrier extends ConstraintHelper {

    /**
     * Left direction constant
     */
    public static final int LEFT = android.support.constraint.solver.widgets.Barrier.LEFT;

    /**
     * Top direction constant
     */
    public static final int TOP = android.support.constraint.solver.widgets.Barrier.TOP;

    /**
     * Right direction constant
     */
    public static final int RIGHT = android.support.constraint.solver.widgets.Barrier.RIGHT;

    /**
     * Bottom direction constant
     */
    public static final int BOTTOM = android.support.constraint.solver.widgets.Barrier.BOTTOM;

    /**
     * Start direction constant
     */
    public static final int START = BOTTOM + 2;

    /**
     * End Barrier constant
     */
    public static final int END = START + 1;

    private int mIndicatedType = LEFT;
    private int mResolvedType = LEFT;
    private android.support.constraint.solver.widgets.Barrier mBarrier;

    public Barrier(Context context) {
        super(context);
        super.setVisibility(View.GONE);
    }

    public Barrier(Context context, AttributeSet attrs) {
        super(context, attrs);
        super.setVisibility(View.GONE);
    }

    public Barrier(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        super.setVisibility(View.GONE);
    }

    /**
     * Get the barrier type ({@code Barrier.LEFT}, {@code Barrier.TOP},
     * {@code Barrier.RIGHT}, {@code Barrier.BOTTOM}, {@code Barrier.END},
     * {@code Barrier.START})
     */
    public int getType() {
        return mIndicatedType;
    }

    /**
     * Set the barrier type ({@code Barrier.LEFT}, {@code Barrier.TOP},
     * {@code Barrier.RIGHT}, {@code Barrier.BOTTOM}, {@code Barrier.END},
     * {@code Barrier.START})
     */
    public void setType(int type) {
        mIndicatedType = type;
        mResolvedType = type;
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
            // Pre JB MR1, left/right should take precedence, unless they are
            // not defined and somehow a corresponding start/end constraint exists
            if (mIndicatedType == START) {
                mResolvedType = LEFT;
            } else if (mIndicatedType == END) {
                mResolvedType = RIGHT;
            }
        } else {
            // Post JB MR1, if start/end are defined, they take precedence over left/right
            Configuration config = getResources().getConfiguration();
            boolean isRtl = (View.LAYOUT_DIRECTION_RTL == config.getLayoutDirection());
            if (isRtl) {
                if (mIndicatedType == START) {
                    mResolvedType = RIGHT;
                } else if (mIndicatedType == END) {
                    mResolvedType = LEFT;
                }
            } else {
                if (mIndicatedType == START) {
                    mResolvedType = LEFT;
                } else if (mIndicatedType == END) {
                    mResolvedType = RIGHT;
                }
            }
        }
        mBarrier.setBarrierType(mResolvedType);
    }

    /**
     * @hide
     * @param attrs
     */
    @Override
    protected void init(AttributeSet attrs) {
        super.init(attrs);
        mBarrier = new android.support.constraint.solver.widgets.Barrier();
        if (attrs != null) {
            TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.ConstraintLayout_Layout);
            final int N = a.getIndexCount();
            for (int i = 0; i < N; i++) {
                int attr = a.getIndex(i);
                if (attr == R.styleable.ConstraintLayout_Layout_barrierDirection) {
                    setType(a.getInt(attr, LEFT));
                } else if (attr == R.styleable.ConstraintLayout_Layout_barrierAllowsGoneWidgets) {
                    mBarrier.setAllowsGoneWidget(a.getBoolean(attr, true));
                }
            }
        }
        mHelperWidget = mBarrier;
        validateParams();
    }

}