12e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet/* 22e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * Copyright (C) 2007 The Android Open Source Project 32e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * 42e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * Licensed under the Apache License, Version 2.0 (the "License"); 52e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * you may not use this file except in compliance with the License. 62e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * You may obtain a copy of the License at 72e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * 82e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * http://www.apache.org/licenses/LICENSE-2.0 92e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * 102e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * Unless required by applicable law or agreed to in writing, software 112e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * distributed under the License is distributed on an "AS IS" BASIS, 122e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 132e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * See the License for the specific language governing permissions and 142e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * limitations under the License. 152e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet */ 162e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet 172e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohetpackage com.android.tests.libwithcustom; 182e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet 192e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet// Need the following import to get access to the app resources, since this 202e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet// class is in a sub-package. 212e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohetimport android.content.Context; 222e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohetimport android.content.res.TypedArray; 232e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohetimport android.graphics.Canvas; 242e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohetimport android.graphics.Paint; 252e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohetimport android.util.AttributeSet; 262e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohetimport android.view.View; 272e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet 282e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet 292e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet/** 302e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * Example of how to write a custom subclass of View. LabelView 312e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * is used to draw simple text views. Note that it does not handle 322e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * styled text or right-to-left writing systems. 332e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * 342e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet */ 352e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohetpublic class LabelView extends View { 362e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet private Paint mTextPaint; 372e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet private String mText; 382e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet private int mAscent; 392e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet 402e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet /** 412e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * Constructor. This version is only needed if you will be instantiating 422e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * the object manually (not from a layout XML file). 432e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * @param context 442e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet */ 452e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet public LabelView(Context context) { 462e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet super(context); 472e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet initLabelView(); 482e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet } 492e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet 502e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet /** 512e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * Construct object, initializing with any attributes we understand from a 522e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * layout file. These attributes are defined in 532e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * SDK/assets/res/any/classes.xml. 542e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * 552e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * @see android.view.View#View(android.content.Context, android.util.AttributeSet) 562e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet */ 572e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet public LabelView(Context context, AttributeSet attrs) { 582e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet super(context, attrs); 592e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet initLabelView(); 602e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet 612e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet 622e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet TypedArray a = context.obtainStyledAttributes(attrs, 632e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet R.styleable.LabelView); 642e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet 652e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet CharSequence s = a.getString(R.styleable.LabelView_text); 662e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet if (s != null) { 672e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet setText(s.toString()); 682e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet } 692e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet 702e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet // Retrieve the color(s) to be used for this view and apply them. 712e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet // Note, if you only care about supporting a single color, that you 722e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet // can instead call a.getColor() and pass that to setTextColor(). 732e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet setTextColor(a.getColor(R.styleable.LabelView_textColor, 0xFF000000)); 742e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet 752e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet int textSize = a.getDimensionPixelOffset(R.styleable.LabelView_textSize, 0); 762e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet if (textSize > 0) { 772e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet setTextSize(textSize); 782e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet } 792e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet 802e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet a.recycle(); 812e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet } 822e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet 832e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet private final void initLabelView() { 842e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet mTextPaint = new Paint(); 852e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet mTextPaint.setAntiAlias(true); 862e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet // Must manually scale the desired text size to match screen density 872e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet mTextPaint.setTextSize(16 * getResources().getDisplayMetrics().density); 882e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet mTextPaint.setColor(0xFF000000); 892e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet setPadding(3, 3, 3, 3); 902e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet } 912e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet 922e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet /** 932e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * Sets the text to display in this label 942e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * @param text The text to display. This will be drawn as one line. 952e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet */ 962e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet public void setText(String text) { 972e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet mText = text; 982e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet requestLayout(); 992e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet invalidate(); 1002e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet } 1012e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet 1022e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet /** 1032e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * Sets the text size for this label 1042e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * @param size Font size 1052e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet */ 1062e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet public void setTextSize(int size) { 1072e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet // This text size has been pre-scaled by the getDimensionPixelOffset method 1082e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet mTextPaint.setTextSize(size); 1092e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet requestLayout(); 1102e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet invalidate(); 1112e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet } 1122e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet 1132e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet /** 1142e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * Sets the text color for this label. 1152e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * @param color ARGB value for the text 1162e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet */ 1172e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet public void setTextColor(int color) { 1182e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet mTextPaint.setColor(color); 1192e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet invalidate(); 1202e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet } 1212e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet 1222e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet /** 1232e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * @see android.view.View#measure(int, int) 1242e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet */ 1252e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet @Override 1262e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 1272e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet setMeasuredDimension(measureWidth(widthMeasureSpec), 1282e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet measureHeight(heightMeasureSpec)); 1292e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet } 1302e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet 1312e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet /** 1322e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * Determines the width of this view 1332e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * @param measureSpec A measureSpec packed into an int 1342e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * @return The width of the view, honoring constraints from measureSpec 1352e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet */ 1362e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet private int measureWidth(int measureSpec) { 1372e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet int result = 0; 1382e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet int specMode = MeasureSpec.getMode(measureSpec); 1392e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet int specSize = MeasureSpec.getSize(measureSpec); 1402e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet 1412e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet if (specMode == MeasureSpec.EXACTLY) { 1422e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet // We were told how big to be 1432e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet result = specSize; 1442e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet } else { 1452e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet // Measure the text 1462e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet result = (int) mTextPaint.measureText(mText) + getPaddingLeft() 1472e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet + getPaddingRight(); 1482e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet if (specMode == MeasureSpec.AT_MOST) { 1492e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet // Respect AT_MOST value if that was what is called for by measureSpec 1502e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet result = Math.min(result, specSize); 1512e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet } 1522e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet } 1532e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet 1542e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet return result; 1552e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet } 1562e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet 1572e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet /** 1582e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * Determines the height of this view 1592e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * @param measureSpec A measureSpec packed into an int 1602e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * @return The height of the view, honoring constraints from measureSpec 1612e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet */ 1622e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet private int measureHeight(int measureSpec) { 1632e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet int result = 0; 1642e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet int specMode = MeasureSpec.getMode(measureSpec); 1652e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet int specSize = MeasureSpec.getSize(measureSpec); 1662e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet 1672e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet mAscent = (int) mTextPaint.ascent(); 1682e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet if (specMode == MeasureSpec.EXACTLY) { 1692e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet // We were told how big to be 1702e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet result = specSize; 1712e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet } else { 1722e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet // Measure the text (beware: ascent is a negative number) 1732e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet result = (int) (-mAscent + mTextPaint.descent()) + getPaddingTop() 1742e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet + getPaddingBottom(); 1752e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet if (specMode == MeasureSpec.AT_MOST) { 1762e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet // Respect AT_MOST value if that was what is called for by measureSpec 1772e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet result = Math.min(result, specSize); 1782e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet } 1792e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet } 1802e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet return result; 1812e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet } 1822e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet 1832e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet /** 1842e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * Render the text 1852e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * 1862e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * @see android.view.View#onDraw(android.graphics.Canvas) 1872e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet */ 1882e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet @Override 1892e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet protected void onDraw(Canvas canvas) { 1902e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet super.onDraw(canvas); 1912e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet canvas.drawText(mText, getPaddingLeft(), getPaddingTop() - mAscent, mTextPaint); 1922e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet } 1932e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet} 194