沒事的時候就喜歡刷刷今日頭條,(不得不吐槽一下,現在的頭條廣告太他媽多了),以前也沒有太在意,這兩天看到個有意思的文章想分享盆友圈時候,突然發現,這個分享平台彈出的動畫挺有趣的,感覺很好玩,但是覺得好像在android端的app上就沒見過,我趕緊把android測試機拿出來試了試,果然:
- 這是ios版的分享動畫:

- 這是android版的分享動畫:
這我就不開心了,ios搞得,難道android就搞不得.廢話不多說,開搞…
- 首先,用屬性動畫應該可以搞出來
- 其次,需要給動畫加個內插補點器interpolator來實作效果
- 然後,界面優化适配等(沒弄)
interpolator不了解的可以看這個部落格,講的挺細的android之interpolator的用法詳解
這是自定義view的代碼,參考了github上一個項目,但位址忘了,找到了再貼上:
public class ShareView2 extends View {
private static final float RADIUS = f;//上排距離
private static final float RADIUS2 = f;//下排距離
private static final float HEIGHT_VIEW = f;
private static float DISTANCEPOINT = ;
private OnDownActionListener2 mDown = null;
private Point currentPoint1;
private Point currentPoint2;
private Point currentPoint3;
private Point currentPoint4;
private Point currentPoint5;
private Point currentPoint6;
private Point currentPoint7;
private float startX;
private float startY;
private float startY2;
private float width;
private float height;
private Paint mPaint;
private Bitmap bitmap1;
private Bitmap bitmap2;
private Bitmap bitmap3;
private Bitmap bitmap4;
private Bitmap bitmap5;
private Bitmap bitmap6;
private Bitmap bitmap7;
public ShareView2(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(Color.BLUE);
// 初始化
WindowManager wm = (WindowManager) getContext().getSystemService(
Context.WINDOW_SERVICE);
height = wm.getDefaultDisplay().getHeight();
width = wm.getDefaultDisplay().getWidth();
Log.e("TAG---", "height----" + height);
Log.e("TAG---", "width----" + width);
DISTANCEPOINT = width / ;
bitmap1 = BitmapFactory.decodeResource(getResources(), R.drawable.umeng_socialize_wechat);
bitmap2 = BitmapFactory.decodeResource(getResources(), R.drawable.umeng_socialize_qq_on);
bitmap3 = BitmapFactory
.decodeResource(getResources(), R.drawable.umeng_socialize_wxcircle);
bitmap4 = BitmapFactory.decodeResource(getResources(), R.drawable.umeng_socialize_qzone_on);
bitmap5 = BitmapFactory.decodeResource(getResources(), R.drawable.umeng_socialize_sina_on);
bitmap6 = BitmapFactory.decodeResource(getResources(), R.drawable.umeng_socialize_sms_on);
bitmap7 = BitmapFactory.decodeResource(getResources(), R.drawable.umeng_socialize_gmail_on);
System.out.println("bitmap_width " + bitmap1.getWidth());
startX = (float) (DISTANCEPOINT - bitmap1.getWidth() / );
startY = height - RADIUS;
startY2 = height - RADIUS2;
}
@Override
protected void onDraw(Canvas canvas) {
if (currentPoint1 == null) {
currentPoint1 = new Point(startX, startY);
currentPoint2 = new Point(startX + DISTANCEPOINT, startY);
currentPoint3 = new Point(startX + * DISTANCEPOINT, startY);
currentPoint4 = new Point(startX + * DISTANCEPOINT, startY);
currentPoint5 = new Point(startX, startY2);
currentPoint6 = new Point(startX + DISTANCEPOINT, startY2);
currentPoint7 = new Point(startX + * DISTANCEPOINT, startY2);
canvas.drawBitmap(bitmap1, currentPoint1.getX(),
currentPoint1.getY(), mPaint);
canvas.drawBitmap(bitmap2, currentPoint2.getX(),
currentPoint2.getY(), mPaint);
canvas.drawBitmap(bitmap3, currentPoint3.getX(),
currentPoint3.getY(), mPaint);
canvas.drawBitmap(bitmap4, currentPoint4.getX(),
currentPoint4.getY(), mPaint);
canvas.drawBitmap(bitmap5, currentPoint5.getX(),
currentPoint5.getY(), mPaint);
canvas.drawBitmap(bitmap6, currentPoint6.getX(),
currentPoint6.getY(), mPaint);
canvas.drawBitmap(bitmap7, currentPoint7.getX(),
currentPoint7.getY(), mPaint);
startAnimation(, startX, startY);
startAnimation(, startX + DISTANCEPOINT, startY);
startAnimation(, startX + * DISTANCEPOINT, startY);
startAnimation(, startX + * DISTANCEPOINT, startY);
startAnimation(, startX, startY2);
startAnimation(, startX + DISTANCEPOINT, startY2);
startAnimation(, startX + * DISTANCEPOINT, startY2);
} else {
canvas.drawBitmap(bitmap1, currentPoint1.getX(),
currentPoint1.getY(), mPaint);
canvas.drawBitmap(bitmap2, currentPoint2.getX(),
currentPoint2.getY(), mPaint);
canvas.drawBitmap(bitmap3, currentPoint3.getX(),
currentPoint3.getY(), mPaint);
canvas.drawBitmap(bitmap4, currentPoint4.getX(),
currentPoint4.getY(), mPaint);
canvas.drawBitmap(bitmap5, currentPoint5.getX(),
currentPoint5.getY(), mPaint);
canvas.drawBitmap(bitmap6, currentPoint6.getX(),
currentPoint6.getY(), mPaint);
canvas.drawBitmap(bitmap7, currentPoint7.getX(),
currentPoint7.getY(), mPaint);
}
}
@SuppressLint("NewApi")
private void startAnimation(int flag, float startX, float startY) {
Point startPoint = new Point(startX, startY);
Point endPoint = new Point(startX, startY - HEIGHT_VIEW);
ValueAnimator anim = ValueAnimator.ofObject(new PointEvaluator(),
startPoint, endPoint);
switch (flag) {
case :
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@SuppressLint("NewApi")
@Override
public void onAnimationUpdate(ValueAnimator animation) {
currentPoint1 = (Point) animation.getAnimatedValue();
invalidate();
}
});
anim.setInterpolator(new AnticipateOvershootInterpolator());
anim.setDuration();
anim.start();
break;
case :
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@SuppressLint("NewApi")
@Override
public void onAnimationUpdate(ValueAnimator animation) {
currentPoint2 = (Point) animation.getAnimatedValue();
invalidate();
}
});
anim.setInterpolator(new AnticipateOvershootInterpolator());
anim.setDuration();
anim.setStartDelay();
anim.start();
break;
case :
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@SuppressLint("NewApi")
@Override
public void onAnimationUpdate(ValueAnimator animation) {
currentPoint3 = (Point) animation.getAnimatedValue();
invalidate();
}
});
anim.setInterpolator(new AnticipateOvershootInterpolator());
anim.setDuration();
anim.setStartDelay();
anim.start();
break;
case :
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@SuppressLint("NewApi")
@Override
public void onAnimationUpdate(ValueAnimator animation) {
currentPoint4 = (Point) animation.getAnimatedValue();
invalidate();
}
});
anim.setInterpolator(new AnticipateOvershootInterpolator());
anim.setDuration();
anim.setStartDelay();
anim.start();
break;
case :
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@SuppressLint("NewApi")
@Override
public void onAnimationUpdate(ValueAnimator animation) {
currentPoint5 = (Point) animation.getAnimatedValue();
invalidate();
}
});
anim.setInterpolator(new AnticipateOvershootInterpolator());
anim.setDuration();
anim.setStartDelay();
anim.start();
break;
case :
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@SuppressLint("NewApi")
@Override
public void onAnimationUpdate(ValueAnimator animation) {
currentPoint6 = (Point) animation.getAnimatedValue();
invalidate();
}
});
anim.setInterpolator(new AnticipateOvershootInterpolator());
anim.setDuration();
anim.setStartDelay();
anim.start();
break;
case :
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@SuppressLint("NewApi")
@Override
public void onAnimationUpdate(ValueAnimator animation) {
currentPoint7 = (Point) animation.getAnimatedValue();
invalidate();
}
});
anim.setInterpolator(new AnticipateOvershootInterpolator());
anim.setDuration();
anim.setStartDelay();
anim.start();
break;
default:
break;
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension((int) width, (int) height);
}
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
if (event.getAction() == MotionEvent.ACTION_UP) {
System.out.println("up");
} else if (event.getAction() == MotionEvent.ACTION_DOWN) {
int result = ;
result = isClick(x, y);
switch (result) {
case :
mDown.OnDown();
return true;
case :
mDown.OnDown();
return true;
case :
mDown.OnDown();
return true;
case :
mDown.OnDown();
return true;
case :
mDown.OnDown();
return true;
case :
mDown.OnDown();
return true;
case :
mDown.OnDown();
return true;
default:
break;
}
}
mDown.OnDown();
return super.onTouchEvent(event);
}
private int isClick(float x, float y) {
if (y > startY - HEIGHT_VIEW
&& y < startY - HEIGHT_VIEW + bitmap1.getHeight() && x > startX
&& x < startX + bitmap1.getWidth()) {
return ;
}
if (y > startY - HEIGHT_VIEW
&& y < startY - HEIGHT_VIEW + bitmap1.getHeight()
&& x > startX + DISTANCEPOINT
&& x < startX + DISTANCEPOINT + bitmap1.getWidth()) {
return ;
}
if (y > startY - HEIGHT_VIEW
&& y < startY - HEIGHT_VIEW + bitmap1.getHeight()
&& x > startX + * DISTANCEPOINT
&& x < startX + * DISTANCEPOINT + bitmap1.getWidth()) {
return ;
}
if (y > startY - HEIGHT_VIEW
&& y < startY - HEIGHT_VIEW + bitmap1.getHeight()
&& x > startX + * DISTANCEPOINT
&& x < startX + * DISTANCEPOINT + bitmap1.getWidth()) {
return ;
}
if (y > startY2 - HEIGHT_VIEW
&& y < startY2 - HEIGHT_VIEW + bitmap1.getHeight()
&& x > startX
&& x < startX + bitmap1.getWidth()) {
return ;
}
if (y > startY2 - HEIGHT_VIEW
&& y < startY2 - HEIGHT_VIEW + bitmap1.getHeight()
&& x > startX + DISTANCEPOINT
&& x < startX + DISTANCEPOINT + bitmap1.getWidth()) {
return ;
}
if (y > startY2 - HEIGHT_VIEW
&& y < startY2 - HEIGHT_VIEW + bitmap1.getHeight()
&& x > startX + * DISTANCEPOINT
&& x < startX + * DISTANCEPOINT + bitmap1.getWidth()) {
return ;
}
return ;
}
// 為每個接口設定監聽器
public void setOnDownActionListener(OnDownActionListener2 down) {
mDown = down;
}
public interface OnDownActionListener2 {
public void OnDown(int clickPoint);
}
}
其中,用到的類:
public class Point {
private float x;
private float y;
public Point(float x, float y) {
this.x = x;
this.y = y;
}
public float getX() {
return x;
}
public float getY() {
return y;
}
}
public class PointEvaluator2 implements TypeEvaluator{
@Override
public Object evaluate(float fraction, Object startValue, Object endValue) {
Point startPoint = (Point) startValue;
Point endPoint = (Point) endValue;
float x = startPoint.getX() + fraction * (endPoint.getX() - startPoint.getX());
float y = startPoint.getY() + fraction * (endPoint.getY() - startPoint.getY());
Point point = new Point(x, y);
return point;
}
然後,在布局檔案share_pop_window2中使用:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="600dp"
>
<cn.heshi.sharedemo.widget.ShareView2
android:id="@+id/share_view"
android:layout_width="match_parent"
android:layout_height="600dp"
android:background="@android:color/transparent"
android:layout_alignParentBottom="true" />
</RelativeLayout>
自定義popwindow:
public class SharePopWindow2 extends PopupWindow implements ShareView2.OnDownActionListener2 {
private View sharePopWindow;
private ShareView2 shareView;
private OnClickPointListener2 onclickPointListener;
public SharePopWindow2(Activity context ) {
super(context);
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
sharePopWindow=inflater.inflate(R.layout.share_pop_window2, null);
shareView=(ShareView2) sharePopWindow.findViewById(R.id.share_view);
shareView.setOnDownActionListener(this);
this.setContentView(sharePopWindow);
//設定SelectPicPopupWindow彈出窗體的寬
this.setWidth(LayoutParams.MATCH_PARENT);
//設定SelectPicPopupWindow彈出窗體的高
this.setHeight();
//設定SelectPicPopupWindow彈出窗體可點選
this.setFocusable(true);
//設定SelectPicPopupWindow彈出窗體動畫效果
this.setAnimationStyle(R.style.popWindow_animation);
//執行個體化一個ColorDrawable顔色為半透明
ColorDrawable dw = new ColorDrawable();
//設定SelectPicPopupWindow彈出窗體的背景
this.setBackgroundDrawable(dw);
}
public void setOnClickPointListener(OnClickPointListener2 onclickPointListener){
this.onclickPointListener=onclickPointListener;
}
public interface OnClickPointListener2 {
public void OnClickPoint(int clickPoint);
}
@Override
public void OnDown(int clickPoint) {
onclickPointListener.OnClickPoint(clickPoint);
}
}
最後在activity中為按鈕添加點選事件,彈出popwindow:
shareButton1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// 執行個體化SelectPicPopupWindow
sharePopWindow2 = new SharePopWindow2(MainActivity.this);
SharePopWindow2.OnClickPointListener2 onClickPointListener = new SharePopWindow2.OnClickPointListener2() {
@Override
public void OnClickPoint(int clickPoint) {
switch (clickPoint) {
case :
Toast.makeText(MainActivity.this, "wx",
Toast.LENGTH_SHORT).show();
break;
case :
Toast.makeText(MainActivity.this, "qq",
Toast.LENGTH_SHORT).show();
break;
case :
Toast.makeText(MainActivity.this, "circle",
Toast.LENGTH_SHORT).show();
break;
case :
Toast.makeText(MainActivity.this, "qzone",
Toast.LENGTH_SHORT).show();
break;
case :
Toast.makeText(MainActivity.this, "weibo",
Toast.LENGTH_SHORT).show();
break;
case :
Toast.makeText(MainActivity.this, "sms",
Toast.LENGTH_SHORT).show();
break;
case :
Toast.makeText(MainActivity.this, "email",
Toast.LENGTH_SHORT).show();
break;
default:
sharePopWindow2.dismiss();
break;
}
}
};
sharePopWindow2.setOnClickPointListener(onClickPointListener);
// 顯示視窗
sharePopWindow2.showAtLocation(
MainActivity.this.findViewById(R.id.share_button),
Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, , ); // 設定layout在PopupWindow中顯示的位置
}
});
最後上效果圖: