android 眨眼效果

该控件通过sin函数图像变化实现动态,背景颜色和眼皮颜色一致,效果如下


//具体代码

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.View;

/**
 * 自定义的View类,为两个球的碰撞模拟
 */
class EyesJFrame extends View {
	// 设置角度值,同时也就眼睛的横坐标长度
	int angle = 250;
	// 因为眨眼采用的sin()函数组成,所以其自然有幅值这一个属性。
	int amplitude = 40;
	// 创建一个用于保存幅值的变化的变量,采用amplitude的缩写ampl
	int ampl = 0;
	// 判断是否到了幅值的临界值,由线程维护
	boolean flag = true;
	// 定义中心点坐标
	int centerX = 1024 / 2;
	int centerY = 768 / 2;
	// 创建统一的颜色背景
	int color = Color.GRAY;
	// 灰眼球的半径初始值
	int blackBallSemi = 25;

	Paint mPaint = new Paint();
	Handler mhandler;
	boolean first = true;

	private int eyeDis = (int) (angle/2*1.5);//两眼距离

	int degree = 0;//眼球转动角度
    int leftX = centerX+eyeDis;//左眼初始化坐标
	int RightX = centerX-eyeDis;//右眼初始化坐标
	private Point pointLeft = new Point(),
			pointRight = new Point(),
    		centerLeft = new Point(),//左右中心坐标
    		centerRight = new Point(),//右眼中心坐标
    		tempLeft = new Point(),//左眼球坐标
    		tempRight = new Point();//有眼球坐标
	public EyesJFrame(Context context, AttributeSet attrs) {
		super(context, attrs);
		startRun();
		mhandler = new Handler();
		color = context.getColor(R.color.skin);//初始化背景颜色
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		//重新初始化下面参数
		centerX = this.getMeasuredWidth()/2;
		centerY = this.getMeasuredHeight()/3;
		angle = this.getMeasuredWidth()/4;
		eyeDis = (int) (angle/2*1.5);
		amplitude = angle/6;
		blackBallSemi = amplitude / 2 - 6;
		leftX = centerX+eyeDis;
		RightX = centerX-eyeDis;
		
		pointLeft.x = leftX - blackBallSemi / 2 / 2;
		pointLeft.y = centerY - blackBallSemi / 2 / 2;
		centerLeft.x = leftX - blackBallSemi;
		centerLeft.y = centerY;
		
		pointRight.x = RightX + blackBallSemi / 2 / 2;
		pointRight.y =  centerY - blackBallSemi / 2 / 2;
		centerRight.x = RightX + blackBallSemi;
		centerRight.y = centerY;
	}

	private Runnable mRunnable = new Runnable() {
		// 界面的主线程
		@Override
		public void run() {
			EyesJFrame.this.invalidate();
		}
	};

