install android studio

Floating Widgets in Android Studio

Floating Widgets:

Floating widgets are the views that float over the screen. This view will remain floating on the screen no matter whichever screen you are in. They are very convenient for multitasking as a user can work on other application and control your application for the same time. That means if you are in the calculator application and a widget from the music player is floating over the screen, you can control your music at the same time. Pretty cool!

In this tutorial, we are going to learn how to create simple floating widget and allow the user to drag them across the screen. So that user can adjust the position of the floating widget on the screen. We are going to develop a floating view that is having buttons to control the music. (To keep this article focused around floating widget, we will not look into how to control music)

implementation:

1. permissions:

uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

2.activity_main.xml:


?xml version="1.0" encoding="utf-8"?>
FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">
 
    
    RelativeLayout
        android:id="@+id/root_container"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        tools:ignore="UselessParent">
 
        
        RelativeLayout
            android:id="@+id/collapse_view"
            android:layout_width="wrap_content"
            android:visibility="visible"
            android:layout_height="wrap_content"
            android:orientation="vertical">
 
            
            ImageView
                android:id="@+id/collapsed_iv"
                android:layout_width="60dp"
                android:layout_height="60dp"
                android:layout_marginTop="8dp"
                android:src="@drawable/ic_android_circle"
                tools:ignore="ContentDescription"/>
 
            
            ImageView
                android:id="@+id/close_btn"
                android:layout_width="20dp"
                android:layout_height="20dp"
                android:layout_marginLeft="40dp"
                android:src="@drawable/ic_close"
                tools:ignore="ContentDescription"/>
        /RelativeLayout>
 
        
        LinearLayout
            android:id="@+id/expanded_container"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="#F8BBD0"
            android:visibility="gone"
            android:orientation="horizontal"
            android:padding="8dp">
 
            
            ImageView
                android:layout_width="80dp"
                android:layout_height="80dp"
                android:src="@drawable/music_player"
                tools:ignore="ContentDescription"/>
 
            
            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="@mipmap/ic_previous"
                tools:ignore="ContentDescription"/>
 
            
            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="@mipmap/ic_play"
                tools:ignore="ContentDescription"/>
 
            
            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="@mipmap/ic_play_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/ic_close"/>
 
                ImageView
                    android:id="@+id/open_button"
                    android:layout_width="20dp"
                    android:layout_height="20dp"
                    android:layout_alignParentBottom="true"
                    android:src="@drawable/ic_open"/>
            /RelativeLayout>
        /LinearLayout>
    /RelativeLayout>
/FrameLayout>

