Tạo cửa sổ lớp phủ hệ thống (luôn ở trên cùng)


285

Tôi đang cố gắng tạo một nút luôn luôn ở trên đỉnh / hình ảnh có thể nhấp luôn ở trên tất cả các cửa sổ mọi lúc.

Bằng chứng của khái niệm là

Tôi đã thành công và có một dịch vụ đang chạy. Dịch vụ hiển thị một số văn bản ở góc trên cùng bên trái của màn hình trong khi người dùng có thể tự do tương tác với các ứng dụng còn lại theo cách thông thường.

Những gì tôi đang làm là phân lớp ViewGroupvà thêm nó vào trình quản lý cửa sổ gốc bằng cờ TYPE_SYSTEM_OVERLAY. Bây giờ tôi muốn thêm một nút / hình ảnh có thể nhấp vào thay cho văn bản này có thể nhận các sự kiện chạm vào chính nó. Tôi đã cố gắng ghi đè "onTouchEvent" cho toàn bộ ViewGroupnhưng nó không nhận được bất kỳ sự kiện nào.

Làm cách nào tôi chỉ có thể nhận các sự kiện trên một số phần nhất định trong nhóm xem luôn ở trên cùng của mình? Vui lòng đề nghị.

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;
    }
}

2
@coreSOLO, tôi hy vọng bạn nhận được câu trả lời của bạn, những câu hỏi tương tự kỳ lạ của tôi không nhận được bất kỳ câu trả lời nào. :) +1
st0le

3
@ st0le Tôi hứa tôi sẽ dành cả ngày lẫn đêm cho đến khi tôi tìm ra giải pháp và chia sẻ nó với bạn :)
coreSOLO

1
@ st0le Ok có lẽ bạn và tôi có thể khai thác nó cùng nhau, cho tôi một liên kết câu hỏi của bạn và cho tôi biết bạn đã có thể tiến bộ đến mức nào ...
coreSOLO


3
Thật đáng ngạc nhiên khi bạn onDraw()đang được gọi. dispatchDraw()Thay vào đó không nên bị ghi đè? Xem nhóm.google.com/forum/?fromgroups
faizal

Câu trả lời:


158

Đây có thể là một giải pháp ngu ngốc. Nhưng nó đã có tác dụng. Nếu bạn có thể cải thiện nó, xin vui lòng cho tôi biết.

OnCreate của Dịch vụ của bạn: Tôi đã sử dụng WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCHcờ. Đây là thay đổi duy nhất trong dịch vụ.

@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.TYPE_SYSTEM_OVERLAY,
                WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
                PixelFormat.TRANSLUCENT);
        params.gravity = Gravity.RIGHT | Gravity.TOP;
        params.setTitle("Load Average");
        WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
        wm.addView(mView, params);
    }

Bây giờ, bạn sẽ bắt đầu nhận được từng sự kiện nhấp chuột. Vì vậy, bạn cần phải khắc phục trong xử lý sự kiện của bạn.

Trong sự kiện chạm Viewgroup của bạn

@Override
public boolean onTouchEvent(MotionEvent event) {

    // ATTENTION: GET THE X,Y OF EVENT FROM THE PARAMETER
    // THEN CHECK IF THAT IS INSIDE YOUR DESIRED AREA


    Toast.makeText(getContext(),"onTouchEvent", Toast.LENGTH_LONG).show();
    return true;
}

Ngoài ra, bạn có thể cần thêm quyền này vào bảng kê khai của mình:

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

1
@pengwang: bạn đang mắc lỗi gì? Mã này không độc lập, bạn cần đặt chúng trong dự án của bạn với tên tệp thích hợp trong dự án phù hợp.
Sarwar Erfan

4
@pengwang: Tìm cách thực hiện đơn giản nhất tại đây: docs.google.com.vn
Sarwar Erfan

6
Toàn bộ mã là chính xác, tôi tìm thấy lỗi của mình, tôi quên liên kết <
used

