Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android開發--桌面浮動歌詞窗口

Android開發--桌面浮動歌詞窗口

編輯:關於Android編程

隨著Android手機的屏幕越來越大,Android浮動窗口的應用也越來越多。像經常會用到的,音樂播放器的桌面歌詞以及一些手機衛士軟件,像騰訊手機管家的小火箭清理內存,都應用到了浮動窗口的原理,今天拿來桌面歌詞做一個簡單的記錄,舉一反三即可實現類似的應用。效果圖如下:

\

一、浮動窗口的實餡喎?/kf/yidong/wp/" target="_blank" class="keylink">WPC9zdHJvbmc+PC9wPgo8cD4gICAgICAgIDEuytfPyM7Sw8fSqsnqx+vIqM/eo6zS1LHjztLDx7/J0tTKtc/WuKG2r7Swv9q1xM3P16c8L3A+CjxwPjwvcD4KPHByZSBjbGFzcz0="brush:java;"> 2.接下來,我們在service中的OnCreate方法顯示浮動窗口,在OnDestory方法中關閉浮動窗口,這樣我們的浮動窗口就可以與Service保持相同的生命周期。

3.顯示浮動窗口:首先通過getApplicationContext().getSystemService(WINDOW_SERVICE)方法我們可以獲得窗口管理類,接下來我們需要設置窗口的params,設置其類型為系統級,否則無法顯示;設置焦點,否則無法獲得觸摸事件;最後通過wm.addView(tv, params)方法將我們的View添加到窗口中。

4.窗口的拖拽:在這裡我們重新寫一個TextView來放置我們的歌詞,並在onTouchEvent中響應觸摸事件,獲得觸摸點的移動來計算觸摸點的移動,並重新設置窗口的位置,在這裡需要注意,MotionEvent中的RawX,RawY是相對屏幕左上角的坐標(包括狀態欄高度),而X,Y是相對於容器本身的坐標,即TextView左上角的坐標。這樣利用RawX-X既可以得到TextView左上角點的屏幕x坐標,RawY-Y-狀態欄高即可獲得TextView左上角點的屏幕y坐標。之後我們調用wm.updateViewLayout(this, params)進行更新。

二、渲染歌詞的實現

通過一個Shader shader = new LinearGradient(0, 0, len, 0, new int[] {Color.YELLOW, Color.RED }, new float[] { one, two },TileMode.CLAMP)可以進行歌詞的渲染,其中前四個參數表示從哪裡渲染到哪裡,第5個參數為渲染的兩種不同顏色, 第6個參數表示渲染的相對長度,范圍從0到1, 第7個參數表示模式。我們可以通過一個異步線程不斷更新one和two的值,並調用postInvalidate方法更新界面。


代碼實現:

MainActivity類:

package com.example.windowtest;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

import com.example.windowtest.service.TestService;

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		((Button) findViewById(R.id.button1))
				.setOnClickListener(new OnClickListener() {

					@Override
					public void onClick(View arg0) {
						// TODO Auto-generated method stub
						Intent serviceIntent = new Intent(MainActivity.this,
								TestService.class);
						startService(serviceIntent);
					}
				});
		((Button) findViewById(R.id.button2))
		.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View arg0) {
				// TODO Auto-generated method stub
				Intent serviceIntent = new Intent(MainActivity.this,
						TestService.class);
				stopService(serviceIntent);
			}
		});
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

}
WindowText類:實現TextView顯示歌詞
package com.example.windowtest.widget;

import java.lang.reflect.Field;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Shader;
import android.graphics.Shader.TileMode;
import android.util.Log;
import android.view.MotionEvent;
import android.view.WindowManager;
import android.widget.TextView;

public class WindowText extends TextView {

	private static final String TAG = WindowText.class.getSimpleName();

	public static WindowManager.LayoutParams params = new WindowManager.LayoutParams();
	private float startX;
	private float startY;
	private float one = 0.0f;
	private float two = 0.01f;

	private WindowManager wm;
	private String text;
	private int statusBarHeight;

