利用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); } }