高仿微信下拉出现小眼睛动画

效果图:




原理:

监听手指向下滑动,对小眼睛的bitmap进行重新绘制,最简单的方法就是直接在原来的眼睛基础上再画一个圆环,圆环环的宽度由大变小,小眼睛就慢慢出来了


布局文件:




activity_main.layout

<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="48dp"
        android:background="#22292C" >

        <FrameLayout
            android:layout_width="wrap_content"
            android:layout_height="48dp"
            android:layout_alignParentLeft="true"
            android:layout_centerVertical="true"
            android:layout_marginLeft="8dp" >

            <TextView
                android:id="@+id/tv"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical"
                android:text="微信"
                android:textColor="#FFFFFF"
                android:textSize="16sp" />

            <Button
                android:id="@+id/bt_del"
                android:layout_width="32dp"
                android:layout_height="32dp"
                android:layout_gravity="center_vertical"
                android:alpha="0"
                android:background="@drawable/a8u" />
        </FrameLayout>

        <Button
            android:id="@+id/bt_add"
            android:layout_width="32dp"
            android:layout_height="32dp"
            android:layout_alignParentRight="true"
            android:layout_centerVertical="true"
            android:layout_margin="8dp"
            android:background="@drawable/a8g" />

        <Button
            android:id="@+id/bt_search"
            android:layout_width="32dp"
            android:layout_height="32dp"
            android:layout_centerVertical="true"
            android:layout_margin="8dp"
            android:layout_toLeftOf="@+id/bt_add"
            android:background="@drawable/a8w" />
    </RelativeLayout>

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

        <include layout="@layout/layout_vedio" />

        <include layout="@layout/layout_chat" />
    </FrameLayout>

</LinearLayout>

代码核心逻辑,对上层界面的滑动监听

	private boolean isMoving = false;

	class MyTouchEvent implements OnTouchListener {

		@Override
		public boolean onTouch(View v, MotionEvent event) {

			if (isMoving)
				return true;
			final int[] location = new int[2];
			mEye.getLocationOnScreen(location);
			int bound = (int) (location[1] + mEye.getHeight());

			switch (event.getAction()) {
			case MotionEvent.ACTION_DOWN:
				downY = (int) event.getRawY();
				break;
			case MotionEvent.ACTION_MOVE:
				int dy = (int) event.getRawY() - downY;
				if (dy < 0)
					break;
				Log.i("ACTION_MOVE", "move>>>>>>>>>>" + dy);
				ViewHelper.setTranslationY(mRl2, dy * factory);
				mEye.setImageBitmap(getCutEye(dy));
				break;
			case MotionEvent.ACTION_UP:
				dy = (int) event.getRawY() - downY;
				Log.i("ACTION_MOVE", "bound" + bound + ",up>>>>>>>>>>" + event.getRawY() + "  "
						+ screenHeight);
				if (dy > bound) {
					showVedioView(event);
				} else {
					showChatView(event);
				}
				break;
			}
			return true;
		}
	}


裁剪小眼睛:

public Bitmap getCutEye(int dy) {
		Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.a_a);
		Bitmap bitmap = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(), Config.RGB_565);
		if (dy > mEye.getHeight()*1.5f) {
			Canvas canvas = new Canvas(bitmap);
			Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
			paint.setColor(Color.BLACK);
			paint.setStyle(Paint.Style.STROKE); // 绘制空心圆
			canvas.drawBitmap(bm, 0, 0, paint);

			Log.i("", "bmH:" + bm.getHeight() + ",dy:" + dy);
			paint.setStrokeWidth(bm.getHeight()*1.5f - dy * 0.5f);
			RectF oval = new RectF(0, 0, bm.getWidth(), bm.getHeight());
			canvas.drawArc(oval, 0, 360, false, paint);
		}
		return bitmap;
	}


布局的动画:

public void showChatView(MotionEvent event) {
		isMoving = true;
		final int oldY = (int) mRl2.getY();
		ValueAnimator va = ValueAnimator.ofFloat(0, time);
		va.setDuration((long) time);
		va.start();
		va.addUpdateListener(new AnimatorUpdateListener() {
			@Override
			public void onAnimationUpdate(ValueAnimator arg0) {
				float value = (float) arg0.getAnimatedValue() / time;
				Log.i("", "Value:" + value);
				mRl2.setY(oldY * (1 - value));
				if (value >= 1)
					isMoving = false;
			}
		});
	}

	public void showVedioView(MotionEvent event) {
		isMoving = true;

		final int[] location = new int[2];
		mRl2.getLocationOnScreen(location);

		final int oldY = (int) mRl2.getY();
		ValueAnimator va = ValueAnimator.ofFloat(0, time);
		va.setDuration((long) time);
		va.start();
		va.addUpdateListener(new AnimatorUpdateListener() {
			@Override
			public void onAnimationUpdate(ValueAnimator arg0) {
				float value = (float) arg0.getAnimatedValue() / time;
				Log.i("", "Value:" + value);
				mRl2.setY(oldY + value * (screenHeight - location[1]));
				mEye.setScaleX(value + 1);
				mEye.setScaleY(value + 1);
				mEye.setY(value * 200);
				mDel.setAlpha(value);
				mTv.setAlpha(1 - value);
				mAdd.setAlpha(1 - value);
				mSearch.setAlpha(1 - value);
				if (value >= 1) {
					mDel.setEnabled(true);
				}
			}
		});
	}



完整的代码:

