android2018. 7. 13. 18:00


fully custom view를 생성하기 위해 아래의 것들을 수행한다.

custom attributes를 정의하고 사용.
-create attrs.xml, dimes-valuebars.xml
-load them from source code while initializing.
Measuring the View
-override onMeasure method
Drawing to the Canvas
Drawing shapes
-override onDraw method
Drawing text

invalidate() View에 변경 사항이 있을 때, 다시 그리도록 호출
requestLayout() View에 remeasure 가 필요한 상황에서 호출되며 전체 레이아웃에 영향을 준다.

The custom attributes will need to be read in and assigned in the init method. 
AttributeSet은 obtainStyledAttributes() 함수를 통해 가져다 access한다.
TypedArray를 통해 resource에 정의되어 역참조된 스타일과 값들을 쉽게 사용가능. (color나 size 등 xml에 정의된 녀석들을 코드상에서 쉽게 사용 가능)
Initialize는 되도록 onDraw 호출되기전에 하는 것이 좋다. 당연히 onDraw할 때 연산이 있으면 성능상 좋을리 없음.
Canvas, Paint는 우선 그림을 그리기 위한 툴킷과 자료형으로 이해하고 넘어가자.

사용자 정의된 attribute를 정의하고 로드 하는 방법을 잘 보도록 하자.

-measure 및 drawing은 직접 그려보지 않고는 이해하기 쉽지 않아 보이므로 필요한 경우 연습을 해보도록 하자.

res/values/attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="ValueBar">
        <attr name="barHeight" format="dimension"/>
        <attr name="circleRadius" format="dimension"/>
        <attr name="spaceAfterBar" format="dimension"/>
        <attr name="circleTextSize" format="dimension"/>
        <attr name="maxValueTextSize" format="dimension"/>
        <attr name="labelTextSize" format="dimension"/>
        <attr name="labelTextColor" format="color" />
        <attr name="maxValueTextColor" format="color"/>
        <attr name="circleTextColor" format="color"/>
        <attr name="baseColor" format="color"/>
        <attr name="fillColor" format="color"/>
        <attr name="labelText" format="string"/>
    </declare-styleable>
</resources>

res/values/dimens-valueBar.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <dimen name="value_bar_height">60dp</dimen>
    <dimen name="value_bar_padding_top">16dp</dimen>
    <dimen name="value_bar_barHeight">10dp</dimen>
    <dimen name="value_bar_circleRadius">12dp</dimen>
    <dimen name="value_bar_circleTextSize">14dp</dimen>
    <dimen name="value_bar_labelTextSize">18dp</dimen>
    <dimen name="value_bar_maxValueTextSize">24dp</dimen>
    <dimen name="value_bar_padding_horizontal">12dp</dimen>
    <dimen name="value_bar_spaceAfterBar">14dp</dimen>
</resources>

 

