该控件通过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>