ユーザーが画面上をドラッグできるフローティングビューを作成しようとしていました。
アイデアは、サービスを起動して、画面上のビューを膨らませるというものです。
しかし、問題があり、イベントがそれ自体に属するのではなく、すべてのユーザー入力イベントを受け取ります。
これが私のコードです:manifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:Android="http://schemas.Android.com/apk/res/Android"
package="com.example.floatandroidpractice"
Android:versionCode="1"
Android:versionName="1.0" >
<uses-sdk
Android:minSdkVersion="8"
Android:targetSdkVersion="17" />
<uses-permission Android:name="Android.permission.SYSTEM_ALERT_WINDOW" />
<application
Android:allowBackup="true"
Android:icon="@drawable/ic_launcher"
Android:label="@string/app_name"
Android:theme="@style/AppTheme" >
<activity
Android:name="com.example.floatandroidpractice.MainActivity"
Android:label="@string/app_name" >
<intent-filter>
<action Android:name="Android.intent.action.MAIN" />
<category Android:name="Android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service Android:name="com.example.floatandroidpractice.WalkingIconService" />
</application>
</manifest>
ドラッグできるフローティングビュー:
package com.example.floatandroidpractice;
import Android.content.Context;
import Android.graphics.Bitmap;
import Android.graphics.BitmapFactory;
import Android.graphics.Canvas;
import Android.graphics.Color;
import Android.graphics.Paint;
import Android.view.MotionEvent;
import Android.view.View;
public class littleIconView extends View {
private float viewX;
private float viewY;
private Paint mPaint;
private Bitmap androidIcon;
public littleIconView(Context context) {
super(context);
mPaint = new Paint();
mPaint.setColor(Color.BLACK);
androidIcon = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
}
@Override
public void onDraw(Canvas cvs) {
cvs.drawBitmap(androidIcon, viewX - androidIcon.getWidth() / 2, viewY - androidIcon.getHeight()
/ 2, mPaint);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
boolean touchedX = Math.abs(viewX - event.getX()) > androidIcon.getWidth();
boolean touchedY = Math.abs(viewY - event.getY()) > androidIcon.getHeight();
boolean isValidTouch = !touchedX && !touchedY;
if (isValidTouch) {
if (event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_MOVE
|| event.getAction() == MotionEvent.ACTION_UP) {
viewX = event.getX();
viewY = event.getY();
}
invalidate();
return true;
}
else
return false;
}
}
そしてサービス:
package com.example.floatandroidpractice;
import Android.app.Service;
import Android.content.Intent;
import Android.graphics.PixelFormat;
import Android.os.IBinder;
import Android.view.WindowManager;
import Android.view.WindowManager.LayoutParams;
public class WalkingIconService extends Service {
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
littleIconView a = new littleIconView(getApplicationContext());
LayoutParams mLayoutParams = new WindowManager.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 0, 0, PixelFormat.TRANSPARENT);
WindowManager mWindowManager = (WindowManager) this.getSystemService(WINDOW_SERVICE);
mLayoutParams.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL | LayoutParams.FLAG_NOT_FOCUSABLE
| LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH |
LayoutParams.FLAG_LAYOUT_INSET_DECOR | LayoutParams.FLAG_LAYOUT_IN_SCREEN;
mWindowManager.addView(a, mLayoutParams);
return super.onStartCommand(intent, flags, startId);
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
完全なプロジェクト: https://github.com/shanwu/shanwu_coding_base/tree/xxx/floatAndroidPractice
キャンバスに画像を描く方法を試しましたが、どこにも行きませんでした。例: EatHeatのgithub 、私が学んだところ。たぶん、これで正しい方向に進むことができるかもしれませんが、そうではないかもしれませんが、私にとってはうまくいきました。
WalkingIconService.Java
package ...
//imports
public class WalkingIconService extends Service {
private WindowManager mWindowManager;
private ImageView image;
public void onCreate() {
super.onCreate();
image = new ImageView(this);
image.setImageResource(R.drawable.ic_launcher);
mWindowManager = (WindowManager)getSystemService(WINDOW_SERVICE);
final LayoutParams paramsF = new WindowManager.LayoutParams(
LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT,
LayoutParams.TYPE_PHONE,
LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
paramsF.gravity = Gravity.TOP | Gravity.LEFT;
paramsF.x=0;
paramsF.y=100;
mWindowManager.addView(image, paramsF);
try{
image.setOnTouchListener(new View.OnTouchListener() {
WindowManager.LayoutParams paramsT = paramsF;
private int initialX;
private int initialY;
private float initialTouchX;
private float initialTouchY;
@Override
public boolean onTouch(View v, MotionEvent event) {
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
initialX = paramsF.x;
initialY = paramsF.y;
initialTouchX = event.getRawX();
initialTouchY = event.getRawY();
break;
case MotionEvent.ACTION_UP:
break;
case MotionEvent.ACTION_MOVE:
paramsF.x = initialX + (int) (event.getRawX() - initialTouchX);
paramsF.y = initialY + (int) (event.getRawY() - initialTouchY);
mWindowManager.updateViewLayout(v, paramsF);
break;
}
return false;
}
});
} catch (Exception e){
e.printStackTrace();
}
}
@Overrride
public void onDestroy(){
super.onDestory();
}
}
MainActivity.Java
package ...
//imports
public class MainActivity extends Activity {
@Override
public void onCreate(icicle) {
super.onCreate(icicle);
setcontentView(R.layout.activity_main);
Button b = (Button)findViewById(R.id.tv);
b.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//toast
startService(new Intent(MainActivity.this, WalkingIconService.class));
}
});
//stopService (from my original code)
Button stop = (Button)findViewById.(R.id.btnStop);
stop.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
stopService(new Intent(MainActivity.this, WalkingIconService.class));
}
});
}
}
aPI 23以降から、サービスを開始する前に、Settings.ACTION_MANAGE_OVERLAY_PERMISSION権限を確認します。
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!Settings.canDrawOverlays(ConversationsActivityWithSpam.this)) {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, 16);
return false;
}
}
デフォルトでは、WRAP_CONTENTを使用してレイアウトすると、Viewは使用可能なスペース全体を占有します。 WindowManager.LayoutParamsでビューサイズを明示的に指定するか、View.onMeasureをオーバーライドするか、(理想的には)ViewではなくImageViewを拡張する必要があります。