Outline.java revision 13ed2178c4df86b5b417497ac0b130e76c9804f2
1/* 2 * Copyright (C) 2014 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 17package android.graphics; 18 19import android.annotation.NonNull; 20import android.graphics.drawable.Drawable; 21import android.view.View; 22 23/** 24 * Defines a simple shape, used for bounding graphical regions. 25 * <p> 26 * Can be used with a View, or computed by a Drawable, to drive the shape of shadows cast by a 27 * View, or to clip the contents of the View. 28 * 29 * @see View#setOutline(Outline) 30 * @see Drawable#getOutline(Outline) 31 */ 32public final class Outline { 33 /** @hide */ 34 public Path mPath; 35 36 /** @hide */ 37 public Rect mRect; 38 /** @hide */ 39 public float mRadius; 40 /** @hide */ 41 public float mAlpha; 42 43 /** 44 * Constructs an empty Outline. Call one of the setter methods to make 45 * the outline valid for use with a View. 46 */ 47 public Outline() {} 48 49 /** 50 * Constructs an Outline with a copy of the data in src. 51 */ 52 public Outline(@NonNull Outline src) { 53 set(src); 54 } 55 56 /** 57 * Sets the outline to be empty. 58 * 59 * @see #isEmpty() 60 */ 61 public void setEmpty() { 62 mPath = null; 63 mRect = null; 64 mRadius = 0; 65 } 66 67 /** 68 * Returns whether the Outline is empty. 69 * <p> 70 * Outlines are empty when constructed, or if {@link #setEmpty()} is called, 71 * until a setter method is called 72 * 73 * @see #setEmpty() 74 */ 75 public boolean isEmpty() { 76 return mRect == null && mPath == null; 77 } 78 79 80 /** 81 * Returns whether the outline can be used to clip a View. 82 * 83 * Currently, only outlines that can be represented as a rectangle, circle, or round rect 84 * support clipping. 85 * 86 * @see {@link View#setClipToOutline(boolean)} 87 */ 88 public boolean canClip() { 89 return !isEmpty() && mRect != null; 90 } 91 92 /** 93 * Sets the alpha represented by the Outline. 94 * 95 * Content producing a fully opaque (alpha = 1.0f) outline is assumed by the drawing system 96 * to fully cover content beneath it, meaning content beneath may be optimized away. 97 */ 98 public void setAlpha(float alpha) { 99 mAlpha = alpha; 100 } 101 102 /** 103 * Returns the alpha represented by the Outline. 104 */ 105 public float getAlpha() { 106 return mAlpha; 107 } 108 109 /** 110 * Replace the contents of this Outline with the contents of src. 111 * 112 * @param src Source outline to copy from. 113 */ 114 public void set(@NonNull Outline src) { 115 if (src.mPath != null) { 116 if (mPath == null) { 117 mPath = new Path(); 118 } 119 mPath.set(src.mPath); 120 mRect = null; 121 } 122 if (src.mRect != null) { 123 if (mRect == null) { 124 mRect = new Rect(); 125 } 126 mRect.set(src.mRect); 127 } 128 mRadius = src.mRadius; 129 mAlpha = src.mAlpha; 130 } 131 132 /** 133 * Sets the Outline to the rounded rect defined by the input rect, and corner radius. 134 */ 135 public void setRect(int left, int top, int right, int bottom) { 136 setRoundRect(left, top, right, bottom, 0.0f); 137 } 138 139 /** 140 * Convenience for {@link #setRect(int, int, int, int)} 141 */ 142 public void setRect(@NonNull Rect rect) { 143 setRect(rect.left, rect.top, rect.right, rect.bottom); 144 } 145 146 /** 147 * Sets the Outline to the rounded rect defined by the input rect, and corner radius. 148 * 149 * Passing a zero radius is equivalent to calling {@link #setRect(int, int, int, int)} 150 */ 151 public void setRoundRect(int left, int top, int right, int bottom, float radius) { 152 if (left >= right || top >= bottom) { 153 setEmpty(); 154 return; 155 } 156 157 if (mRect == null) mRect = new Rect(); 158 mRect.set(left, top, right, bottom); 159 mRadius = radius; 160 mPath = null; 161 } 162 163 /** 164 * Convenience for {@link #setRoundRect(int, int, int, int, float)} 165 */ 166 public void setRoundRect(@NonNull Rect rect, float radius) { 167 setRoundRect(rect.left, rect.top, rect.right, rect.bottom, radius); 168 } 169 170 /** 171 * Sets the outline to the oval defined by input rect. 172 */ 173 public void setOval(int left, int top, int right, int bottom) { 174 if (left >= right || top >= bottom) { 175 setEmpty(); 176 return; 177 } 178 179 if ((bottom - top) == (right - left)) { 180 // represent circle as round rect, for efficiency, and to enable clipping 181 setRoundRect(left, top, right, bottom, (bottom - top) / 2.0f); 182 return; 183 } 184 185 if (mPath == null) mPath = new Path(); 186 mPath.reset(); 187 mPath.addOval(left, top, right, bottom, Path.Direction.CW); 188 mRect = null; 189 } 190 191 /** 192 * Convenience for {@link #setOval(int, int, int, int)} 193 */ 194 public void setOval(@NonNull Rect rect) { 195 setOval(rect.left, rect.top, rect.right, rect.bottom); 196 } 197 198 /** 199 * Sets the Constructs an Outline from a {@link android.graphics.Path#isConvex() convex path}. 200 */ 201 public void setConvexPath(@NonNull Path convexPath) { 202 if (convexPath.isEmpty()) { 203 setEmpty(); 204 return; 205 } 206 207 if (!convexPath.isConvex()) { 208 throw new IllegalArgumentException("path must be convex"); 209 } 210 if (mPath == null) mPath = new Path(); 211 212 mPath.set(convexPath); 213 mRect = null; 214 mRadius = -1.0f; 215 } 216} 217