Estou tentando criar um botão sempre op-top / imagem clicável que fica no topo de todas as janelas o tempo todo.
A prova de conceito é
- aqui - Barra de tarefas inteligente (no AppBrain)
- e aqui SWKey estilo V1.4.0 da barra lateral - salvador de botões (em xda-developers)
Fui bem-sucedido e tenho um serviço em execução agora. O serviço exibe algum texto no canto superior esquerdo da tela o tempo todo, enquanto o usuário pode interagir livremente com o restante dos aplicativos da maneira normal.
O que estou fazendo é subclasse ViewGroup
e adicione-o ao gerenciador de janelas raiz com sinalizador TYPE_SYSTEM_OVERLAY
. Agora, quero adicionar um botão / imagem clicável no lugar deste texto que possa receber eventos de toque em si mesmo. Tentei substituir "onTouchEvent" no todo, ViewGroup
mas ele não recebe nenhum evento.
Como posso receber eventos apenas em certas partes do meu grupo de visualizações sempre no topo? Por favor, sugira.
public class HUD extends Service {
HUDView mView;
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
Toast.makeText(getBaseContext(),"onCreate", Toast.LENGTH_LONG).show();
mView = new HUDView(this);
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
0,
// WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
// | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.RIGHT | Gravity.TOP;
params.setTitle("Load Average");
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
wm.addView(mView, params);
}
@Override
public void onDestroy() {
super.onDestroy();
Toast.makeText(getBaseContext(),"onDestroy", Toast.LENGTH_LONG).show();
if(mView != null)
{
((WindowManager) getSystemService(WINDOW_SERVICE)).removeView(mView);
mView = null;
}
}
}
class HUDView extends ViewGroup {
private Paint mLoadPaint;
public HUDView(Context context) {
super(context);
Toast.makeText(getContext(),"HUDView", Toast.LENGTH_LONG).show();
mLoadPaint = new Paint();
mLoadPaint.setAntiAlias(true);
mLoadPaint.setTextSize(10);
mLoadPaint.setARGB(255, 255, 0, 0);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawText("Hello World", 5, 15, mLoadPaint);
}
@Override
protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int arg4) {
}
@Override
public boolean onTouchEvent(MotionEvent event) {
//return super.onTouchEvent(event);
Toast.makeText(getContext(),"onTouchEvent", Toast.LENGTH_LONG).show();
return true;
}
}
onDraw()
esteja sendo chamado. EmdispatchDraw()
vez disso, não deve ser substituído? Consulte groups.google.com/forum/?fromgroups#!topic/android-developers/…Respostas:
Esta pode ser uma solução estúpida. Mas funciona. Se você pode melhorar, por favor me avise.
Ao criar o seu serviço: usei a
WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
flag. Esta é a única alteração no serviço.Agora, você começará a receber todos os eventos de clique. Portanto, você precisa corrigir no seu manipulador de eventos.
No seu evento de toque no ViewGroup
Você também pode precisar adicionar esta permissão ao seu manifesto:
fonte
Seguindo a resposta de @Sam Lu, o Indeed 4.x impede que certos tipos ouçam eventos de toque externos, mas alguns tipos, como
TYPE_SYSTEM_ALERT
, ainda fazem o trabalho.Exemplo
Permissões
fonte
Começando com Android 4.x, equipe do Android corrigiu um problema de segurança em potencial, adicionando uma nova função
adjustWindowParamsLw()
na qual ele irá adicionarFLAG_NOT_FOCUSABLE
,FLAG_NOT_TOUCHABLE
e removerFLAG_WATCH_OUTSIDE_TOUCH
bandeiras paraTYPE_SYSTEM_OVERLAY
janelas.Ou seja, uma
TYPE_SYSTEM_OVERLAY
janela não receberá nenhum evento de toque na plataforma ICS e, é claro, usarTYPE_SYSTEM_OVERLAY
não é uma solução viável para o ICS e dispositivos futuros.fonte
Sou um dos desenvolvedores do Tooleap SDK . Também fornecemos uma maneira de os desenvolvedores exibirem sempre nas janelas e botões superiores e lidamos com uma situação semelhante.
Um problema que as respostas aqui não abordaram é o dos "Botões protegidos" do Android.
Os botões protegidos têm a
filterTouchesWhenObscured
propriedade, o que significa que eles não podem ser interagidos, se colocados sob uma janela, mesmo que essa janela não receba nenhum toque. Citando a documentação do Android:Um exemplo desse botão é o botão de instalação quando você tenta instalar aplicativos de terceiros. Qualquer aplicativo pode exibir esse botão se adicionar ao layout da visualização a seguinte linha:
Se você exibir uma janela sempre na parte superior sobre um "Botão protegido", todas as partes protegidas do botão cobertas por uma sobreposição não terão nenhum toque, mesmo que essa sobreposição não seja clicável. Portanto, se você planeja exibir essa janela, deve fornecer uma maneira de o usuário movê-la ou descartá-la. E se uma parte da sua sobreposição for transparente, leve em consideração que o usuário pode ficar confuso por que um determinado botão no aplicativo subjacente não está funcionando para ele de repente.
fonte
TRABALHANDO SEMPRE NO BOTÃO SUPERIOR DA IMAGEM
primeiro de tudo desculpa pelo meu ingles
edito seus códigos e faço com que o botão da imagem de trabalho que ouça seu evento de toque não dê controle de toque a seus elementos de segundo plano.
também dá ouvintes de toque para fora de outros elementos
os alinhamentos dos botões estão na parte inferior e esquerda
você pode alterar alterações, mas precisa alterar cordinats no evento touch no elemento if
fonte
Na verdade, você pode tentar o WindowManager.LayoutParams.TYPE_SYSTEM_ERROR em vez de TYPE_SYSTEM_OVERLAY. Pode parecer um hack, mas permite exibir a visualização em cima de tudo e ainda receber eventos de toque.
fonte
TYPE_SYSTEM_OVERLAY Essa constante foi descontinuada desde o nível 26 da API. Use TYPE_APPLICATION_OVERLAY. ou ** para usuários abaixo e acima do android 8
fonte
Tente isso. Funciona bem no ICS. Se você deseja interromper o serviço, basta clicar na notificação gerada na barra de status.
ATUALIZAR
Amostra aqui
Para criar uma exibição de sobreposição, ao configurar o LayoutParams, NÃO defina o tipo como TYPE_SYSTEM_OVERLAY.
fonte
Aqui está uma solução simples: tudo o que você precisa é aumentar o layout XML da mesma forma que faz nos adaptadores de lista, basta criar o layout XML para aumentá-lo. Aqui está o código que você precisa.
fonte
Encontrei uma biblioteca que faz exatamente isso: https://github.com/recruit-lifestyle/FloatingView
Há um projeto de amostra na pasta raiz. Eu o executei e funciona conforme necessário. O fundo é clicável - mesmo que seja outro aplicativo.
fonte
Ele usa a permissão "android.permission.SYSTEM_ALERT_WINDOW" tutorial completo neste link: http://androidsrc.net/facebook-chat-like-floating-chat-heads/
fonte
Bem, tente meu código, pelo menos ele fornece uma string como sobreposição, você pode muito bem substituí-lo por um botão ou uma imagem. Você não vai acreditar que este é o meu primeiro aplicativo para Android LOL. De qualquer forma, se você tem mais experiência com aplicativos Android do que eu, tente
fonte
Se alguém ainda estiver lendo este tópico e não conseguir fazê-lo funcionar, lamento informar que essa maneira de interceptar evento de movimento é considerada um bug e correção no android> = 4.2.
O evento de movimento que você interceptou, embora tenha ação como ACTION_OUTSIDE, retorne 0 em getX e getY. Isso significa que você não pode ver toda a posição do movimento na tela, nem fazer nada. Eu sei que o documento disse que ele receberá x e y, mas a verdade é que NÃO VAI. Parece que isso é para bloquear o key logger.
Se alguém tiver uma solução alternativa, deixe seu comentário.
ref: Por que ACTION_OUTSIDE retorna 0 todas as vezes no KitKat 4.4.2?
https://code.google.com/p/android/issues/detail?id=72746
fonte
usando o serviço, você pode conseguir isso:
fonte
A resposta de @Sarwar Erfan não funciona mais, pois o Android não permite adicionar visualização com WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY à janela para ser tocável mais, nem mesmo com WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH.
Encontrei solução para este problema. Você pode conferir na seguinte pergunta
Ao adicionar a exibição à janela com WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY, ele não está recebendo o evento de toque
fonte
Esta é uma pergunta antiga, mas recentemente o Android tem suporte para Bubbles. Em breve, o Bubbles será lançado, mas atualmente os desenvolvedores podem começar a usá-los. Eles foram projetados para serem uma alternativa ao uso
SYSTEM_ALERT_WINDOW
. Aplicativos como (Facebook Messenger e MusiXMatch usam o mesmo conceito).As bolhas são criadas por meio da API de notificação, você envia sua notificação normalmente. Se você quiser que borbulhe, precisará anexar alguns dados extras. Para obter mais informações sobre o Bubbles, acesse o Guia oficial do desenvolvedor do Android sobre Bubbles .
fonte