1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.constraintlayout.widget; 18 19 import android.annotation.SuppressLint; 20 import android.content.Context; 21 import android.graphics.Canvas; 22 import android.util.AttributeSet; 23 import android.view.View; 24 25 import org.jspecify.annotations.NonNull; 26 27 /** 28 * Utility class representing a Guideline helper object for 29 * {@link ConstraintLayout}. 30 * Helper objects are not displayed on device 31 * (they are marked as {@code View.GONE}) and are only used 32 * for layout purposes. They only work within a 33 * {@link ConstraintLayout}. 34 *<p> 35 * A Guideline can be either horizontal or vertical: 36 * <ul> 37 * <li>Vertical Guidelines have a width of zero and the height of their 38 * {@link ConstraintLayout} parent</li> 39 * <li>Horizontal Guidelines have a height of zero and the width of their 40 * {@link ConstraintLayout} parent</li> 41 * </ul> 42 *<p> 43 * Positioning a Guideline is possible in three different ways: 44 * <ul> 45 * <li>specifying a fixed distance from the left or the top of a layout 46 * ({@code layout_constraintGuide_begin})</li> 47 * <li>specifying a fixed distance from the right or the bottom of a layout 48 * ({@code layout_constraintGuide_end})</li> 49 * <li>specifying a percentage of the width or the height of a layout 50 * ({@code layout_constraintGuide_percent})</li> 51 * </ul> 52 * <p> 53 * Widgets can then be constrained to a Guideline, 54 * allowing multiple widgets to be positioned easily from 55 * one Guideline, or allowing reactive layout behavior by using percent positioning. 56 * <p> 57 * See the list of attributes in 58 * {@link androidx.constraintlayout.widget.ConstraintLayout.LayoutParams} to set a Guideline 59 * in XML, as well as the corresponding {@link ConstraintSet#setGuidelineBegin}, 60 * {@link ConstraintSet#setGuidelineEnd} 61 * and {@link ConstraintSet#setGuidelinePercent} functions in {@link ConstraintSet}. 62 * <p> 63 * Example of a {@code Button} constrained to a vertical {@code Guideline}: 64 * <pre>{@code 65 * <androidx.constraintlayout.widget.ConstraintLayout 66 * xmlns:android="http://schemas.android.com/apk/res/android" 67 * xmlns:app="http://schemas.android.com/apk/res-auto" 68 * xmlns:tools="http://schemas.android.com/tools" 69 * android:layout_width="match_parent" 70 * android:layout_height="match_parent"> 71 * 72 * <androidx.constraintlayout.widget.Guideline 73 * android:layout_width="wrap_content" 74 * android:layout_height="wrap_content" 75 * android:id="@+id/guideline" 76 * app:layout_constraintGuide_begin="100dp" 77 * android:orientation="vertical"/> 78 * <Button 79 * android:text="Button" 80 * android:layout_width="wrap_content" 81 * android:layout_height="wrap_content" 82 * android:id="@+id/button" 83 * app:layout_constraintLeft_toLeftOf="@+id/guideline" 84 * android:layout_marginTop="16dp" 85 * app:layout_constraintTop_toTopOf="parent" /> 86 * </androidx.constraintlayout.widget.ConstraintLayout> 87 * } 88 * </pre> 89 * <p/> 90 */ 91 public class Guideline extends View { 92 private boolean mFilterRedundantCalls = true; Guideline(Context context)93 public Guideline(Context context) { 94 super(context); 95 super.setVisibility(View.GONE); 96 } 97 Guideline(Context context, AttributeSet attrs)98 public Guideline(Context context, AttributeSet attrs) { 99 super(context, attrs); 100 super.setVisibility(View.GONE); 101 } 102 Guideline(Context context, AttributeSet attrs, int defStyleAttr)103 public Guideline(Context context, AttributeSet attrs, int defStyleAttr) { 104 super(context, attrs, defStyleAttr); 105 super.setVisibility(View.GONE); 106 } 107 Guideline(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)108 public Guideline(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 109 super(context, attrs, defStyleAttr); 110 super.setVisibility(View.GONE); 111 } 112 113 /** 114 * 115 */ 116 @Override setVisibility(int visibility)117 public void setVisibility(int visibility) { 118 } 119 120 /** 121 * We are overriding draw and not calling super.draw() here because 122 * Helper objects are not displayed on device. 123 * 124 * 125 */ 126 @SuppressLint("MissingSuperCall") 127 @Override draw(@onNull Canvas canvas)128 public void draw(@NonNull Canvas canvas) { 129 130 } 131 132 /** 133 * 134 */ 135 @Override onMeasure(int widthMeasureSpec, int heightMeasureSpec)136 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 137 setMeasuredDimension(0, 0); 138 } 139 140 /** 141 * Set the guideline's distance from the top or left edge. 142 * 143 * @param margin the distance to the top or left edge 144 */ setGuidelineBegin(int margin)145 public void setGuidelineBegin(int margin) { 146 ConstraintLayout.LayoutParams params = (ConstraintLayout.LayoutParams) getLayoutParams(); 147 if (mFilterRedundantCalls && params.guideBegin == margin) { 148 return; 149 } 150 params.guideBegin = margin; 151 setLayoutParams(params); 152 } 153 154 /** 155 * Set a guideline's distance to end. 156 * 157 * @param margin the margin to the right or bottom side of container 158 */ setGuidelineEnd(int margin)159 public void setGuidelineEnd(int margin) { 160 ConstraintLayout.LayoutParams params = (ConstraintLayout.LayoutParams) getLayoutParams(); 161 if (mFilterRedundantCalls && params.guideEnd == margin) { 162 return; 163 } 164 params.guideEnd = margin; 165 setLayoutParams(params); 166 } 167 168 /** 169 * Set a Guideline's percent. 170 * @param ratio the ratio between the gap on the left and right 0.0 is top/left 0.5 is middle 171 */ setGuidelinePercent(float ratio)172 public void setGuidelinePercent(float ratio) { 173 ConstraintLayout.LayoutParams params = (ConstraintLayout.LayoutParams) getLayoutParams(); 174 if (mFilterRedundantCalls && params.guidePercent == ratio) { 175 return; 176 } 177 params.guidePercent = ratio; 178 setLayoutParams(params); 179 } 180 181 /** 182 * filter redundant calls to setGuidelineBegin, setGuidelineEnd & setGuidelinePercent. 183 * 184 * By default calling setGuidelineStart,setGuideLineEnd and setGuidelinePercent will do nothing 185 * if the value is the same as the current value. This can disable that behaviour and call 186 * setLayoutParams(..) while will call requestLayout 187 * 188 * @param filter default true set false to always generate a setLayoutParams 189 */ setFilterRedundantCalls(boolean filter)190 public void setFilterRedundantCalls(boolean filter) { 191 this.mFilterRedundantCalls = filter; 192 } 193 } 194