如何实现Android的圆形悬浮球
答案:2 悬赏:60 手机版
解决时间 2021-02-03 09:01
- 提问者网友:鐵馬踏冰河
- 2021-02-03 05:19
如何实现Android的圆形悬浮球
最佳答案
- 五星知识达人网友:举杯邀酒敬孤独
- 2021-02-03 06:46
一共涉及四个类
自定义的悬浮球:
Service类:由于要一直悬浮球要一直显示在屏幕上,所以要使用Service显示悬浮球。
ViewManager类:用于添加悬浮球和删除悬浮球
public class ViewManager
{
private static ViewManager viewManager;
private WindowManager windowManager;
private FloatBall floatBall;
private ViewManager() {}
public static ViewManager getViewManagerInstance()
{
if(viewManager == null)
viewManager = new ViewManager();
return viewManager;
}
public void show(final Context context)
{
windowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
floatBall = new FloatBall(context);
floatBall.setBackgroundColor(Color.parseColor("#ffdddddd"));
layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;
layoutParams.width = floatBall.width;
layoutParams.height = floatBall.height;
layoutParams.flags = 40;
layoutParams.format = PixelFormat.RGBA_8888 | PixelFormat.TRANSLUCENT;
//floatBall.setLayoutParams(layoutParams);
windowManager.addView(floatBall, layoutParams);
floatBall.setOnTouchListener(new View.OnTouchListener()
{
float startX;
float startY; // 原位置
@Override
public boolean onTouch(View v, MotionEvent event)
{
int action = event.getAction();
float x = event.getRawX();
float y = event.getRawY(); // 新位置
if(action == MotionEvent.ACTION_DOWN)
{
startX = x;
startY = y;
}
else if(action == MotionEvent.ACTION_MOVE)
{
x = event.getRawX();
y = event.getRawY();
layoutParams.x += (int)(x - startX);
layoutParams.y += (int)(y - startY);
windowManager.updateViewLayout(floatBall, layoutParams);
startX = x;
startY = y;
}
else if(action == MotionEvent.ACTION_UP)
{
startX = x;
startY = y;
}
return false;
}
});
floatBall.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
final View view = LayoutInflater.from(context).inflate(R.layout.streamvolume, null);
view.setBackgroundColor(Color.parseColor("#ffdddddd"));
WindowManager.LayoutParams layoutParams1 = new WindowManager.LayoutParams();
layoutParams1.width = 800;
layoutParams1.height = 950;
layoutParams1.type = WindowManager.LayoutParams.TYPE_PHONE;
layoutParams1.flags = 40;
windowManager.addView(view, layoutParams1);
final AudioManager am = (AudioManager)view.getContext().getSystemService(Context.AUDIO_SERVICE);
SeekBar sysVolume = (SeekBar)view.findViewById(R.id.sysVolume);
SeekBar callVolume = (SeekBar)view.findViewById(R.id.callVolume);
SeekBar ringVolume = (SeekBar)view.findViewById(R.id.ringVolume);
SeekBar musicVolume = (SeekBar)view.findViewById(R.id.musicVolume);
SeekBar notifyVolume = (SeekBar)view.findViewById(R.id.notifyVolume);
SeekBar alarmVolume = (SeekBar)view.findViewById(R.id.alarmVolume);
// 1 系统音量
sysVolume.setMax(am.getStreamMaxVolume(AudioManager.STREAM_SYSTEM));
sysVolume.setProgress(am.getStreamVolume(AudioManager.STREAM_SYSTEM));
sysVolume.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener()
{
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
{
am.setStreamVolume(AudioManager.STREAM_SYSTEM, progress, AudioManager.FLAG_PLAY_SOUND);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {}
});
// 2 通话音量
callVolume.setMax(am.getStreamMaxVolume(AudioManager.STREAM_VOICE_CALL));
callVolume.setProgress(am.getStreamVolume(AudioManager.STREAM_VOICE_CALL));
callVolume.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener()
{
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
{
am.setStreamVolume(AudioManager.STREAM_VOICE_CALL, progress, AudioManager.FLAG_PLAY_SOUND);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {}
});
// 3 铃声音量
ringVolume.setMax(am.getStreamMaxVolume(AudioManager.STREAM_RING));
ringVolume.setProgress(am.getStreamVolume(AudioManager.STREAM_RING));
ringVolume.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener()
{
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
{
am.setStreamVolume(AudioManager.STREAM_RING, progress, AudioManager.FLAG_PLAY_SOUND);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {}
});
// 4 媒体音量
musicVolume.setMax(am.getStreamMaxVolume(AudioManager.STREAM_MUSIC));
musicVolume.setProgress(am.getStreamVolume(AudioManager.STREAM_MUSIC));
musicVolume.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener()
{
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
{
am.setStreamVolume(AudioManager.STREAM_MUSIC, progress, AudioManager.FLAG_PLAY_SOUND);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {}
});
// 5 通知音量
notifyVolume.setMax(am.getStreamMaxVolume(AudioManager.STREAM_NOTIFICATION));
notifyVolume.setProgress(am.getStreamVolume(AudioManager.STREAM_NOTIFICATION));
notifyVolume.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener()
{
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
{
am.setStreamVolume(AudioManager.STREAM_NOTIFICATION, progress, AudioManager.FLAG_PLAY_SOUND);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {}
});
// 6 警报音量
alarmVolume.setMax(am.getStreamMaxVolume(AudioManager.STREAM_ALARM));
alarmVolume.setProgress(am.getStreamVolume(AudioManager.STREAM_ALARM));
alarmVolume.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener()
{
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
{
am.setStreamVolume(AudioManager.STREAM_ALARM, progress, AudioManager.FLAG_PLAY_SOUND);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {}
});
ImageView c = (ImageView)view.findViewById(R.id.close);
c.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
windowManager.removeView(view);
}
});
}
});
}
public void close()
{
windowManager.removeView(floatBall);
}
}
另外是一个MainAcitivity类,定义两个按钮,点击它们可以启动Service和关闭Servcie。
自定义的悬浮球:
Service类:由于要一直悬浮球要一直显示在屏幕上,所以要使用Service显示悬浮球。
ViewManager类:用于添加悬浮球和删除悬浮球
public class ViewManager
{
private static ViewManager viewManager;
private WindowManager windowManager;
private FloatBall floatBall;
private ViewManager() {}
public static ViewManager getViewManagerInstance()
{
if(viewManager == null)
viewManager = new ViewManager();
return viewManager;
}
public void show(final Context context)
{
windowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
floatBall = new FloatBall(context);
floatBall.setBackgroundColor(Color.parseColor("#ffdddddd"));
layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;
layoutParams.width = floatBall.width;
layoutParams.height = floatBall.height;
layoutParams.flags = 40;
layoutParams.format = PixelFormat.RGBA_8888 | PixelFormat.TRANSLUCENT;
//floatBall.setLayoutParams(layoutParams);
windowManager.addView(floatBall, layoutParams);
floatBall.setOnTouchListener(new View.OnTouchListener()
{
float startX;
float startY; // 原位置
@Override
public boolean onTouch(View v, MotionEvent event)
{
int action = event.getAction();
float x = event.getRawX();
float y = event.getRawY(); // 新位置
if(action == MotionEvent.ACTION_DOWN)
{
startX = x;
startY = y;
}
else if(action == MotionEvent.ACTION_MOVE)
{
x = event.getRawX();
y = event.getRawY();
layoutParams.x += (int)(x - startX);
layoutParams.y += (int)(y - startY);
windowManager.updateViewLayout(floatBall, layoutParams);
startX = x;
startY = y;
}
else if(action == MotionEvent.ACTION_UP)
{
startX = x;
startY = y;
}
return false;
}
});
floatBall.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
final View view = LayoutInflater.from(context).inflate(R.layout.streamvolume, null);
view.setBackgroundColor(Color.parseColor("#ffdddddd"));
WindowManager.LayoutParams layoutParams1 = new WindowManager.LayoutParams();
layoutParams1.width = 800;
layoutParams1.height = 950;
layoutParams1.type = WindowManager.LayoutParams.TYPE_PHONE;
layoutParams1.flags = 40;
windowManager.addView(view, layoutParams1);
final AudioManager am = (AudioManager)view.getContext().getSystemService(Context.AUDIO_SERVICE);
SeekBar sysVolume = (SeekBar)view.findViewById(R.id.sysVolume);
SeekBar callVolume = (SeekBar)view.findViewById(R.id.callVolume);
SeekBar ringVolume = (SeekBar)view.findViewById(R.id.ringVolume);
SeekBar musicVolume = (SeekBar)view.findViewById(R.id.musicVolume);
SeekBar notifyVolume = (SeekBar)view.findViewById(R.id.notifyVolume);
SeekBar alarmVolume = (SeekBar)view.findViewById(R.id.alarmVolume);
// 1 系统音量
sysVolume.setMax(am.getStreamMaxVolume(AudioManager.STREAM_SYSTEM));
sysVolume.setProgress(am.getStreamVolume(AudioManager.STREAM_SYSTEM));
sysVolume.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener()
{
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
{
am.setStreamVolume(AudioManager.STREAM_SYSTEM, progress, AudioManager.FLAG_PLAY_SOUND);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {}
});
// 2 通话音量
callVolume.setMax(am.getStreamMaxVolume(AudioManager.STREAM_VOICE_CALL));
callVolume.setProgress(am.getStreamVolume(AudioManager.STREAM_VOICE_CALL));
callVolume.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener()
{
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
{
am.setStreamVolume(AudioManager.STREAM_VOICE_CALL, progress, AudioManager.FLAG_PLAY_SOUND);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {}
});
// 3 铃声音量
ringVolume.setMax(am.getStreamMaxVolume(AudioManager.STREAM_RING));
ringVolume.setProgress(am.getStreamVolume(AudioManager.STREAM_RING));
ringVolume.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener()
{
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
{
am.setStreamVolume(AudioManager.STREAM_RING, progress, AudioManager.FLAG_PLAY_SOUND);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {}
});
// 4 媒体音量
musicVolume.setMax(am.getStreamMaxVolume(AudioManager.STREAM_MUSIC));
musicVolume.setProgress(am.getStreamVolume(AudioManager.STREAM_MUSIC));
musicVolume.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener()
{
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
{
am.setStreamVolume(AudioManager.STREAM_MUSIC, progress, AudioManager.FLAG_PLAY_SOUND);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {}
});
// 5 通知音量
notifyVolume.setMax(am.getStreamMaxVolume(AudioManager.STREAM_NOTIFICATION));
notifyVolume.setProgress(am.getStreamVolume(AudioManager.STREAM_NOTIFICATION));
notifyVolume.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener()
{
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
{
am.setStreamVolume(AudioManager.STREAM_NOTIFICATION, progress, AudioManager.FLAG_PLAY_SOUND);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {}
});
// 6 警报音量
alarmVolume.setMax(am.getStreamMaxVolume(AudioManager.STREAM_ALARM));
alarmVolume.setProgress(am.getStreamVolume(AudioManager.STREAM_ALARM));
alarmVolume.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener()
{
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
{
am.setStreamVolume(AudioManager.STREAM_ALARM, progress, AudioManager.FLAG_PLAY_SOUND);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {}
});
ImageView c = (ImageView)view.findViewById(R.id.close);
c.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
windowManager.removeView(view);
}
});
}
});
}
public void close()
{
windowManager.removeView(floatBall);
}
}
另外是一个MainAcitivity类,定义两个按钮,点击它们可以启动Service和关闭Servcie。
全部回答
- 1楼网友:傲气稳了全场
- 2021-02-03 07:38
想要监听来电首先需要要manifest中申明"android.permission.read_phone_state"权限
还需要注册来电监听,目前我的处理方式是接收开机广播,然后在接收到广播后注册来电监听。接收开机广播需要有“android.permission.receive_boot_completed”权限,manifest中申明如下
然后注册广播接收类
phonebootreceiver中注册监听来电,首先得获取系统服务“telephony_service”
telephonymanager telm = (telephonymanager)getsystemservice(context.telephony_service);
然后添加监听
telm.listen(new tellistener(context), phonestatelistener.listen_call_state);
tellistener是自己定义的电话状态监听类,继承自phonestatelistener,监听来电只需要实现oncallstatechanged(int state, string incomingnumber)方法。
咳咳...标题上说了弹出悬浮窗口,其实悬浮窗口就是在windowmanager中添加一个view,这个功能我也是在tellistener实现的。要想实现悬浮窗口,首先得有“android.permission.system_alert_window”的权限,在manifest中申明如下:
windowmanager需要通过context.getapplicationcontext().getsystemservice(context.window_service);
来获取。
先把tellistener源码放出来,再详解
public class tellistener extends phonestatelistener {
private context context;
private windowmanager wm;
private textview tv;
public tellistener(context context){
this.context = context;
}
@override
public void oncallstatechanged(int state, string incomingnumber) {
// todo auto-generated method stub
super.oncallstatechanged(state, incomingnumber);
if(state == telephonymanager.call_state_ringing){
wm = (windowmanager)context.getapplicationcontext().getsystemservice(context.window_service);
windowmanager.layoutparams params = new windowmanager.layoutparams();
params.type = windowmanager.layoutparams.type_system_overlay;
params.flags = windowmanager.layoutparams.flag_not_touch_modal | windowmanager.layoutparams.flag_not_focusable;
params.width = windowmanager.layoutparams.wrap_content;
params.height = windowmanager.layoutparams.wrap_content;
params.format = pixelformat.rgba_8888;
tv = new textview(context);
tv.settext("这是悬浮窗口,来电号码:" + incomingnumber);
wm.addview(tv, params);
}else if(state == telephonymanager.call_state_idle){
if(wm != null){
wm.removeview(tv);
}
}
}
}
state = telephonymanager.call_state_ringing表示有新的来电,state = telephonymanager.call_state_idle表示电话中断(可能理解不是很准确,电话挂断的时候state会和telephonymanager.call_state_idle相等)
定义窗口布局
windowmanager.layoutparams params = new windowmanager.layoutparams();
设置窗口类型在所有窗口之上
params.type = windowmanager.layoutparams.type_system_overlay;
别忘了
params.flags = windowmanager.layoutparams.flag_not_touch_modal | windowmanager.layoutparams.flag_not_focusable;
如果没有这句话的话,在生成悬浮窗口后,悬浮窗口后的界面上东西都不能点。这句话的目的是让悬浮窗口失去焦点。
背景透明
params.format = pixelformat.rgba_8888;
本例中悬浮窗口只是显示一个textview其内容为“这是悬浮窗口,来电号码:xxxxxx”,最后将textview添加到窗体中
wm.addview(tv, params);
在电话中断后将textview移除,否则会一直显示的...
wm.removeview(tv);
啦..本文就到这儿了...
“啥?要可移动的?”
要想可以拖动的话,那给textview添加setontouchlistener,实现ontouchlistener的ontouchlistener方法。
对了,别忘了将
params.type = windowmanager.layoutparams.type_system_overlay;
修改为
params.type = windowmanager.layoutparams.type_phone;
因为type_system_overlay的话是textview获取不到输入焦点,也就没法拖动了哈。
这个例子只是监听来电,如果想监听去电的话,需要写一个broadcast receiver用来监听拨打电话时的系统广播“android.intent.action.new_outgoing_call”,而且需要在manifest中配置“android.permission.process_outgoing_calls”权限。在broadcast receiver中可以通过intent.getstringextra(intent.extra_phone_number)来获取拨出去的电话号码。剩下的应该就简单了。
我要举报
如以上问答信息为低俗、色情、不良、暴力、侵权、涉及违法等信息,可以点下面链接进行举报!
大家都在看
推荐资讯