[Android] Hướng dẫn tạo Floating View như ứng dụng Messenger

Đăng bởi: Admin | Lượt xem: 2881 | Chuyên mục: Android

Floating View là view trôi trên màn hình, thường gặp ở một số ứng dụng nhắn tin như Messenger, Zalo,... dưới dạng bong bóng chat. Người dùng có thể dễ dàng kéo thả, thao tác với view này ngay cả khi đang mở ứng dụng khác. Trong bài viết này, mình sẽ hướng dẫn các bạn tạo floating view tương tự như Messenger của Facebook.


1. Giới thiệu

Floating view là view trôi trên màn hình, nó rất thuận tiện cho việc thao tác đa nhiệm, 1 người có thể làm việc trên các ứng dụng khác nhau và kiểm soát chúng cùng 1 lúc. Điều đó có nghĩa là nếu bạn đang ở trong các ứng dụng tính toán, bạn có thể thấy được tin nhắn đến và trả lời tin nhắn thông qua bong bóng chat của Messenger nổi trên màn hình

Trong bài viết này, chúng ta sẽ tìm hiểu làm thế nào để tạo floating view đơn giản và cho phép người sử dụng để kéo chúng trên màn hình.

2. Bắt đầu

2.1. Tạo mới Project

Các bạn mở Android Studio, tạo mới ứng dụng với một activity: MainActivity và layout là activity_main.xml như sau :

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/btn_start"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="START" />

    <Button
        android:id="@+id/btn_stop"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/btn_start"
        android:layout_centerHorizontal="true"
        android:text="STOP" />

</RelativeLayout>

Trong MainActivity, chúng ta sẽ có 2 button START, STOP để mở và tắt view giống MessengerFacebook.

2.2 "Draw over other apps" permission

Để view có thể kéo thả lên trên các ứng dụng khác, bạn phải yêu cầu ứng dụng của mình được sử dụng permison ACTION_MANAGE_OVERLAY_PERMISSION. Do đó, xử lý trong MainActivity như sau :

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if (!Settings.canDrawOverlays(this)) {
            Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName()));
            startActivityForResult(intent, 0);
        }

    }

Ngoài ra, bạn cần phải thêm permission trong AndroidManifest.xml như sau :

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

Lúc này, khi chạy ứng dụng, app mở lên sẽ chuyển sang màn hình setting, để bạn có thể cho phép ứng dụng của mình được hiển thị đè lên các ứng dụng khác như sau :

Bạn hãy enable permission này lên để chúng ta tiếp tục các phần sau.

2.3. Service

Chúng ta sẽ tạo một Service để điểu khiển view mà chúng ta mong muốn. Các bạn hãy tạo một class mới, đặt tên là MyService.

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;

import androidx.annotation.Nullable;

public class MyService extends Service {

    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

Nhớ khai báo trong AndroidManifest.xml như sau :

      <service
            android:name=".MyService"
            android:exported="true" />

Trong MyService, chúng ta sẽ tạo ra một ImageView, hiển thị icon của app, và xử lý logic khi người dùng kéo thả như sau :

package com.demo.floating;

import android.app.Service;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.os.IBinder;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageView;

import androidx.annotation.Nullable;

public class MyService extends Service {

    private WindowManager mWindowManager;
    private ImageView image;

    @Override
    public void onCreate() {
        super.onCreate();

        image = new ImageView(this);

        image.setImageResource(R.mipmap.ic_launcher);

        mWindowManager = (WindowManager)getSystemService(WINDOW_SERVICE);

        final WindowManager.LayoutParams paramsF = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.TYPE_PHONE,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
                PixelFormat.TRANSLUCENT);

        paramsF.gravity = Gravity.TOP | Gravity.LEFT;
        paramsF.x=0;
        paramsF.y=100;
        mWindowManager.addView(image, paramsF);

        try{

            image.setOnTouchListener(new View.OnTouchListener() {
                WindowManager.LayoutParams paramsT = paramsF;
                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:
                            initialX = paramsF.x;
                            initialY = paramsF.y;
                            initialTouchX = event.getRawX();
                            initialTouchY = event.getRawY();
                            break;
                        case MotionEvent.ACTION_UP:
                            break;
                        case MotionEvent.ACTION_MOVE:
                            paramsF.x = initialX + (int) (event.getRawX() - initialTouchX);
                            paramsF.y = initialY + (int) (event.getRawY() - initialTouchY);
                            mWindowManager.updateViewLayout(v, paramsF);
                            break;
                    }
                    return false;
                }
            });
        } catch (Exception e){
            e.printStackTrace();
        }

    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

2.4. Xử lý trong MainActivity

Chúng ta sẽ xử lý khi click vào button START , STOP trong MainActivity như sau :

import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Settings;
import android.view.View;

import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if (!Settings.canDrawOverlays(this)) {
            Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName()));
            startActivityForResult(intent, 0);
        }

        findViewById(R.id.btn_start).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //toast
                startService(new Intent(MainActivity.this, MyService.class));
            }
        });

        findViewById(R.id.btn_stop).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                stopService(new Intent(MainActivity.this, MyService.class));
            }
        });

    }
}

Chạy ứng dụng, khi bạn click vào START, sẽ xuất hiện 1 view chính là icon của app. Bạn có thể kéo thả nó toàn màn hình, ngay cả khi thoát app như sau :

3. Kết luận

Qua bài viết hy vọng bạn đã biết cách tạo Floating View và có thể ứng dụng cho các dự án trong tương lai.

Cảm ơn bạn đã đọc bài viết.

Chào thân ái và quyết thắng!

vncoder logo

Theo dõi VnCoder trên Facebook, để cập nhật những bài viết, tin tức và khoá học mới nhất!



Khóa học liên quan

Khóa học: Android

Học Kotlin cơ bản
Số bài học:
Lượt xem: 17611
Đăng bởi: Admin
Chuyên mục: Android

Học lập trình Flutter cơ bản
Số bài học:
Lượt xem: 58507
Đăng bởi: Admin
Chuyên mục: Android

Lập trình Android cơ bản
Số bài học:
Lượt xem: 22990
Đăng bởi: Admin
Chuyên mục: Android