Android仿苹果siri浮动控件

实现原理是用WindowManager添加视图,生命周期可以不跟随某一页面或某一应用,可以全屏浮动(状态栏除外)。只有一个主类FloatView。在应用中new一下就可以显示了。

需要添加权限:<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

参考了网上很多的例子,谢谢大家的分享。


主类FloatView贴在下面,详细的大家可以下载项目看看。

package com.example.testandroidproject;

import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.PixelFormat;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.widget.ImageView;

public class FloatView extends ImageView implements OnTouchListener{

	private float x; //touch事件相对于屏幕的位置
	private float y; 
	
	private float mTouchX; //touch事件相对于控件左上角的位置
	private float mTouchY; 
	
	private float mStartX; 
	private float mStartY; 
	
	private int screenWidth;//屏幕宽度
	
	private int width;//控件宽度
	
	private int statusBarHeight;//状态栏高度

	private boolean is_translucent = true;//按钮是否是半透明效果,默认为true	
	
	private WindowManager windowManager;

	private WindowManager.LayoutParams windowManagerParams;//此windowManagerParams用以保存悬浮窗口的属性 

	private OnClickListener mClickListener; 
	
	private final int SMALL_ALPHA = 100;//最小透明度
	private final int BIG_ALPHA = 200;//最大透明度		
	
	private final int MSG_TRANSLUCENT = 1;//使按钮变半透明
	
	//handler使用弱引用避免内存泄漏
	private WeakReference
   
   
    
     handler = new WeakReference
    
    
     
     (new Handler() {
		@Override
		public void handleMessage(Message msg) {
			super.handleMessage(msg);
			switch(msg.what){
			case MSG_TRANSLUCENT:
				alphaAnimator(BIG_ALPHA,SMALL_ALPHA);
				is_translucent = true;
				break;
			}
		}
	});

	public FloatView(Context context) {
		this(context,null);
	}

	public FloatView(Context context, AttributeSet attrs) {
		super(context, attrs);
		
		DisplayMetrics dm = getResources().getDisplayMetrics();    
		screenWidth = dm.widthPixels; 

		statusBarHeight = getStatusHeight(context);
		
		setPadding(0, 10, 0, 10);
		//设置图片
		Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
		setImageBitmap(bitmap);
		
		setBackgroundResource(R.drawable.selector_bg_float_view);//设置背景点击效果
		
		setViewAlpha(SMALL_ALPHA);//设置半透明效果
		
		setOnTouchListener(this);//设置点击事件监听

		windowManagerParams = new WindowManager.LayoutParams(); 
		
		windowManagerParams.type = LayoutParams.TYPE_PHONE; // 设置window type 
		windowManagerParams.format = PixelFormat.RGBA_8888; // 设置图片格式,效果为背景透明 

		//设置Window flag 
		windowManagerParams.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL|LayoutParams.FLAG_NOT_FOCUSABLE; 
		/* 注意,flag的值可以为: 
		 LayoutParams.FLAG_NOT_TOUCH_MODAL 不影响后面的事件 
		 LayoutParams.FLAG_NOT_FOCUSABLE 不可聚焦 
		 LayoutParams.FLAG_NOT_TOUCHABLE 不可触摸 */

		// 调整悬浮窗口至左上角,便于调整坐标 
		windowManagerParams.gravity = Gravity.LEFT | Gravity.TOP; 
		// 以屏幕左上角为原点,设置x、y初始值 
		windowManagerParams.x = 0; 
		windowManagerParams.y = 0; 
		// 设置悬浮窗口长宽数据 
		windowManagerParams.width = LayoutParams.WRAP_CONTENT; 
		windowManagerParams.height = LayoutParams.WRAP_CONTENT; 
		
		windowManager = (WindowManager) getContext() 
				.getApplicationContext().getSystemService(Context.WINDOW_SERVICE); 
		windowManager.addView(this, windowManagerParams); //显示FloatView
	}