1
Câu trả lời này rất hữu ích, ngoại trừ một điều. Như được sử dụng trong mã, WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH, theo tài liệu, "sẽ không nhận được toàn bộ cử chỉ lên / di chuyển / xuống". Nói cách khác, không thể phát hiện các thao tác vuốt hoặc bất kỳ thứ gì khác ngoài ACTION_DOWN. Tôi biết rằng có thể phát hiện các lần vuốt vì Wave Launcher sử dụng khái niệm tương tự này và họ có thể phát hiện các lần vuốt. Bất cứ ai có thể giải thích cho tôi làm thế nào điều này làm việc?
Brian

6
@SarwarErfan - Tôi đã sử dụng nút chai này một cách hoàn hảo trên 2.3 nhưng sự kiện onTouch không phải là sự thay đổi được gọi là trên Android 4.0, ngày 1 4.1. Xin hãy giúp đỡ
Sanjay Singh

66

Theo câu trả lời của @Sam Lu, Thật vậy, Android 4.x chặn một số loại nhất định không nghe các sự kiện chạm bên ngoài, nhưng một số loại, chẳng hạn như TYPE_SYSTEM_ALERT, vẫn thực hiện công việc.

Thí dụ

    WindowManager.LayoutParams params = new WindowManager.LayoutParams(
            WindowManager.LayoutParams.MATCH_PARENT,
            WindowManager.LayoutParams.MATCH_PARENT,
            WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
            WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                    | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                    | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
            PixelFormat.TRANSLUCENT);

    WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
    LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
    View myView = inflater.inflate(R.layout.my_view, null);
    myView.setOnTouchListener(new OnTouchListener() {
       @Override
       public boolean onTouch(View v, MotionEvent event) {
           Log.d(TAG, "touch me");
           return true;
       }
     });

    // Add layout to window manager
    wm.addView(myView, params);

Quyền

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

5
Nó làm cho màn hình của tôi bị treo .. Mọi ý tưởng
Viswanath Lekshmanan

Bài đăng tuyệt vời. Hy vọng điều này không bị vô hiệu hóa trong các phiên bản tương lai.
Cookster

Ảnh động sẽ không hoạt động trên đó ... :( Và nó không thể bắt được nhấp vào bất kỳ chế độ xem nào trong đó vào 4.2.X. Có đề xuất nào không?
Kamran Ahmed

Nó hoạt động nhưng khi tôi sử dụng phím tắt đó (tức là Thông báo mức hệ thống), các hộp thoại khác sẽ không được hiển thị. Tại sao ?
Chimu

@Arju ý bạn là gì? bạn đang cố gắng để loại bỏ nó?
amirlazarovich

18

Bắt đầu với Android 4.x, đội ngũ Android khắc phục sự cố an ninh tiềm năng bằng cách thêm một chức năng mới adjustWindowParamsLw(), trong đó nó sẽ thêm FLAG_NOT_FOCUSABLE, FLAG_NOT_TOUCHABLEvà loại bỏ FLAG_WATCH_OUTSIDE_TOUCHcờ choTYPE_SYSTEM_OVERLAY cửa sổ.

Đó là, một TYPE_SYSTEM_OVERLAYcửa sổ sẽ không nhận được bất kỳ sự kiện chạm nào trên nền tảng ICS và tất nhiên, việc sử dụng TYPE_SYSTEM_OVERLAYkhông phải là một giải pháp khả thi cho ICS và các thiết bị trong tương lai.


4
Vì vậy, các lựa chọn thay thế là gì?
radhoo


13

Tôi là một trong những nhà phát triển SDK Tooleap . Chúng tôi cũng cung cấp một cách để các nhà phát triển hiển thị luôn trên các cửa sổ và nút trên cùng và chúng tôi đã xử lý một tình huống tương tự.

Một vấn đề mà câu trả lời ở đây chưa được giải quyết là "Nút bảo mật" của Android.

Các nút được bảo mật có thuộc filterTouchesWhenObscuredtính có nghĩa là chúng không thể tương tác với nhau, nếu được đặt dưới cửa sổ, ngay cả khi cửa sổ đó không nhận được bất kỳ chạm nào. Trích dẫn tài liệu Android:

Chỉ định xem có lọc các chạm hay không khi cửa sổ của chế độ xem bị che khuất bởi một cửa sổ hiển thị khác. Khi được đặt thành đúng, chế độ xem sẽ không nhận được chạm mỗi khi bánh mì nướng, hộp thoại hoặc cửa sổ khác xuất hiện phía trên cửa sổ của chế độ xem. Tham khảo tài liệu bảo mật {@link android.view.View} để biết thêm chi tiết.

Một ví dụ về nút như vậy là nút cài đặt khi bạn cố gắng cài đặt apks của bên thứ ba. Bất kỳ ứng dụng nào cũng có thể hiển thị nút như vậy nếu thêm vào bố cục chế độ xem dòng sau:

android:filterTouchesWhenObscured="true"

Nếu bạn hiển thị cửa sổ luôn ở trên cùng trên "Nút bảo mật", thì tất cả các phần nút được bảo mật được phủ bởi lớp phủ sẽ không xử lý bất kỳ chạm nào, ngay cả khi lớp phủ đó không thể nhấp được. Vì vậy, nếu bạn đang dự định hiển thị một cửa sổ như vậy, bạn nên cung cấp một cách để người dùng di chuyển nó hoặc loại bỏ nó. Và nếu một phần của lớp phủ của bạn trong suốt, hãy tính đến việc người dùng của bạn có thể bị nhầm lẫn tại sao một nút nhất định trong ứng dụng cơ bản không hoạt động cho anh ta đột ngột.


Bạn có thể vui lòng trả lời câu hỏi của tôi không: stackoverflow.com/questions/28964771/
Kẻ

Có một số hoạt động trong Android 10 mà chế độ xem lớp phủ không thể hiển thị ở trên chúng, bạn có thể vui lòng cho biết lý do hoặc xem câu hỏi của tôi ở đây không, nó sẽ rất hữu ích stackoverflow.com/questions/59598264/
Mateen Chaudhry

12

LÀM VIỆC LUÔN LUÔN TRÊN NÚT HÌNH ẢNH HÀNG ĐẦU

trước hết xin lỗi vì tiếng anh của tôi

tôi chỉnh sửa mã của bạn và làm cho nút hình ảnh hoạt động nghe sự kiện chạm của anh ấy không điều khiển cảm ứng cho các thành phần nền của anh ấy.

nó cũng cung cấp cho người nghe cảm ứng ra khỏi các yếu tố khác

nút thắt là đáy và trái

bạn có thể cheat alingsment nhưng bạn cần cheat cordinats trong sự kiện liên lạc trong phần tử if

import android.annotation.SuppressLint;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.os.IBinder;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.Toast;

public class HepUstte extends Service {
    HUDView mView;

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

        Toast.makeText(getBaseContext(),"onCreate", Toast.LENGTH_LONG).show();

        final Bitmap kangoo = BitmapFactory.decodeResource(getResources(),
                R.drawable.logo_l);


        WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                kangoo.getWidth(), 
                kangoo.getHeight(),
                WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                |WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                |WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
                 PixelFormat.TRANSLUCENT);






        params.gravity = Gravity.LEFT | Gravity.BOTTOM;
        params.setTitle("Load Average");
        WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);



        mView = new HUDView(this,kangoo);

        mView.setOnTouchListener(new OnTouchListener() {


            @Override
            public boolean onTouch(View arg0, MotionEvent arg1) {
                // TODO Auto-generated method stub
                //Log.e("kordinatlar", arg1.getX()+":"+arg1.getY()+":"+display.getHeight()+":"+kangoo.getHeight());
                if(arg1.getX()<kangoo.getWidth() & arg1.getY()>0)
                {
                 Log.d("tıklandı", "touch me");
                }
                return false;
            }
             });


        wm.addView(mView, params);



        }



    @Override
    public IBinder onBind(Intent arg0) {
        // TODO Auto-generated method stub
        return null;
    }

}



@SuppressLint("DrawAllocation")
class HUDView extends ViewGroup {


    Bitmap kangoo;

    public HUDView(Context context,Bitmap kangoo) {
        super(context);

        this.kangoo=kangoo;



    }


    protected void onDraw(Canvas canvas) {
        //super.onDraw(canvas);


        // delete below line if you want transparent back color, but to understand the sizes use back color
        canvas.drawColor(Color.BLACK);

        canvas.drawBitmap(kangoo,0 , 0, null); 


        //canvas.drawText("Hello World", 5, 15, mLoadPaint);

    }


    protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int arg4) {
    }

    public boolean onTouchEvent(MotionEvent event) {
        //return super.onTouchEvent(event);
       // Toast.makeText(getContext(),"onTouchEvent", Toast.LENGTH_LONG).show();

        return true;
    }
}

Điều này hoạt động, nhưng làm thế nào tôi có thể chắc chắn rằng hình ảnh của tôi đã được nhấp và không phải cái gì đó xung quanh hình ảnh?
Liam W

@LiamW, tọa độ của cảm ứng được so sánh với kangaroo.getWidth () trong ví dụ này. Bạn có thể suy ra những gì để so sánh nó với mã của riêng bạn dựa trên nơi bạn đang vẽ hình ảnh của mình.
Yevgeny Simkin

Rất đẹp! Hoạt động hoàn hảo.
Yevgeny Simkin

Phiên bản Android tối thiểu này hoạt động trên là gì? Tôi đang làm việc để viết lên nhưng tôi mới sử dụng Android vì vậy có thời gian mới bắt đầu.
Noitidart

6

Trên thực tế, bạn có thể dùng thử WindowManager.LayoutParams.TYPE_SYIUS_ERROR thay vì TYPE_SYIUS_OVERLAY. Nghe có vẻ giống như một bản hack, nhưng nó cho phép bạn hiển thị chế độ xem trên đầu mọi thứ và vẫn nhận được các sự kiện chạm.


1
Tôi đã thử mọi cách để làm cho nó hoạt động, nhưng không thành công .... nhưng thêm TYPE_SYIUS_ERROR đã hoàn thành công việc .... Trên thực tế TYPE_SYIUS_OVERLAY đã chặn cảm ứng ..... + 1.
Robi Kumar Tomar

6

TYPE_SYIUS_OVERLAY Hằng số này không được dùng nữa kể từ cấp API 26. Thay vào đó, hãy sử dụng TYPE_APPLICATION_OVERLAY. hoặc ** cho người dùng bên dưới và trên android 8

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    LAYOUT_FLAG = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
} else {
    LAYOUT_FLAG = WindowManager.LayoutParams.TYPE_PHONE;
}

5

