Android Studio Messenger Chat Baloncuğu Gibi Floating Widget Oluşturma

Telefon üzerinde bir uygulamadan çıktıktan sonra başka uygulamalara geçince o uygulamanın kapanmayıp diğer uygulamanın üstünde gözükmesini ve bir takım işlemleri diğer uygulamalarda gezinirken yapmak isteyebiliriz işte bu noktada kullanmamız gereken Floating Widgets yapısı olacaktır. Bu makalemizde bu Widget’ı nasıl yapabileceğimizi anlatmaya çalışacağım.
Yapılması gerenler:
1-Buraya tıklayarak uygulamada kullacağımız resimleri indirip drawable klasörünün altına ekleyelim.
2-AndroidManifest.xml dosyamıza SYSTEM_ALERT_WINDOW iznini ekleyelim.
1 |
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/> |
Artık uygulamamızı yazmaya başlayabiliriz. activity_main.xml dosyamıza bir tane buton sürükleyip bırakıyoruz.
activity_main.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.esatgozcu.floatingwidgetkullanimi.MainActivity"> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent"> <Button android:id="@+id/olustur" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" android:layout_marginTop="216dp" android:background="@android:color/holo_red_dark" android:paddingLeft="10dp" android:paddingRight="10dp" android:text="FloatingWidget Oluştur" android:textColor="@android:color/white" android:textSize="24sp" android:textStyle="bold" /> </RelativeLayout> </android.support.constraint.ConstraintLayout> |
MainActivity.java klasörümüzde gerekli izinlerin kontrolünü yapıyoruz eğer izin verilmişse Widgetimizi oluşturuyoruz.
MainActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
package com.example.esatgozcu.floatingwidgetkullanimi; import android.content.Intent; import android.net.Uri; import android.os.Build; import android.provider.Settings; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Toast; public class MainActivity extends AppCompatActivity { private static final int CODE_DRAW_OVER_OTHER_APP_PERMISSION = 2084; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //Bir uygulamanın telefonunuzda diğer uygulamaların üzerinde görüntülenmesine izin vermemiz gerekiyor //ACTION_MANAGE_OVERLAY_PERMISSION ve CODE_DRAW_OVER_OTHER_APP_PERMISSION izinleri uygulamaya //başlamadan önce almamız gerekli o yüzden kontolünü yapıyoruz. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(this)) { //Eğer izin verilmemiş ise izin verilmesini sağlıyoruz Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())); startActivityForResult(intent, CODE_DRAW_OVER_OTHER_APP_PERMISSION); } else { //Eğer izinler verilmiş ise servisi başlatıyoruz initializeView(); } } private void initializeView() { findViewById(R.id.olustur).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { startService(new Intent(MainActivity.this, FloatingViewService.class)); finish(); } }); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == CODE_DRAW_OVER_OTHER_APP_PERMISSION) { //İzinin verilip verilmediği kontrol ediliyor if (resultCode == RESULT_OK) { //Verildiyse servis başlatılıyor initializeView(); } else { //İzin verilmediyse mesaj bastırıyoruz Toast.makeText(this, "Uygulamayı kullanabilmek için lütfen izin veriniz", Toast.LENGTH_SHORT).show(); finish(); } } else { super.onActivityResult(requestCode, resultCode, data); } } } |
Şimdi FloatWidget butonumuzun tasarımınızı yapalım.
layout_floating_widget.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" xmlns:tools="http://schemas.android.com/tools"> <RelativeLayout android:id="@+id/root_container" tools:ignore="UselessParent" android:layout_width="wrap_content" android:layout_height="wrap_content"> <!--View while view is collapsed--> <RelativeLayout android:id="@+id/collapse_view" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" android:visibility="visible"> <!--Icon of floating widget --> <ImageView android:id="@+id/collapsed_iv" tools:ignore="ContentDescription" android:layout_width="60dp" android:layout_height="60dp" android:layout_marginTop="8dp" android:src="@drawable/music_player" /> <!--Close button--> <ImageView android:id="@+id/close_btn" tools:ignore="ContentDescription" android:layout_width="20dp" android:layout_height="20dp" android:layout_marginLeft="40dp" android:src="@drawable/close" /> </RelativeLayout> <!--View while view is expanded--> <LinearLayout android:id="@+id/expanded_container" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@android:color/white" android:orientation="horizontal" android:padding="8dp" android:visibility="gone"> <!--Album image for the song currently playing.--> <ImageView android:layout_width="80dp" android:layout_height="80dp" android:src="@drawable/music_player" tools:ignore="ContentDescription" /> <!--Previous button--> <ImageView android:id="@+id/prev_btn" android:layout_width="30dp" android:layout_height="30dp" android:layout_gravity="center_vertical" android:layout_marginLeft="20dp" android:src="@drawable/previous" tools:ignore="ContentDescription" /> <!--Play button--> <ImageView android:id="@+id/play_btn" android:layout_width="50dp" android:layout_height="50dp" android:layout_gravity="center_vertical" android:layout_marginLeft="10dp" android:src="@drawable/play" tools:ignore="ContentDescription" /> <!--Next button--> <ImageView android:id="@+id/next_btn" android:layout_width="30dp" android:layout_height="30dp" android:layout_gravity="center_vertical" android:layout_marginLeft="10dp" android:src="@drawable/next" tools:ignore="ContentDescription" /> <RelativeLayout android:layout_width="wrap_content" android:layout_height="match_parent" android:orientation="vertical"> <ImageView android:id="@+id/close_button" android:layout_width="20dp" android:layout_height="20dp" android:src="@drawable/close" /> <ImageView android:id="@+id/open_button" android:layout_width="20dp" android:layout_height="20dp" android:layout_alignParentBottom="true" android:src="@drawable/open" /> </RelativeLayout> </LinearLayout> </RelativeLayout> </FrameLayout> |
FloatingWidget butonumuzun gerekli fonksiyonlarını tanımlıyoruz.
FloatingViewService.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
package com.example.esatgozcu.floatingwidgetkullanimi; import android.app.Service; import android.content.Intent; import android.graphics.PixelFormat; import android.os.IBinder; import android.view.Gravity; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.WindowManager; import android.widget.ImageView; import android.widget.Toast; public class FloatingViewService extends Service{ private WindowManager mWindowManager; private View mFloatingView; public FloatingViewService() { } @Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate() { super.onCreate(); mFloatingView = LayoutInflater.from(this).inflate(R.layout.layout_floating_widget, null); //LayoutParams layoutların özelliklerini (en,boy,yazının konumu vb.) kod üzerinde değişiklik yapma imkanı sağlar //Ekrana, view elemetini eklemek için gerekli ayarları yapıyoruz final WindowManager.LayoutParams params = new WindowManager.LayoutParams( WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.TYPE_PHONE, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT); //Widget başlangıçta nerede gözükmesini istiyorsak ayarını yapıyoruz //Widget sol üst köşede başlayacak params.gravity = Gravity.TOP | Gravity.LEFT; params.x = 0; params.y = 100; //Ekrana, layout icinde barınan view elementini ekliyoruz. mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE); mWindowManager.addView(mFloatingView, params); final View collapsedView = mFloatingView.findViewById(R.id.collapse_view); final View expandedView = mFloatingView.findViewById(R.id.expanded_container); //Kapatma butonunu tanımlıyoruz ImageView closeButtonCollapsed = (ImageView) mFloatingView.findViewById(R.id.close_btn); //İşlevini tanımlıyoruz closeButtonCollapsed.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { stopSelf(); } }); //Music player daki play butonunu tanımlıyoruz ImageView playButton = (ImageView) mFloatingView.findViewById(R.id.play_btn); //İşlevini tanımlıyoruz playButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(FloatingViewService.this, "Playing the song.", Toast.LENGTH_LONG).show(); } }); //Music player daki next butonunu tanımlıyoruz ImageView nextButton = (ImageView) mFloatingView.findViewById(R.id.next_btn); //İşlevini tanımlıyoruz nextButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(FloatingViewService.this, "Playing next song.", Toast.LENGTH_LONG).show(); } }); //Music player daki previous butonunu tanımlıyoruz ImageView prevButton = (ImageView) mFloatingView.findViewById(R.id.prev_btn); //İşlevini tanımlıyoruz prevButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(FloatingViewService.this, "Playing previous song.", Toast.LENGTH_LONG).show(); } }); //Music player daki kapatma butonunu tanımlıyoruz ImageView closeButton = (ImageView) mFloatingView.findViewById(R.id.close_button); //İşlevini tanımlıyoruz closeButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //Kapatma butonuna tıklandığında view elemntlerinin görünürlüğünü değiştiriyoruz collapsedView.setVisibility(View.VISIBLE); expandedView.setVisibility(View.GONE); } }); //Uygulamanın anasayfasına geri dönmek için yapılan Music player üstünde open butonunu tanımlıyoruz ImageView openButton = (ImageView) mFloatingView.findViewById(R.id.open_button); //İşlevinin tanımlıyoruz openButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent = new Intent(FloatingViewService.this, MainActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); stopSelf(); } }); //Kullanıcı Floatwidget butonu sürükleyim istediği yerde bırakacağı zaman yerinin değişmesini sağlıyoruz mFloatingView.findViewById(R.id.root_container).setOnTouchListener(new View.OnTouchListener() { private int initialX; private int initialY; private float initialTouchX; private float initialTouchY; //Bu method yerinin değişmesini sağlıyor //Eğer methodu anlamakta sıkıntı çekiyorsanız ezberlemek zoruda değilsiniz //Kopyala yapıştır ile uygulamanızda kullanabilirsiniz @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: initialX = params.x; initialY = params.y; initialTouchX = event.getRawX(); initialTouchY = event.getRawY(); return true; case MotionEvent.ACTION_UP: int Xdiff = (int) (event.getRawX() - initialTouchX); int Ydiff = (int) (event.getRawY() - initialTouchY); if (Xdiff < 10 && Ydiff < 10) { if (isViewCollapsed()) { collapsedView.setVisibility(View.GONE); expandedView.setVisibility(View.VISIBLE); } } return true; case MotionEvent.ACTION_MOVE: params.x = initialX + (int) (event.getRawX() - initialTouchX); params.y = initialY + (int) (event.getRawY() - initialTouchY); //Layout üzerinde değişen x ve y koordinatlarını güncelliyoruz mWindowManager.updateViewLayout(mFloatingView, params); return true; } return false; } }); } private boolean isViewCollapsed() { return mFloatingView == null || mFloatingView.findViewById(R.id.collapse_view).getVisibility() == View.VISIBLE; } @Override public void onDestroy() { super.onDestroy(); if (mFloatingView != null) mWindowManager.removeView(mFloatingView); } } |
Son olarak AndroidManifest.xml dosyamıza FloatingViewService.java sınıfının service tagını ekliyoruz.
1 2 3 4 |
<service android:name="com.example.esatgozcu.floatingwidgetkullanimi.FloatingViewService" android:enabled="true" android:exported="false"/> |
AndroidManifest.xml dosyamızın son görüntüsü şu şekilde olması gerekiyor.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.esatgozcu.floatingwidgetkullanimi"> <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/> <application android:allowBackup="true" android:icon="@drawable/music_player" android:label="@string/app_name" android:roundIcon="@drawable/music_player" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <service android:name="com.example.esatgozcu.floatingwidgetkullanimi.FloatingViewService" android:enabled="true" android:exported="false"/> </application> </manifest> |
Böylelikle FloatingWidget baloncuğunu nasıl oluşturabileceğimizi anlattım. Artık sizde kendi uygulamalarınıza uyarlayarak uygulamanızı zenginleştirebilirsiniz.
Kaynakça : Kaynak1
Projenin kodlarını buraya tıklayarak indirebilirsiniz.