效果图:
原理:
监听手指向下滑动,对小眼睛的bitmap进行重新绘制,最简单的方法就是直接在原来的眼睛基础上再画一个圆环,圆环环的宽度由大变小,小眼睛就慢慢出来了
布局文件:
activity_main.layout
<LinearLayout xmlns:android="http://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