package com.zyh.pull2change;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.nineoldandroids.animation.ValueAnimator;
import com.nineoldandroids.animation.ValueAnimator.AnimatorUpdateListener;
import com.nineoldandroids.view.ViewHelper;

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		bindViews();

		DisplayMetrics metrics = new DisplayMetrics();
		getWindowManager().getDefaultDisplay().getMetrics(metrics);
		screenHeight = metrics.heightPixels;

		mDel.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				ValueAnimator va = ValueAnimator.ofFloat(0, time);
				va.setDuration((long) time);
				va.start();
				final float sc = mRl2.getScaleX();
				final float oldY = mEye.getY();
				va.addUpdateListener(new AnimatorUpdateListener() {
					@Override
					public void onAnimationUpdate(ValueAnimator arg0) {
						float value = (float) arg0.getAnimatedValue() / time;
						Log.i("", "Value:" + value);
						mRl2.setY((1 - value) * screenHeight);
						mDel.setAlpha(1 - value);
						mTv.setAlpha(value);
						mAdd.setAlpha(value);
						mSearch.setAlpha(value);
						mEye.setScaleX(sc * (1 - value) + 1);
						mEye.setScaleY(sc * (1 - value) + 1);
						mEye.setY(oldY * (1 - value));
						if (value >= 1) {
							isMoving = false;
							mDel.setEnabled(false);
						}
					}
				});
			}
		});
		mRl2.setOnTouchListener(new MyTouchEvent());
	}

	private boolean isMoving = false;

	class MyTouchEvent implements OnTouchListener {

		@Override
		public boolean onTouch(View v, MotionEvent event) {

			if (isMoving)
				return true;
			final int[] location = new int[2];
			mEye.getLocationOnScreen(location);
			int bound = (int) (location[1] + mEye.getHeight());

			switch (event.getAction()) {
			case MotionEvent.ACTION_DOWN:
				downY = (int) event.getRawY();
				break;
			case MotionEvent.ACTION_MOVE:
				int dy = (int) event.getRawY() - downY;
				if (dy < 0)
					break;
				Log.i("ACTION_MOVE", "move>>>>>>>>>>" + dy);
				ViewHelper.setTranslationY(mRl2, dy * factory);
				mEye.setImageBitmap(getCutEye(dy));
				break;
			case MotionEvent.ACTION_UP:
				dy = (int) event.getRawY() - downY;
				Log.i("ACTION_MOVE", "bound" + bound + ",up>>>>>>>>>>" + event.getRawY() + "  "
						+ screenHeight);
				if (dy > bound) {
					showVedioView(event);
				} else {
					showChatView(event);
				}
				break;
			}
			return true;
		}
	}

	private float factory = 0.6f;
	private int screenHeight;
	private int downY;
	private RelativeLayout mRl2;
	private ImageView mEye;
	private float time = 500;
	private TextView mTv;
	private Button mDel;
	private Button mSearch;
	private Button mAdd;

	private void bindViews() {
		mRl2 = (RelativeLayout) findViewById(R.id.rl2);
		mEye = (ImageView) findViewById(R.id.iv_eye);
		mDel = (Button) findViewById(R.id.bt_del);
		mSearch = (Button) findViewById(R.id.bt_search);
		mAdd = (Button) findViewById(R.id.bt_add);
		mTv = (TextView) findViewById(R.id.tv);
	}

	public Bitmap getCutEye(int dy) {
		Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.a_a);
		Bitmap bitmap = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(), Config.RGB_565);
		if (dy > mEye.getHeight()*1.5f) {
			Canvas canvas = new Canvas(bitmap);
			Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
			paint.setColor(Color.BLACK);
			paint.setStyle(Paint.Style.STROKE); // 绘制空心圆
			canvas.drawBitmap(bm, 0, 0, paint);

			Log.i("", "bmH:" + bm.getHeight() + ",dy:" + dy);
			paint.setStrokeWidth(bm.getHeight()*1.5f - dy * 0.5f);
			RectF oval = new RectF(0, 0, bm.getWidth(), bm.getHeight());
			canvas.drawArc(oval, 0, 360, false, paint);
		}
		return bitmap;
	}

	public void showChatView(MotionEvent event) {
		isMoving = true;
		final int oldY = (int) mRl2.getY();
		ValueAnimator va = ValueAnimator.ofFloat(0, time);
		va.setDuration((long) time);
		va.start();
		va.addUpdateListener(new AnimatorUpdateListener() {
			@Override
			public void onAnimationUpdate(ValueAnimator arg0) {
				float value = (float) arg0.getAnimatedValue() / time;
				Log.i("", "Value:" + value);
				mRl2.setY(oldY * (1 - value));
				if (value >= 1)
					isMoving = false;
			}
		});
	}

	public void showVedioView(MotionEvent event) {
		isMoving = true;

		final int[] location = new int[2];
		mRl2.getLocationOnScreen(location);

		final int oldY = (int) mRl2.getY();
		ValueAnimator va = ValueAnimator.ofFloat(0, time);
		va.setDuration((long) time);
		va.start();
		va.addUpdateListener(new AnimatorUpdateListener() {
			@Override
			public void onAnimationUpdate(ValueAnimator arg0) {
				float value = (float) arg0.getAnimatedValue() / time;
				Log.i("", "Value:" + value);
				mRl2.setY(oldY + value * (screenHeight - location[1]));
				mEye.setScaleX(value + 1);
				mEye.setScaleY(value + 1);
				mEye.setY(value * 200);
				mDel.setAlpha(value);
				mTv.setAlpha(1 - value);
				mAdd.setAlpha(1 - value);
				mSearch.setAlpha(1 - value);
				if (value >= 1) {
					mDel.setEnabled(true);
				}
			}
		});
	}

}




源码: https://github.com/18236887539/WeixinEye