• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 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 android.graphics.drawable.shapes;
18 
19 import android.graphics.Canvas;
20 import android.graphics.Outline;
21 import android.graphics.Paint;
22 import android.graphics.Path;
23 import android.graphics.RectF;
24 
25 /**
26  * Creates a rounded-corner rectangle. Optionally, an inset (rounded) rectangle
27  * can be included (to make a sort of "O" shape).
28  * The rounded rectangle can be drawn to a Canvas with its own draw() method,
29  * but more graphical control is available if you instead pass
30  * the RoundRectShape to a {@link android.graphics.drawable.ShapeDrawable}.
31  */
32 public class RoundRectShape extends RectShape {
33     private float[] mOuterRadii;
34     private RectF   mInset;
35     private float[] mInnerRadii;
36 
37     private RectF mInnerRect;
38     private Path  mPath;    // this is what we actually draw
39 
40     /**
41      * RoundRectShape constructor.
42      * Specifies an outer (round)rect and an optional inner (round)rect.
43      *
44      * @param outerRadii An array of 8 radius values, for the outer roundrect.
45      *                   The first two floats are for the
46      *                   top-left corner (remaining pairs correspond clockwise).
47      *                   For no rounded corners on the outer rectangle,
48      *                   pass null.
49      * @param inset      A RectF that specifies the distance from the inner
50      *                   rect to each side of the outer rect.
51      *                   For no inner, pass null.
52      * @param innerRadii An array of 8 radius values, for the inner roundrect.
53      *                   The first two floats are for the
54      *                   top-left corner (remaining pairs correspond clockwise).
55      *                   For no rounded corners on the inner rectangle,
56      *                   pass null.
57      *                   If inset parameter is null, this parameter is ignored.
58      */
RoundRectShape(float[] outerRadii, RectF inset, float[] innerRadii)59     public RoundRectShape(float[] outerRadii, RectF inset,
60                           float[] innerRadii) {
61         if (outerRadii != null && outerRadii.length < 8) {
62             throw new ArrayIndexOutOfBoundsException("outer radii must have >= 8 values");
63         }
64         if (innerRadii != null && innerRadii.length < 8) {
65             throw new ArrayIndexOutOfBoundsException("inner radii must have >= 8 values");
66         }
67         mOuterRadii = outerRadii;
68         mInset = inset;
69         mInnerRadii = innerRadii;
70 
71         if (inset != null) {
72             mInnerRect = new RectF();
73         }
74         mPath = new Path();
75     }
76 
77     @Override
draw(Canvas canvas, Paint paint)78     public void draw(Canvas canvas, Paint paint) {
79         canvas.drawPath(mPath, paint);
80     }
81 
82     @Override
getOutline(Outline outline)83     public void getOutline(Outline outline) {
84         if (mInnerRect != null) return; // have a hole, can't produce valid outline
85 
86         float radius = 0;
87         if (mOuterRadii != null) {
88             radius = mOuterRadii[0];
89             for (int i = 1; i < 8; i++) {
90                 if (mOuterRadii[i] != radius) {
91                     // can't call simple constructors, use path
92                     outline.setConvexPath(mPath);
93                     return;
94                 }
95             }
96         }
97 
98         final RectF rect = rect();
99         outline.setRoundRect((int) Math.ceil(rect.left), (int) Math.ceil(rect.top),
100                 (int) Math.floor(rect.right), (int) Math.floor(rect.bottom),
101                 radius);
102     }
103 
104     @Override
onResize(float w, float h)105     protected void onResize(float w, float h) {
106         super.onResize(w, h);
107 
108         RectF r = rect();
109         mPath.reset();
110 
111         if (mOuterRadii != null) {
112             mPath.addRoundRect(r, mOuterRadii, Path.Direction.CW);
113         } else {
114             mPath.addRect(r, Path.Direction.CW);
115         }
116         if (mInnerRect != null) {
117             mInnerRect.set(r.left + mInset.left, r.top + mInset.top,
118                            r.right - mInset.right, r.bottom - mInset.bottom);
119             if (mInnerRect.width() < w && mInnerRect.height() < h) {
120                 if (mInnerRadii != null) {
121                     mPath.addRoundRect(mInnerRect, mInnerRadii, Path.Direction.CCW);
122                 } else {
123                     mPath.addRect(mInnerRect, Path.Direction.CCW);
124                 }
125             }
126         }
127     }
128 
129     @Override
clone()130     public RoundRectShape clone() throws CloneNotSupportedException {
131         RoundRectShape shape = (RoundRectShape) super.clone();
132         shape.mOuterRadii = mOuterRadii != null ? mOuterRadii.clone() : null;
133         shape.mInnerRadii = mInnerRadii != null ? mInnerRadii.clone() : null;
134         shape.mInset = new RectF(mInset);
135         shape.mInnerRect = new RectF(mInnerRect);
136         shape.mPath = new Path(mPath);
137         return shape;
138     }
139 }
140