android-自定义View

Posted 武略

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了android-自定义View相关的知识,希望对你有一定的参考价值。

1、自定义View的属性

2、在View的构造方法中获得我们自定义的属性

[ 3、重写onMesure ]

4、重写onDraw

我把3用[]标出了,所以说3不一定是必须的,当然了大部分情况下还是需要重写的。

1、自定义View的属性,首先在res/values/  下建立一个attrs.xml , 在里面定义我们的属性和声明我们的整个样式。

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <declare-styleable name="HeartProgressBar">
        <attr name="heartColor" format="color" />
    </declare-styleable>

</resources>

 

format是值该属性的取值类型:

一共有:string,color,demension,integer,enum,reference,float,boolean,fraction,flag;不清楚的可以google一把。

然后在布局中声明我们的自定义View

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#fff1da84"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context=".MainActivity">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="start"
        android:layout_centerHorizontal="true"
        android:onClick="onClick"/>

   
 <com.hornet.heartprogressbar.HeartProgressBar
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:id="@+id/progressBar"/>

</RelativeLayout>

2、在View的构造方法中,获得我们的自定义的样式

package com.hornet.heartprogressbar;

import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DiscretePathEffect;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.Display;
import android.view.View;
import android.view.WindowManager;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.AnticipateInterpolator;
import android.view.animation.AnticipateOvershootInterpolator;
import android.view.animation.BounceInterpolator;
import android.view.animation.CycleInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.LinearInterpolator;
import android.view.animation.OvershootInterpolator;
import android.widget.ProgressBar;

/**
 * Created by Ahmed on 7/19/14.
 */
public class HeartProgressBar extends View {

// #MARK - Constants

    // view property
    private int width;
    private int height;
    private Context context;
    private int heartColor;

    private boolean isStopped;
    private ValueAnimator animatorLeftHeart;
    private ValueAnimator animatorRightHeart;
    private final static String POSITION_X = "positionX";
    private final static String POSITION_Y = "positionY";

    private float leftHeartX;
    private float leftHeartY;
    private float rightHeartX;
    private float rightHeartY;

// #MARK - Constructors

    public HeartProgressBar(Context context) {
        super(context);
        init(context, Color.parseColor("#FF4351"));
    }

    public HeartProgressBar(Context context, AttributeSet attrs) {
        super(context, attrs);
        TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.HeartProgressBar, 0, 0);
        try {
            int heartColor = typedArray.getColor(R.styleable.HeartProgressBar_heartColor, Color.parseColor("#FF4351"));
            init(context, heartColor);
        } finally {
            typedArray.recycle();
        }
    }

    private void init(Context context, int heartColor){
        this.context = context;
        this.heartColor = heartColor;
        this.isStopped = true;
    }

// #MARK - User‘s Methods

    public void start() {
        this.isStopped = false;

        leftHeartX = width/4 + width/8;
        leftHeartY = height/4 + height/8;

        PropertyValuesHolder widthPropertyHolder = PropertyValuesHolder.ofFloat(POSITION_X, width/4 + width/8, width/2 + width/8);
        PropertyValuesHolder heightPropertyHolder = PropertyValuesHolder.ofFloat(POSITION_Y, height/4 + height/8, height/2 + height/8);
        animatorLeftHeart = ValueAnimator.ofPropertyValuesHolder(widthPropertyHolder, heightPropertyHolder);
        animatorLeftHeart.setDuration(2000);
        animatorLeftHeart.setStartDelay(1000);
        animatorLeftHeart.setInterpolator(new AnticipateOvershootInterpolator());
        animatorLeftHeart.addUpdateListener(leftHeartAnimationUpdateListener);
        animatorLeftHeart.setRepeatMode(ValueAnimator.REVERSE);
        animatorLeftHeart.setRepeatCount(ValueAnimator.INFINITE);

        widthPropertyHolder = PropertyValuesHolder.ofFloat(POSITION_X, width/2 + width/8, width/4 + width/8);
        heightPropertyHolder = PropertyValuesHolder.ofFloat(POSITION_Y, height/4 + height/8, height/2 + height/8);
        animatorRightHeart = ValueAnimator.ofPropertyValuesHolder(widthPropertyHolder, heightPropertyHolder);
        animatorRightHeart.setDuration(2000);
        animatorRightHeart.setInterpolator(new AnticipateOvershootInterpolator());
        animatorRightHeart.addUpdateListener(rightHeartAnimationUpdateListener);
        animatorRightHeart.setRepeatCount(ValueAnimator.INFINITE);
        animatorRightHeart.setRepeatMode(ValueAnimator.REVERSE);

        animatorRightHeart.start();
        animatorLeftHeart.start();

        invalidate();
    }

    public void dismiss() {
        this.isStopped = true;
        animatorLeftHeart.cancel();
        animatorRightHeart.cancel();
        invalidate();
    }

    public boolean isStopped() {
        return this.isStopped;
    }

    public void setHeartColor(int color) {
        this.heartColor = color;
        invalidate();
    }