	@Override
	public boolean onTouch(View v, MotionEvent event) {
		int ea = event.getAction();  

		if(is_translucent){
			setViewAlpha(BIG_ALPHA);
			is_translucent = false;
		}

		// 获取相对屏幕的坐标,即以屏幕左上角为原点 
		x = event.getRawX(); 
		y = event.getRawY()-statusBarHeight; // statusBarHeight是系统状态栏的高度 

		switch(ea){
		case MotionEvent.ACTION_DOWN: 
			setPressed(true);
			// 获取相对View的坐标,即以此View左上角为原点 
			mTouchX = event.getX(); 
			mTouchY = event.getY(); 
			mStartX = x; 
			mStartY = y; 
			break;     
		case MotionEvent.ACTION_MOVE:  			
			updateViewPosition(x-mTouchX,y-mTouchY); 
			break;                    
		case MotionEvent.ACTION_UP:  	
			if ((x - mStartX) < 5 && (y - mStartY) < 5&&mClickListener!=null)
				mClickListener.onClick(this); 

			if(x<=screenWidth/2)	
				horizontalTranslate(x-mTouchX,0);
			else
				horizontalTranslate(x-mTouchX,screenWidth-width);	

			setPressed(false);//恢复未选中状态

			handler.get().removeMessages(MSG_TRANSLUCENT);
			handler.get().sendEmptyMessageDelayed(MSG_TRANSLUCENT, 3000);

		default:
			break;	
		}
		return true;	
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {		
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		//获取测试完成后的宽度
		width  = getWidth(); 
	}

	/**
	 * 获得状态栏的高度
	 * 
	 * @param context
	 * @return
	 */
	private int getStatusHeight(Context context) {
		int statusBarHeight = 0; 
		try {  
			Class
     
      c = Class.forName("com.android.internal.R$dimen");  
			Object o = c.newInstance();  
			Field field = c.getField("status_bar_height");  
			int x = (Integer) field.get(o);  
			statusBarHeight = getResources().getDimensionPixelSize(x);  
		} catch (Exception e) {  
			e.printStackTrace();  
		}  

		return statusBarHeight; 
	}

	/**
	 * 水平平移属性动画
	 * @param xStart 水平移动开始位置
	 * @param xEnd 水平移动结束位置
	 */
	private void horizontalTranslate(float xStart,float xEnd){
		if(xStart==xEnd)
			return;
		ValueAnimator animation = ValueAnimator.ofFloat(xStart,xEnd);
		animation.setDuration(300);
		animation.addUpdateListener(new AnimatorUpdateListener() {
			@Override
			public void onAnimationUpdate(ValueAnimator animation) {	
				float x = (Float)animation.getAnimatedValue();
				updateViewPosition(x,y-mTouchY);
			}
		});
		animation.setInterpolator(new DecelerateInterpolator());
		animation.start();
	}

	/**
	 * 渐变透明度
	 * @param startA
	 * @param endA
	 */
	private void alphaAnimator(int startA,int endA){
		ValueAnimator animation = ValueAnimator.ofInt(startA,endA);
		animation.setDuration(1000);
		animation.addUpdateListener(new AnimatorUpdateListener() {
			@Override
			public void onAnimationUpdate(ValueAnimator animation) {	
				int value = (int)animation.getAnimatedValue();
				setViewAlpha(value);
			}
		});
		animation.setInterpolator(new AccelerateInterpolator());
		animation.start();
	}

	/**
	 * 设置透明度
	 * @param alpha
	 */
	private void setViewAlpha(int alpha){
		getBackground().setAlpha(alpha);
		setImageAlpha(alpha);
	}


	/**
	 * 更新浮动窗口位置参数 
	 * @param x
	 * @param y
	 */
	private void updateViewPosition(float x,float y) { 
		windowManagerParams.x = (int) x; 
		windowManagerParams.y = (int) y; 
		windowManager.updateViewLayout(this, windowManagerParams); // 刷新显示 
	} 

	@Override 
	public void setOnClickListener(OnClickListener l) { 
		this.mClickListener = l; 
	} 

	/**
	 * 销毁控件
	 */
	public void destroy(){
		windowManager.removeView(this); 
	}
}

    
    
   
   

项目资源下载地址:http://download.csdn.net/detail/igaocx/9690182













  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Android仿Siri动效是指在Android系统上开发出一种类似于苹果Siri语音助手的动画效果。Siri苹果公司推出的一款智能语音助手,它可以通过语音指令来完成用户的需求,如发送短信、查找信息等。它以其独特的对话界面和流畅的动画效果而受到广大用户的喜爱。 要实现Android仿Siri动效,首先需要设计一个类似于Siri的对话界面,可以使用Android的布局和控件来完成。在布局中,可以加入文本框、图标等控件,通过这些控件来显示对话内容和用户的问题。 在动画效果方面,可以借鉴Siri中的一些动画特效,如文字弹出、波浪效果等。这些效果可以通过Android动画库来实现。在动画开始时,可以让文本一次性显示出来,或者逐字逐句地显示。然后,可以通过一些缩放、平移和渐变效果来让文本或图标呈现出波浪动画的效果。通过调整这些动画的参数和时长,可以使得整个动画看起来更加流畅、自然。 除了动画效果外,还可以为Android仿Siri动效添加声音效果,如音频提示或语音合成。这样,在用户与仿Siri对话时,可以出现仿真的语音对话效果,增强用户的体验。 总之,Android仿Siri动效可以通过设计类似的对话界面、实现一些特殊的动画效果和添加声音效果来实现。这样的效果可以为用户提供一种更加直观、有趣的交互方式,提高用户的使用体验。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值