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