	//眼球转动
	private Runnable mRunnable1 = new Runnable() {
		// 界面的主线程
		@Override
		public void run() {
			degree = 0;
			new Thread() {
				public void run() {
					while (true) {
						degree++;
						if (degree == 360) {//转一圈360度
							degree = 0;
							break;
	                    }
						calcNewPoint(tempLeft,pointLeft,centerLeft,degree);//计算左眼转动坐标
		                calcNewPoint(tempRight,pointRight,centerRight,degree);////计算右眼转动坐标
		                mhandler.post(mRunnable); 
		                try {
							Thread.sleep(3);
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}

				};

			}.start();
		}
	};
	
    
    private static void calcNewPoint(Point p1,Point p, Point pCenter, float angle) {  
        // calc arc   
        float l = (float) ((angle * Math.PI) / 180);  
          
        //sin/cos value  
        float cosv = (float) Math.cos(l);  
        float sinv = (float) Math.sin(l);  
      
        // calc new point  
        float newX = (float) ((p.x - pCenter.x) * cosv - (p.y - pCenter.y) * sinv + pCenter.x);  
        float newY = (float) ((p.x - pCenter.x) * sinv + (p.y - pCenter.y) * cosv + pCenter.y); 
        p1.x = (int) newX;
        p1.y = (int) newY;
        //return new Point((int) newX, (int) newY);  
    }

	/**
	 * 用线程维护眼睛的眨眼效果,线程结构如下: 1、该线程使用while(true)维护动态效果 2、ampl用于表示当前的眨眼效果的幅值
	 */
	public void startRun() {
		new Thread() {
			public void run() {
				while (true) {
					if (flag) {
						ampl++;
						if (ampl >= amplitude) {//眨眼幅度
							flag = false;
						}
						if (!first) {
							first = true;
						}
					} else {
						ampl--;
						if (ampl <= 0) {
							flag = true;
						}
						if (first) {
							mhandler.post(mRunnable1);
							try {
								Thread.sleep(3000);//3秒眨一次眼
							} catch (InterruptedException e) {
								e.printStackTrace();
							}
							first = false;
						}

					}
					try {
						Thread.sleep(5);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					mhandler.post(mRunnable);
				}

			};

		}.start();
	}

	@Override
	public void onDraw(Canvas canvas) {
		drawLeft(canvas);//左眼
		drawRight(canvas);//右眼
	}

	private void drawLeft(Canvas canvas) {
		// 以centerX,centerY为中心,在眼睛所在的地方绘制一个白色的背景底色,
		// 长度为angle,宽为amplitude*2
		
		mPaint.setColor(Color.WHITE);
		for (int i = 0; i < angle; i++) {
			canvas.drawLine(leftX - angle / 2 + i, centerY, leftX - angle
					/ 2 + i, centerY
					- (int) (Math.sin(Math.PI * i / angle) * amplitude), mPaint);
			canvas.drawLine(leftX - angle / 2 + i, centerY, leftX - angle
					/ 2 + i, centerY
					+ (int) (Math.sin(Math.PI * i / angle) * amplitude), mPaint);
		}
		// 以centerX,centerY为中心,绘制一个灰色的眼球
		// 半径为blackBallSemi*2
		mPaint.setColor(Color.DKGRAY);
		canvas.drawCircle(leftX - blackBallSemi, centerY, blackBallSemi * 2,
				mPaint);
		// 以centerX,centerY为中心,绘制一个白色的瞳孔
		// 半径为blackBallSemi/2
		mPaint.setColor(Color.WHITE);
		canvas.drawCircle(tempLeft.x, tempLeft.y, blackBallSemi / 2, mPaint);
		// 使用和窗口一样的背景色将眼睛外框颜色去掉,这里使用sin()函数来完成
		// 在这里体现的方法其实就是画直线,把不需要的地方都画成与背景色相同的颜色
		mPaint.setColor(color);
		for (int i = 0; i < angle; i++) {
			canvas.drawLine(leftX - angle / 2 + i, centerY - amplitude,
					leftX - angle / 2 + i,
					centerY - (int) (Math.sin(Math.PI * i / angle) * ampl),
					mPaint);
			canvas.drawLine(leftX - angle / 2 + i, centerY + amplitude,
					leftX - angle / 2 + i,
					centerY + (int) (Math.sin(Math.PI * i / angle) * ampl),
					mPaint);
		}
	}

	private void drawRight(Canvas canvas) {
		// 长度为angle,宽为amplitude*2

		mPaint.setColor(Color.WHITE);
		for (int i = 0; i < angle; i++) {
			canvas.drawLine(RightX - angle / 2 + i, centerY, RightX - angle
					/ 2 + i, centerY
					- (int) (Math.sin(Math.PI * i / angle) * amplitude), mPaint);
			canvas.drawLine(RightX - angle / 2 + i, centerY, RightX - angle
					/ 2 + i, centerY
					+ (int) (Math.sin(Math.PI * i / angle) * amplitude), mPaint);
		}
		// 以centerX,centerY为中心,绘制一个灰色的眼球
		// 半径为blackBallSemi*2
		mPaint.setColor(Color.DKGRAY);
		canvas.drawCircle(RightX + blackBallSemi, centerY, blackBallSemi * 2,
				mPaint);
		// 以centerX,centerY为中心,绘制一个白色的瞳孔
		// 半径为blackBallSemi/2
		mPaint.setColor(Color.WHITE);
		/*canvas.drawCircle(RightX + blackBallSemi / 2 / 2, centerY
				- blackBallSemi / 2 / 2, blackBallSemi / 2, mPaint);*/
		canvas.drawCircle(tempRight.x, tempRight.y, blackBallSemi / 2, mPaint);
		// 使用和窗口一样的背景色将眼睛外框颜色去掉,这里使用sin()函数来完成
		// 在这里体现的方法其实就是画直线,把不需要的地方都画成与背景色相同的颜色
		mPaint.setColor(color);
		for (int i = 0; i < angle; i++) {
			canvas.drawLine(RightX - angle / 2 + i, centerY - amplitude,
					RightX - angle / 2 + i,
					centerY - (int) (Math.sin(Math.PI * i / angle) * ampl),
					mPaint);
			canvas.drawLine(RightX - angle / 2 + i, centerY + amplitude,
					RightX - angle / 2 + i,
					centerY + (int) (Math.sin(Math.PI * i / angle) * ampl),
					mPaint);
		}
	}

}
 
 
 
 
//布局文件如下
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/background"
    android:layout_width="match_parent"
    android:background="@color/skin"
    android:layout_height="match_parent">


    <com.floatbubbleview.view.EyesJFrame
        android:background="@android:color/transparent"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />


</RelativeLayout>
 
 
//颜色
<color name="skin">#EEE8CD</color>


猜你喜欢

转载自blog.csdn.net/zhuxingchong/article/details/79083020
今日推荐