RoundRectShape.java revision 31ba192dd201df2cad96a8c503f730130ab0d80f
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 17package android.graphics.drawable.shapes; 18 19import android.graphics.Canvas; 20import android.graphics.Outline; 21import android.graphics.Paint; 22import android.graphics.Path; 23import 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 */ 32public 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 */ 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 78 public void draw(Canvas canvas, Paint paint) { 79 canvas.drawPath(mPath, paint); 80 } 81 82 @Override 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 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 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