import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Typeface; import android.support.annotation.Nullable; import android.util.AttributeSet; import android.view.View; import com.test.simpletest.R; public class ValueBar extends View { private int barHeight; private int circleRadius; private int spaceAfterBar; private int circleTextSize; private int maxValueTextSize; private int labelTextSize; private int labelTextColor; private int currentValueTextColor; private int circleTextColor; private int baseColor; private int fillColor; private String labelText; private int maxValue=100;//default private int currentValue=50; private Paint labelPaint; private Paint maxValuePaint; private Paint barBasePaint; private Paint circlePaint; private Paint barFillPaint; private Paint currentValuePaint; private float valueToDraw; public void setMaxValue(int maxValue){ this.maxValue = maxValue; invalidate(); requestLayout(); } public void setValue( int newValue ){ if (newValue < 0){ currentValue=0; } else if ( newValue > maxValue ){ currentValue=maxValue; } else { currentValue= newValue; } invalidate(); } public ValueBar(Context context, @Nullable AttributeSet attrs) { super(context, attrs); init(context, attrs); } private void init(Context context, AttributeSet attrs) { TypedArray ta = context.getTheme().obtainStyledAttributes(attrs, R.styleable.ValueBar,0 ,0); barHeight = ta.getDimensionPixelSize(R.styleable.ValueBar_barHeight,0); circleRadius = ta.getDimensionPixelSize(R.styleable.ValueBar_circleRadius,0); spaceAfterBar = ta.getDimensionPixelSize(R.styleable.ValueBar_spaceAfterBar,0); circleTextSize = ta.getDimensionPixelSize(R.styleable.ValueBar_circleTextSize, 0); maxValueTextSize = ta.getDimensionPixelSize(R.styleable.ValueBar_maxValueTextSize, 0); labelTextSize = ta.getDimensionPixelSize(R.styleable.ValueBar_labelTextSize, 0); labelTextColor = ta.getColor(R.styleable.ValueBar_labelTextColor, Color.BLACK); currentValueTextColor = ta.getColor(R.styleable.ValueBar_maxValueTextColor, Color.BLACK); circleTextColor = ta.getColor(R.styleable.ValueBar_circleTextColor, Color.BLACK); baseColor = ta.getColor(R.styleable.ValueBar_baseColor, Color.BLACK); fillColor = ta.getColor(R.styleable.ValueBar_fillColor, Color.BLACK); labelText = ta.getString(R.styleable.ValueBar_labelText); ta.recycle(); labelPaint = new Paint(Paint.ANTI_ALIAS_FLAG); labelPaint.setTextSize(labelTextSize); labelPaint.setColor(labelTextColor); labelPaint.setTextAlign(Paint.Align.LEFT); labelPaint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD)); maxValuePaint = new Paint(Paint.ANTI_ALIAS_FLAG); maxValuePaint.setTextSize(maxValueTextSize); maxValuePaint.setColor(currentValueTextColor); maxValuePaint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD)); maxValuePaint.setTextAlign(Paint.Align.RIGHT); barBasePaint = new Paint(Paint.ANTI_ALIAS_FLAG); barBasePaint.setColor(baseColor); barFillPaint = new Paint(Paint.ANTI_ALIAS_FLAG); barFillPaint.setColor(fillColor); circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG); circlePaint.setColor(fillColor); currentValuePaint = new Paint(Paint.ANTI_ALIAS_FLAG); currentValuePaint.setTextSize(circleTextSize); currentValuePaint.setColor(circleTextColor); currentValuePaint.setTextAlign(Paint.Align.CENTER); } @Override protected void onDraw(Canvas canvas) { drawLabel(canvas); drawBar(canvas); drawMaxValue(canvas); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //super.onMeasure(widthMeasureSpec, heightMeasureSpec); setMeasuredDimension(measureWidth(widthMeasureSpec),measureHeight(heightMeasureSpec)); } private int measureHeight(int measureSpec){ int size = getPaddingTop() + getPaddingBottom(); size += labelPaint.getFontSpacing(); float maxValueTextSpacing = maxValuePaint.getFontSpacing(); size += Math.max(maxValueTextSpacing, Math.max(barHeight, circleRadius * 2)); return resolveSizeAndState(size, measureSpec,0); } private int measureWidth(int measureSpec){ int size = getPaddingLeft() + getPaddingRight(); Rect bounds = new Rect(); labelPaint.getTextBounds(labelText, 0, labelText.length(), bounds); size += bounds.width(); return resolveSizeAndState(size, measureSpec,0); } private void drawLabel(Canvas canvas){ float x = getPaddingLeft(); Rect bounds= new Rect(); labelPaint.getTextBounds(labelText, 0, labelText.length(), bounds); float y = getPaddingTop() + bounds.height(); canvas.drawText(labelText, x, y, labelPaint); } private void drawBar(Canvas canvas){ String maxValueString = String.valueOf(maxValue); Rect maxValueRect =new Rect(); maxValuePaint.getTextBounds(maxValueString, 0 , maxValueString.length(), maxValueRect); float barLength = getWidth() - getPaddingRight() - getPaddingLeft() - circleRadius - maxValueRect.width() - spaceAfterBar; float barCenter = getBarCenter(); float halfBarheight = barHeight/2; float top = barCenter - halfBarheight; float bottom =barCenter + halfBarheight; float left = getPaddingLeft(); float right = getPaddingLeft() + barLength; RectF rect = new RectF(left,top,right,bottom); canvas.drawRoundRect(rect, halfBarheight, halfBarheight, barBasePaint); float percentFilled = (float) currentValue / (float) maxValue; float fillLength = barLength * percentFilled; float fillPosition = left + fillLength; RectF fillRect = new RectF(left,top, fillPosition, bottom); canvas.drawRoundRect(fillRect, halfBarheight,halfBarheight,barFillPaint); canvas.drawCircle(fillPosition, barCenter, circleRadius, circlePaint); Rect bounds = new Rect(); String valueString = String.valueOf(Math.round(currentValue)); currentValuePaint.getTextBounds(valueString, 0, valueString.length(), bounds); float y = barCenter + (bounds.height() / 2); canvas.drawText(valueString, fillPosition, y, currentValuePaint); } private float getBarCenter(){ float barCenter = (getHeight() - getPaddingTop() - getPaddingBottom())/ 2; barCenter += getPaddingTop() + .1f * getHeight();//move it down a bit return barCenter; } private void drawMaxValue(Canvas canvas){ String maxValue = String.valueOf(this.maxValue); Rect maxValueRect = new Rect(); maxValuePaint.getTextBounds(maxValue,0 ,maxValue.length(), maxValueRect); float xPos = getWidth() - getPaddingRight(); float yPos = getBarCenter() + maxValueRect.height()/2; canvas.drawText(maxValue, xPos, yPos, maxValuePaint); } }




출처 : https://www.intertech.com/Blog/android-custom-view-tutorial-part-2-custom-attributes-drawing-and-measuring/


'android' 카테고리의 다른 글

tutorialspoint  (0) 2018.07.16
custom view tutorial 따라하기 3  (0) 2018.07.16
custom view tutorial 따라하기 1  (0) 2018.07.12
Simple voice search test2  (0) 2018.07.11
Simple voice search test  (0) 2018.07.11
Posted by easy16