// #MARK - Utility Methods

    private int measureWidth(int widthMeasureSpec){
        int result = 0;

        int specMode = MeasureSpec.getMode(widthMeasureSpec);
        int specSize = MeasureSpec.getSize(widthMeasureSpec);

        WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        Display display = windowManager.getDefaultDisplay();
        Point size = new Point();

        display.getSize(size);
        int screenWidth = size.x;
        if(specMode == MeasureSpec.EXACTLY){
            result = specSize;
        } else {
//            result = screenWidth;
            result = 200;
            if(specMode == MeasureSpec.AT_MOST){
                result = Math.min(result, specSize);
            }
        }
        this.width = result;
        return result;
    }

    private int measureHeight(int heightMeasureSpec){
        int result = 0;

        int specMode = MeasureSpec.getMode(heightMeasureSpec);
        int specSize = MeasureSpec.getSize(heightMeasureSpec);

        WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        Display display = windowManager.getDefaultDisplay();
        Point size = new Point();
        display.getSize(size);
        int screenHeight = size.y;
        if(specMode == MeasureSpec.EXACTLY){
            result = specSize;
        } else {
//            result = screenHeight;
            result = 200;
            if(specMode == MeasureSpec.AT_MOST){
                result = Math.min(result, specSize);
            }
        }
        this.height = result;
        return result;
    }

    private float measureCircleRadius(int width, int height){
        float radius = (float) Math.sqrt(Math.pow(width/2, 2) + Math.pow(height/2, 2))/4;
        return radius + 2;
    }

// #MARK - Listeners Methods

    ValueAnimator.AnimatorUpdateListener leftHeartAnimationUpdateListener = new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            if(!isStopped) {
                leftHeartX = (Float) animation.getAnimatedValue(POSITION_X);
                leftHeartY = (Float) animation.getAnimatedValue(POSITION_Y);
                invalidate();
            }
        }
    };

    ValueAnimator.AnimatorUpdateListener rightHeartAnimationUpdateListener = new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            if(!isStopped) {
                rightHeartX = (Float) animation.getAnimatedValue(POSITION_X);
                rightHeartY = (Float) animation.getAnimatedValue(POSITION_Y);
                invalidate();
            }
        }
    };

// #MARK - Override Methods

    @Override
    protected void onDraw(Canvas canvas){
        super.onDraw(canvas);
        canvas.save();
        if(this.width != this.height) {
            return;
        }
        if(!this.isStopped) {
            drawRhombus(canvas);
            drawCircle(canvas, rightHeartX, rightHeartY);
            drawCircle(canvas, leftHeartX, leftHeartY);
        }
        canvas.restore();
    }

    @Override
    protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
        super.onSizeChanged(width, height, oldWidth, oldHeight);
        this.width = width;
        this.height = height;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
        setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));
    }

// #MARK - Drawing Methods

    private void drawRhombus(Canvas canvas) {
        Paint rectPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        rectPaint.setColor(this.heartColor);
        RectF rect = new RectF();
        float sizeOffset = (float) (width * 0.145);
        float xOffset = (float) (width * 0.075);
        float yOffset = (float) (height * 0.075);
        rect.set(width/4 + xOffset, height/4 + sizeOffset - yOffset, width - width/4 - sizeOffset + xOffset, height - height/4 - yOffset);
        canvas.rotate(-45f, rect.centerX(), rect.centerY());
        canvas.drawRect(rect, rectPaint);
        canvas.rotate(45f, rect.centerX(), rect.centerY());

        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setColor(this.heartColor);
        paint.setStyle(Paint.Style.FILL_AND_STROKE);
        paint.setDither(true);
        paint.setStrokeJoin(Paint.Join.ROUND);
        paint.setStrokeCap(Paint.Cap.ROUND);
        paint.setStrokeWidth(3);

        Path path = new Path();
        path.setFillType(Path.FillType.EVEN_ODD);
        path.moveTo(width/2, height/4);
        path.lineTo(width/4, height/2);
        path.moveTo(width/4, height/2);
        path.lineTo(width/2, height - height/4);
        path.moveTo(width/2, height - height/4);
        path.lineTo(width - width/4, height/2);
        path.moveTo(width - width/4, height/2);
        path.lineTo(width/2, height/4);
        path.close();
        canvas.drawPath(path, paint);
    }

    private void drawCircle(Canvas canvas, float x, float y) {
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setStyle(Paint.Style.FILL);
        paint.setColor(this.heartColor);
        float circleRadius = measureCircleRadius(this.width, this.height);
        canvas.drawCircle(x, y, circleRadius, paint);
    }

}

3、我们重写onDraw,onMesure调用系统提供的:

protected void onDraw(Canvas canvas){
super.onDraw(canvas);
canvas.save();
if(this.width != this.height) {
return;
}
if(!this.isStopped) {
drawRhombus(canvas);
drawCircle(canvas, rightHeartX, rightHeartY);
drawCircle(canvas, leftHeartX, leftHeartY);
}
canvas.restore();
}

 

以上是关于android-自定义View的主要内容,如果未能解决你的问题,请参考以下文章

Android自定义的View闪烁问题

Android - 如何将自定义对象传递给片段

从android中的片段更改自定义ActionBar标题

片段中ListView的android自定义适配器

浅谈Android自定义View

Android自定义view详解