3. FloatingViewService.java:


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();
       //Inflate the floating view layout we created
       mFloatingView = LayoutInflater.from(this).inflate(R.layout.layout_floating_widget, null);
 
       //Add the view to the window.
       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);
 
       //Specify the view position
       params.gravity = Gravity.TOP | Gravity.LEFT;        //Initially view will be added to top-left corner
       params.x = 0;
       params.y = 100;
 
       //Add the view to the window
       mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
       mWindowManager.addView(mFloatingView, params);
 
       //The root element of the collapsed view layout
       final View collapsedView = mFloatingView.findViewById(R.id.collapse_view);
       //The root element of the expanded view layout
       final View expandedView = mFloatingView.findViewById(R.id.expanded_container);
 
       //Set the close button
       ImageView closeButtonCollapsed = (ImageView) mFloatingView.findViewById(R.id.close_btn);
       closeButtonCollapsed.setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View view) {
               //close the service and remove the from from the window
               stopSelf();
           }
       });
 
       //Set the view while floating view is expanded.
       //Set the play button.
       ImageView playButton = (ImageView) mFloatingView.findViewById(R.id.play_btn);
       playButton.setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View v) {
               Toast.makeText(FloatingViewService.this, "Playing the song.", Toast.LENGTH_LONG).show();
           }
       });
 
 
       //Set the next button.
       ImageView nextButton = (ImageView) mFloatingView.findViewById(R.id.next_btn);
       nextButton.setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View v) {
               Toast.makeText(FloatingViewService.this, "Playing next song.", Toast.LENGTH_LONG).show();
           }
       });
 
 
       //Set the pause button.
       ImageView prevButton = (ImageView) mFloatingView.findViewById(R.id.prev_btn);
       prevButton.setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View v) {
               Toast.makeText(FloatingViewService.this, "Playing previous song.", Toast.LENGTH_LONG).show();
           }
       });
 
 
       //Set the close button
       ImageView closeButton = (ImageView) mFloatingView.findViewById(R.id.close_button);
       closeButton.setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View view) {
               collapsedView.setVisibility(View.VISIBLE);
               expandedView.setVisibility(View.GONE);
           }
       });
 
 
       //Open the application on thi button click
       ImageView openButton = (ImageView) mFloatingView.findViewById(R.id.open_button);
       openButton.setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View view) {
               //Open the application  click.
               Intent intent = new Intent(FloatingViewService.this, MainActivity.class);
               intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
               startActivity(intent);
 
 
               //close the service and remove view from the view hierarchy
               stopSelf();
           }
       });
 
       //Drag and move floating view using user's touch action.
       mFloatingView.findViewById(R.id.root_container).setOnTouchListener(new View.OnTouchListener() {
           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:
 
                       //remember the initial position.
                       initialX = params.x;
                       initialY = params.y;
 
                       //get the touch location
                       initialTouchX = event.getRawX();
                       initialTouchY = event.getRawY();
                       return true;
                   case MotionEvent.ACTION_UP:
                       int Xdiff = (int) (event.getRawX() - initialTouchX);
                       int Ydiff = (int) (event.getRawY() - initialTouchY);
 
 
                       //The check for Xdiff <10 && YDiff< 10 because sometime elements moves a little while clicking.
                       //So that is click event.
                       if (Xdiff < 10 && Ydiff < 10) {
                           if (isViewCollapsed()) {
                               //When user clicks on the image view of the collapsed layout,
                               //visibility of the collapsed layout will be changed to "View.GONE"
                               //and expanded view will become visible.
                               collapsedView.setVisibility(View.GONE);
                               expandedView.setVisibility(View.VISIBLE);
                           }
                       }
                       return true;
                   case MotionEvent.ACTION_MOVE:
                       //Calculate the X and Y coordinates of the view.
                       params.x = initialX + (int) (event.getRawX() - initialTouchX);
                       params.y = initialY + (int) (event.getRawY() - initialTouchY);
 
 
                       //Update the layout with new X & Y coordinate
                       mWindowManager.updateViewLayout(mFloatingView, params);
                       return true;
               }
               return false;
           }
       });
   }
 
 
   /**
    * Detect if the floating view is collapsed or expanded.
    *
    * @return true if the floating view is collapsed.
    */
   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);
   }
}

4. MainActivity.java:


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);
 
       //Check if the application has draw over other apps permission or not?
       //This permission is by default available for API<23. But for API > 23
       //you have to ask for the permission in runtime.
       if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(this)) {
 
 
           //If the draw over permission is not available open the settings screen
           //to grant the permission.
           Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
                   Uri.parse("package:" + getPackageName()));
           startActivityForResult(intent, CODE_DRAW_OVER_OTHER_APP_PERMISSION);
       } else {
           initializeView();
       }
   }
 
   /**
    * Set and initialize the view elements.
    */
   private void initializeView() {
       findViewById(R.id.notify_me).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) {
           //Check if the permission is granted or not.
           if (resultCode == RESULT_OK) {
               initializeView();
           } else { //Permission is not available
               Toast.makeText(this,
                       "Draw over other app permission not available. Closing the application",
                       Toast.LENGTH_SHORT).show();
 
               finish();
           }
       } else {
           super.onActivityResult(requestCode, resultCode, data);
       }
   }
}


Problem will be discussed in Comment section.

About the author

Generic Bytes

Hi! we are from Generic Bytes an aspiring bloggers with an obsession of things tech.This blog is dedicated to people who want to learn the technology.

View all posts

Leave a Reply

Your email address will not be published. Required fields are marked *