	public WindowText(Context context) {
		super(context);
		// handler.post(update);
		wm = (WindowManager) getContext().getApplicationContext()
				.getSystemService(Context.WINDOW_SERVICE);
		updateTextThread.start();
		statusBarHeight = getStatusBarHeight();
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		// 觸摸點相對於屏幕左上角坐標
		float x = event.getRawX();
		float y = event.getRawY() - statusBarHeight;

		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			startX = event.getX();
			startY = event.getY();
			break;
		case MotionEvent.ACTION_MOVE:
			Log.w(TAG, "x::" + startX + ",y::" + startY);
			Log.w(TAG, "rawx::" + x + ",rawy::" + y);
		case MotionEvent.ACTION_UP:
			updatePosition(x - startX, y - startY);
			break;
		}
		return true;
	}

	@Override
	protected void onDraw(Canvas canvas) {
		// TODO Auto-generated method stub
		super.onDraw(canvas);
		float len = getTextSize() * text.length();
		/*
		 * 渲染歌詞,前四個參數表示從哪裡渲染到哪裡,第5個參數為渲染的兩種不同顏色, 第6個參數表示渲染的相對位置,范圍從0到1 第7個參數表示模式
		 */
		Shader shader = new LinearGradient(0, 0, len, 0, new int[] {
				Color.YELLOW, Color.RED }, new float[] { one, two },
				TileMode.CLAMP);
		Paint p = new Paint();
		p.setShader(shader);
		p.setTextSize(getTextSize());
		canvas.drawText(text, 0, getTextSize(), p);
	}

	// 通過一個異步線程來控制歌詞渲染的速度
	private Thread updateTextThread = new Thread() {

		@Override
		public void run() {
			// TODO Auto-generated method stub
			super.run();
			while (true) {
				one += 0.001f;
				two += 0.001f;
				if (two > 1.0) {
					one = 0.0f;
					two = 0.01f;
				}
				postInvalidate();
				try {
					Thread.sleep(10);
				} catch (Exception e) {
					// TODO: handle exception
				}
			}
		}

	};

	// 更新浮動窗口位置參數
	private void updatePosition(float x, float y) {
		// View的當前位置
		params.x = (int) x;
		params.y = (int) y;
		wm.updateViewLayout(this, params);
	}

	// 獲得狀態欄高度
	private int getStatusBarHeight() {
		Class c = null;
		Object obj = null;
		Field field = null;
		int x = 0;
		try {
			c = Class.forName("com.android.internal.R$dimen");
			obj = c.newInstance();
			field = c.getField("status_bar_height");
			x = Integer.parseInt(field.get(obj).toString());
			return getResources().getDimensionPixelSize(x);
		} catch (Exception e1) {
			e1.printStackTrace();
			return 75;
		}
	}

	public String getText() {
		return text;
	}

	public void setText(String text) {
		this.text = text;
	}

}
Service類:
package com.example.windowtest.service;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.view.Gravity;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;

import com.example.windowtest.widget.WindowText;

public class TestService extends Service {

	private WindowManager wm;
	private WindowText tv;

	public TestService() {
		// TODO Auto-generated constructor stub
	}

	@Override
	public void onCreate() {
		// TODO Auto-generated method stub
		super.onCreate();
		wm = (WindowManager) getApplicationContext().getSystemService(
				WINDOW_SERVICE);
		showWindow();
	}

	// 顯示浮動窗口
	private void showWindow() {
		WindowManager.LayoutParams params = WindowText.params;

		params.type = LayoutParams.TYPE_SYSTEM_ALERT
				| 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;
		// 以屏幕左上角為原點,設置x、y初始值,將懸浮窗口設置在屏幕中間的位置
		params.x = 0;
		params.y = wm.getDefaultDisplay().getHeight() / 2;
		tv = new WindowText(TestService.this);
		tv.setTextSize(20);
		tv.setText("難以忘記初次見你,一雙迷人的眼睛");
		wm.addView(tv, params);
	}

	// service退出時關閉浮動窗口
	@Override
	public void onDestroy() {
		// TODO Auto-generated method stub
		WindowManager wm = (WindowManager) getApplicationContext()
				.getSystemService(WINDOW_SERVICE);

		if (tv != null && tv.isShown()) {
			wm.removeView(tv);
		}
		super.onDestroy();
	}

	@Override
	public IBinder onBind(Intent arg0) {
		// TODO Auto-generated method stub
		return null;
	}

}





  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved