編輯:關於Android編程
隨著Android手機的屏幕越來越大,Android浮動窗口的應用也越來越多。像經常會用到的,音樂播放器的桌面歌詞以及一些手機衛士軟件,像騰訊手機管家的小火箭清理內存,都應用到了浮動窗口的原理,今天拿來桌面歌詞做一個簡單的記錄,舉一反三即可實現類似的應用。效果圖如下:
一、浮動窗口的實餡喎?/kf/yidong/wp/" target="_blank" class="keylink">WPC9zdHJvbmc+PC9wPgo8cD4gICAgICAgIDEuytfPyM7Sw8fSqsnqx+vIqM/eo6zS1LHjztLDx7/J0tTKtc/WuKG2r7Swv9q1xM3P16c8L3A+CjxwPjwvcD4KPHByZSBjbGFzcz0="brush:java;"> 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;
}
}
了解了基本的自定義view基礎後,現在我們就來實踐下自定義view,也是看到我華為手機上自帶的天氣預報軟件後,想著模仿做一個,於是,我自己嘗試了下,雖然不算太像,但是還算
監聽器在Java中非常常用,在自定義控件時可能根據自己的需要去監聽一些數據的改變,這時就需要我們自己去寫監聽器,Java中的監聽器實際上就是C++中的回調
本文實例講述了Android編程實現仿QQ發表說說,上傳照片及彈出框效果。分享給大家供大家參考,具體如下:代碼很簡單,主要就是幾個動畫而已,圖標什麼的就隨便找了幾個,效果
運行效果C#實現using Android.App;using Android.OS;using Android.Widget;namespace ImageDemo{