利用WindowManager简单实现了显示歌词的效果~

通过程序对窗口服务有一定的了解,知识点大概为:

理解View及其子类的实现方法,程序中用到textview作为显示,作为拓展,我们知道textview继承自view类,view类能实现的onTouchEvent()和onDraw(Canvas canvas)方法textview也可以实现。WindowManager.LayoutParams 类的使用,如何将tv进行更新(对UI线程的理解),最后把textview显示到窗口中。

TextView的相关代码:

public class GeTextView extends TextView {
    private final String TAG = GeTextView.class.getSimpleName();
                                                                               
    public static WindowManager.LayoutParams params = new WindowManager.LayoutParams();
    private float sX,sY,x,y;
    public static int BAR = 25;
    private String str;
    private float f1 = 0.0f ,f2 = 0.01f;
    private Handler handler;
                                                                               
    WindowManager wm = (WindowManager) getContext().getApplicationContext().getSystemService(getContext().WINDOW_SERVICE);
                                                                               
    public GeTextView(Context context) {
        super(context);
        str = "再累也要开心D~~,学习ing~~";
        this.setBackgroundColor(Color.argb(90, 150, 150, 150));
    }
    public boolean onTouchEvent(MotionEvent event){
        /**注意getRawX和getX之间的区别*/
        x = event.getRawX();
        y = event.getRawY() - BAR;
        switch(event.getAction()){
        case MotionEvent.ACTION_DOWN:
            sX = event.getX();
            sY = event.getY();
            break;
        case MotionEvent.ACTION_MOVE:
            params.x = (int) (x - sX);
            params.y = (int) (y - sY);
            wm.updateViewLayout(this, params);
            break;
        case MotionEvent.ACTION_UP:
            params.x = (int) (x - sX);
            params.y = (int) (y - sY);
            wm.updateViewLayout(this, params);
            sX = sY = 0;
            break;
        }
        return true;
    }
                                                                               
    protected void onDraw(Canvas canvas){
        super.onDraw(canvas);
        f1 += 0.001f;
        f2 += 0.001f;
                                                                                   
        if(f2 > 1.0){
            f1 = 0.0f;
            f2 = 0.01f;
        }
        this.setText("");
        float len = this.getTextSize() * str.length();
        Shader shader = new LinearGradient(0, 0, len, 0,
                new int[] { Color.YELLOW, Color.GREEN },  new float[]{f1, f2},
                TileMode.CLAMP);
        Paint p = new Paint();
        p.setShader(shader);
        p.setTypeface(Typeface.DEFAULT_BOLD);
        canvas.drawText(str, 0, 12, p);
    }
                                                                               
    private Runnable update = new Runnable(){
        public void run(){
            /**刷新tv,放在UI线程的Runnable每隔5ms执行一次*/
            GeTextView.this.postInvalidate();
            handler.postDelayed(update, 5);
        }
    };
}

************

悬浮窗始终显示在最顶层

onTouchEvent方法下关于MotionEvent的3个action分别代表:手指落下,手指一动和手指离开屏幕的事件。onDraw方法设置Shader类来实现TextView的渐变,int[]数组定义参与渐变效果的颜色几个,float[]定义每个颜色处于渐变的相对位置。postDelayed()方法把传给它的指定Runnable在指定时间下执行。

主窗口:

public class GeciActivity extends Activity {
    private Button click;
    private GeTextView tv = null;
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        click =(Button) findViewById(R.id.click);
        click.setOnClickListener(new OnClickListener(){
            public void onClick(View v) {
                if(tv != null && tv.isShown()){
                    WindowManager wm = (WindowManager)getApplicationContext().getSystemService(GeciActivity.this.WINDOW_SERVICE);
                    wm.removeView(tv);
                }
                showWindow();
            }
        });
    }
        
    public void showWindow(){
        Rect rect = new Rect();
        /**获得显示(电量信息)等的窗口*/
        getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
        /**保证窗口在上面的装饰窗口之下*/
        GeTextView.BAR  =rect.top;
        WindowManager wm = (WindowManager)getApplicationContext().getSystemService(WINDOW_SERVICE);
        WindowManager.LayoutParams params = GeTextView.params;
            
        /**设置显示tv窗口的参数*/
        params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT | WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
        params.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL | LayoutParams.FLAG_NOT_FOCUSABLE;
            
        params.width = WindowManager.LayoutParams.FILL_PARENT;
        params.height = WindowManager.LayoutParams.WRAP_CONTENT;
        params.alpha = 80;
        params.gravity = Gravity.LEFT|Gravity.TOP;
            
        params.x = 0;
        params.y = 0;
            
        tv = new GeTextView(GeciActivity.this);
        /**在窗口加入tv*/
        wm.addView(tv, params);
    }
}