Thử cái này. Hoạt động tốt trong ICS. Nếu bạn muốn dừng dịch vụ, chỉ cần nhấp vào thông báo được tạo trong thanh trạng thái.

 public class HUD extends Service
 {
    protected boolean foreground = false;
    protected boolean cancelNotification = false;
    private Notification notification;
    private View myView;
    protected int id = 0;
    private WindowManager wm;
    private WindowManager.LayoutParams params;
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
    @Override
    public void onCreate() {
        super.onCreate();
       // System.exit(0);
        Toast.makeText(getBaseContext(),"onCreate", Toast.LENGTH_SHORT).show();
        params = new WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.TYPE_PHONE, WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                        | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT);
        params.gravity=Gravity.TOP|Gravity.LEFT;
    wm = (WindowManager) getSystemService(WINDOW_SERVICE);
    inflateview();
    foregroundNotification(1);
    //moveToForeground(1,n,true);
    }     
   @Override
    public void onDestroy() {
        super.onDestroy();
        ((NotificationManager) getSystemService(NOTIFICATION_SERVICE)).cancel(0);
        Toast.makeText(getBaseContext(),"onDestroy", Toast.LENGTH_SHORT).show();
        if(myView != null)
        {
            ((WindowManager) getSystemService(WINDOW_SERVICE)).removeView(myView);
            myView = null;
        }
    }
    protected Notification foregroundNotification(int notificationId) 
   {    
    notification = new Notification(R.drawable.ic_launcher, "my Notification", System.currentTimeMillis());    
        notification.flags = notification.flags | Notification.FLAG_ONGOING_EVENT | Notification.FLAG_ONLY_ALERT_ONCE;   
        notification.setLatestEventInfo(this, "my Notification", "my Notification", notificationIntent());          
        ((NotificationManager) getSystemService(NOTIFICATION_SERVICE)).notify(id, notification);            
        return notification;
    }
    private PendingIntent notificationIntent() {
        Intent intent = new Intent(this, stopservice.class);    
        PendingIntent pending = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);    
        return pending;
    }
    public void inflateview()
    {
         LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
            myView = inflater.inflate(R.layout.activity_button, null);
            myView.setOnTouchListener(new OnTouchListener() {
               @Override
               public boolean onTouch(View v, MotionEvent event) {
                   Toast.makeText(getBaseContext(),"onToasttt", Toast.LENGTH_SHORT).show();
                   return false;
               }
             });
            // Add layout to window manager
            wm.addView(myView, params); 
    }
}

CẬP NHẬT

Mẫu ở đây

Để tạo chế độ xem lớp phủ, khi thiết lập LayoutParams KHÔNG đặt loại thành TYPE_SYIUS_OVERLAY.

Instead set it to TYPE_PHONE.

Use the following flags:

FLAG_NOT_TOUCH_MODAL

FLAG_WATCH_OUTSIDE_TOUCH

Điều này không hoạt động với tôi, Màn hình của tôi không tương tác với nền. Bất kỳ phương pháp nào khác mà bạn biết ...
Vinuthan 16/07/13

@Vinuthan Đầu ra của bạn là gì, nó có phản hồi không
Viswanath Lekshmanan 18/07/13

Không, nó không đáp ứng. Tôi đã đệm hoạt động của mình ở trên một nửa màn hình để tôi có thể tương tác với nền, nhưng tôi không thể tương tác với nền.
Vinuthan

FLAG_WATCH_OUTSIDE_TOUCH ngăn bạn tương tác với nền
Richard Le Mesurier

1
TYPE_PHONE đã làm việc cho tôi - bây giờ các lần chạm đã được gửi - ít nhất là tôi có thể nhấn vào một nút;) cảm ơn!
vir chúng tôi

3

Đây là một số giải pháp đơn giản, Tất cả những gì bạn cần là làm tăng bố cục XML giống như bạn làm trên các bộ điều hợp danh sách, chỉ cần tạo bố cục XML để làm tăng nó. Đây là mã mà tất cả bạn cần.

 public class HUD extends Service {
    View mView;

    LayoutInflater inflate;
    TextView t;
    Button b;

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

        Toast.makeText(getBaseContext(),"onCreate", Toast.LENGTH_LONG).show();


        WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);

        Display display = wm.getDefaultDisplay();  get phone display size
        int width = display.getWidth();  // deprecated - get phone display width
        int height = display.getHeight(); // deprecated - get phone display height 


        WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                width, 
                height,
                WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                |WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                |WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
                 PixelFormat.TRANSLUCENT);


        params.gravity = Gravity.LEFT | Gravity.CENTER;
        params.setTitle("Load Average");

        inflate = (LayoutInflater) getBaseContext()
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        mView = inflate.inflate(R.layout.canvas, null);

        b =  (Button) mView.findViewById(R.id.button1);
        t = (TextView) mView.findViewById(R.id.textView1);
        b.setOnClickListener(new OnClickListener() {

        public void onClick(View v) {
            // TODO Auto-generated method stub
            t.setText("yes you click me ");
        }
       });

        wm.addView(mView, params);

        }



    @Override
    public IBinder onBind(Intent arg0) {
        // TODO Auto-generated method stub
        return null;
    }

}



