Android jest dużym kombajnem, z którego możemy dużo wycisnąć. To nie tylko telefony, tv, ale też i normalny sprawny system operacyjny. Możemy z niego korzystać jak z każdego systemu zainstalowanego na komputerze. Prawie na każdym systemie mamy okna, które możemy przesuwać po ekranie. Android też to posiada, dlatego poniżej zobaczysz, w jaki sposób stworzyć pływające okna w Androidzie. Można to wykorzystać w powiadomieniach, takie zastosowanie możemy znaleźć w aplikacji Messenger od Facebooka jako dymki. Zaczynajmy!
Przygotowania
W przypadku wersji Androida API<=22 nie potrzebujemy żadnych uprawnień, natomiast w nowszym Androidzie musimy uzyskać uprawnienia, aby aplikacja mogła „rysować” widoki nad innymi aplikacjami. W pliku manifestu dodajemy:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
W kodzie aplikacji (na przykład w głównej aktywności) dodajemy coś takiego:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(this)) { checkPermission(); } else { initBtn(); } .... private void initBtn() { Button startFloatingWindow = findViewById(R.id.startFloatingWindow); startFloatingWindow.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { startService(new Intent(MainActivity.this, FloatWindowService.class)); } }); } @TargetApi(Build.VERSION_CODES.M) @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE) { if (resultCode == RESULT_OK) initBtn(); else { Toast.makeText(this,"Draw over other app permission not available.", Toast.LENGTH_SHORT).show(); } } } public void checkPermission() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (!Settings.canDrawOverlays(this)) { Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())); startActivityForResult(intent, ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE); } } }
Musisz także zarejestrować usługę w manifeście:
<service android:name=".FloatWindowService" />
Przygotuj serwis
Teraz musisz stworzyć klasę FloatWindowService, która będzie pracowała w tle. Rozszerz ją o klasę Service. Metoda onCreate() może wyglądać tak:
@Override public void onCreate() { super.onCreate(); windowManager = (WindowManager) getSystemService(WINDOW_SERVICE); int LAYOUT_FLAG; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) LAYOUT_FLAG = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; else LAYOUT_FLAG = WindowManager.LayoutParams.TYPE_PHONE; final WindowManager.LayoutParams params = new WindowManager.LayoutParams( WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, LAYOUT_FLAG, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT); params.x = 0; params.y = 0; params.gravity = Gravity.CENTER; floatingWindow = getXML(); windowManager.addView(floatingWindow, params); floatingWindow.setOnTouchListener( new View.OnTouchListener() { WindowManager.LayoutParams updatedParams = params; int x,y; float touchX,touchY; @Override public boolean onTouch(View view, MotionEvent motionEvent) { switch (motionEvent.getAction()){ case MotionEvent.ACTION_DOWN: //remember the initial position. x= updatedParams.x; y=updatedParams.y; //get the touch location touchX = motionEvent.getRawX(); touchY = motionEvent.getRawY(); break; case MotionEvent.ACTION_MOVE: //Calculate the X and Y coordinates of the view. updatedParams.x = (int)(x+(motionEvent.getRawX() - touchX)); updatedParams.y = (int)(y+(motionEvent.getRawY() - touchY)); //Update the layout with new X & Y coordinate windowManager.updateViewLayout(view,updatedParams); default:break; } return false; } }); }
W pierwszej kolejności tworzymy menadżer okna wraz z parametrami, który ma się pojawić. Następnie dodajemy widok do menadżera (zmienna floatingWindow).
Metoda setOnTouchListener() pozwala na przesuwanie elementu na ekranie. Za każdym razem, gdy użytkownik dotknie widoku, zarejestrujemy początkowe współrzędne X i Y, a kiedy użytkownik poruszy element, aplikacja obliczy nowe współrzędne X i Y i przeniesie widok w nowe miejsce.
Tworzenie widoku
Tworząc pływające okna w Androidzie, masz dwie opcję:
- Stworzyć za pomocą pliku xml jak każdy inny layout.
- Stworzyć programowo.
Poniżej przedstawiam dwie metody przykładowe. Za pomocą XML:
public View getXML() { View myview = LayoutInflater.from(this).inflate(R.layout.window, null); Button button = myview.findViewById(R.id.stopWindow); button.setOnClickListener(btnListener); return myview; }
lub programowo:
public View getLayout() { LinearLayout linearLayout = new LinearLayout(this); LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT); linearLayout.setLayoutParams(layoutParams); linearLayout.setBackgroundResource(R.color.transparent); linearLayout.setOrientation(LinearLayout.VERTICAL); TextView textView = new TextView(this); textView.setText("This is a floating window"); textView.setGravity(Gravity.CENTER_HORIZONTAL); LinearLayout.LayoutParams layoutParamsText = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); textView.setLayoutParams(layoutParamsText); linearLayout.addView(textView); Button button = new Button(this); button.setText("Stop floating window"); ViewGroup.LayoutParams btnparms = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); button.setLayoutParams(btnparms); button.setGravity(Gravity.CENTER_HORIZONTAL); button.setOnClickListener(btnListener); linearLayout.addView(button); return linearLayout; }
Nie zapomnij też o obsłudze przycisku, który zamknie okno i wyłączy usługę.
View.OnClickListener btnListener = new View.OnClickListener() { @Override public void onClick(View view) { windowManager.removeView(floatingWindow); stopSelf(); } };
Efekt:
Podsumowanie
To wszystkie kroki, które musisz wykonać, aby wyświetlić pływające okno w Androidzie. Powyższy przykład jest prosty i pokazuje kwadraz z guzikiem. Nic nie stoi, na przeszkodzi, aby widok zmienić na kółko, trójkąt czy inny wygląd 🙂 Teraz stwórz własny projekt. Efekt fajny, ale pamiętaj, że ma swoje ograniczenia. Musisz zapytać użytkownika o uprawnienia. Warto przed ustawieniem uprawnień wyjaśnić użytkownikowi czemu potrzebujesz takich uprawnień.