1

Hãy thử mã của tôi, ít nhất nó cung cấp cho bạn một chuỗi như lớp phủ, bạn rất có thể thay thế nó bằng một nút hoặc hình ảnh. Bạn sẽ không tin đây là ứng dụng Android đầu tiên của tôi LOL. Dù sao, nếu bạn có nhiều kinh nghiệm với các ứng dụng Android hơn tôi, vui lòng thử

  • thay đổi tham số 2 và 3 trong "WindowManager.LayoutParams mới"
  • thử một số cách tiếp cận sự kiện khác nhau

Cuối cùng tôi đã không tìm thấy thời gian để theo đuổi điều này, do đó tôi vẫn còn khan hiếm về các chi tiết của nó ...
st0le

1

Nếu bất cứ ai vẫn đọc chủ đề này và không thể làm cho nó hoạt động, tôi rất tiếc phải nói với bạn cách này để chặn sự kiện chuyển động được coi là lỗi và sửa lỗi trong android> = 4.2.

Sự kiện chuyển động bạn đã chặn, mặc dù có hành động là ACTION_OUTSIDE, trả về 0 trong getX và getY. Điều này có nghĩa là bạn không thể thấy tất cả các vị trí chuyển động trên màn hình, bạn cũng không thể làm gì. Tôi biết tài liệu nói Nó sẽ nhận được x và y, nhưng sự thật là nó KHÔNG. Có vẻ như đây là để chặn logger.

Nếu bất cứ ai có một cách giải quyết, xin vui lòng để lại nhận xét của bạn.

ref: Tại sao ACTION_OUTSIDE trả về 0 mỗi lần trên KitKat 4.4.2?

https://code.google.com.vn/p/android/issues/detail?id=72746


1

bằng cách sử dụng dịch vụ bạn có thể đạt được điều này:

public class PopupService extends Service{

    private static final String TAG = PopupService.class.getSimpleName();
    WindowManager mWindowManager;
    View mView;
    String type ;

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

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
//        registerOverlayReceiver();
        type = intent.getStringExtra("type");
        Utils.printLog("type = "+type);
        showDialog(intent.getStringExtra("msg"));
        return super.onStartCommand(intent, flags, startId);
    }

    private void showDialog(String aTitle)
    {
        if(type.equals("when screen is off") | type.equals("always"))
        {
            Utils.printLog("type = "+type);
            PowerManager pm = (PowerManager) getApplicationContext().getSystemService(Context.POWER_SERVICE);
            WakeLock mWakeLock = pm.newWakeLock((PowerManager.SCREEN_DIM_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP), "YourServie");
            mWakeLock.acquire();
            mWakeLock.release();
        }

        mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
        mView = View.inflate(getApplicationContext(), R.layout.dialog_popup_notification_received, null);
        mView.setTag(TAG);

        int top = getApplicationContext().getResources().getDisplayMetrics().heightPixels / 2;

        LinearLayout dialog = (LinearLayout) mView.findViewById(R.id.pop_exit);
//        android.widget.LinearLayout.LayoutParams lp = (android.widget.LinearLayout.LayoutParams) dialog.getLayoutParams();
//        lp.topMargin = top;
//        lp.bottomMargin = top;
//        mView.setLayoutParams(lp);

        final EditText etMassage = (EditText) mView.findViewById(R.id.editTextInPopupMessageReceived);

        ImageButton imageButtonSend = (ImageButton) mView.findViewById(R.id.imageButtonSendInPopupMessageReceived);
//        lp = (LayoutParams) imageButton.getLayoutParams();
//        lp.topMargin = top - 58;
//        imageButton.setLayoutParams(lp);
        imageButtonSend.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Utils.printLog("clicked");
//                mView.setVisibility(View.INVISIBLE);
                if(!etMassage.getText().toString().equals(""))
                {
                    Utils.printLog("sent");
                    etMassage.setText("");
                }
            }
        });

        TextView close = (TextView) mView.findViewById(R.id.TextViewCloseInPopupMessageReceived);
        close.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View arg0) {
                hideDialog();   
            }
        });

        TextView view = (TextView) mView.findViewById(R.id.textviewViewInPopupMessageReceived);
        view.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View arg0) {
                hideDialog();   
            }
        });

        TextView message = (TextView) mView.findViewById(R.id.TextViewMessageInPopupMessageReceived);
        message.setText(aTitle);

        final WindowManager.LayoutParams mLayoutParams = new WindowManager.LayoutParams(
        ViewGroup.LayoutParams.MATCH_PARENT,
        ViewGroup.LayoutParams.MATCH_PARENT, 0, 0,
        WindowManager.LayoutParams.TYPE_SYSTEM_ERROR,
        WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
                | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
//                | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
                | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON ,
        PixelFormat.RGBA_8888);

        mView.setVisibility(View.VISIBLE);
        mWindowManager.addView(mView, mLayoutParams);
        mWindowManager.updateViewLayout(mView, mLayoutParams);

    }

    private void hideDialog(){
        if(mView != null && mWindowManager != null){
            mWindowManager.removeView(mView);
            mView = null;
        }
    }
}

1

@Sarwar Câu trả lời của Erfan không còn hoạt động nữa vì Android không cho phép thêm chế độ xem với WindowManager.LayoutParams.TYPE_SYIUS_OVERLAY để cửa sổ có thể chạm được nữa, ngay cả với WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH.

Tôi tìm thấy giải pháp cho vấn đề này. Bạn có thể kiểm tra nó trong câu hỏi sau đây

Khi thêm chế độ xem vào cửa sổ với WindowManager.LayoutParams.TYPE_SYIUS_OVERLAY, nó không nhận được sự kiện cảm ứng


Giải pháp được giới thiệu của bạn cũng không hoạt động trong Marshmallow
Ahmad Shahwaiz

@AhmadShahwaiz Vui lòng kiểm tra lại liên kết Tôi đã thêm nhận xét cho vấn đề bạn đã đề cập ở đó
patilmandar2007

Vâng, bây giờ nó hoạt động. Nhưng không nhận được phản hồi gọi lại sau khi gọi startActivityForResult (ý định, OVERLAY_REQ_CODE); trong phương thức void được bảo vệ onActivityResult (int requestCode, int resultCode, Intent data).
Ahmad Shahwaiz 7/11/2016

@AhmadShahwaiz Các thay đổi được đề cập trong liên kết sẽ được gọi bằng cách sử dụng hoạt động trong đó chúng tôi nhận được cuộc gọi lại trong phương thức onActivityResult. Nếu bạn đang kiểm tra quyền trên Dịch vụ thì bạn có thể cần thêm một hoạt động trong suốt giả để bắt đầu từ dịch vụ, có thể yêu cầu Người dùng cấp phép và sau đó trong hoạt động giả trên onActivityResult bạn sẽ nhận được kết quả từ người dùng. Sau khi bạn sẽ yêu cầu thông báo dịch vụ của mình để thêm chế độ xem vào cửa sổ hay không tùy thuộc vào phản hồi của người dùng
patilmandar2007

1

Đây là một Câu hỏi cũ nhưng gần đây Android có hỗ trợ cho Bong bóng. Bong bóng sẽ sớm được tung ra nhưng hiện tại các nhà phát triển có thể bắt đầu sử dụng chúng. Chúng được thiết kế để thay thế cho việc sử dụng SYSTEM_ALERT_WINDOW. Các ứng dụng như (Facebook Messenger và MusiXMatch sử dụng cùng một khái niệm).

Bong bóng

Bong bóng được tạo thông qua API thông báo, bạn gửi thông báo của mình như bình thường. Nếu bạn muốn nó bong bóng, bạn cần đính kèm một số dữ liệu bổ sung cho nó. Để biết thêm thông tin về Bong bóng, bạn có thể truy cập Hướng dẫn dành cho nhà phát triển Android chính thức về Bong bóng .

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.