Перемещение ImageView, расположенного в WindowManager, не работает должным образом

Я пытаюсь нарисовать значок поверх всего на экране (САМЫЙ ТОП), похожий на заголовок чата нового мессенджера Facebook.

Я создал службу для работы в фоновом режиме, и в зависимости от определенного условия мой значок должен появиться на экране (точно так же, как когда кто-то отправляет вам сообщение на Facebook, служба обмена сообщениями перехватывает сообщение и показывает заголовок чата на экране, чтобы уведомить ты о новом сообщении)

Что я сделал:

Я создал службу и дал ей разрешение показывать окна системных предупреждений (поскольку голова на самом деле является окном системных предупреждений)

[assembly: UsesPermission(Name = Android.Manifest.Permission.SystemAlertWindow)]

Я унаследовал класс (StickyHeadView) от ImageView и реализовал прослушиватель OnTouchListener следующим образом:

class StickyHeadView : ImageView, Android.Views.View.IOnTouchListener
{
    private StickyHeadService OwnerService;

    public StickyHeadView(StickyHeadService ContextService, Context context)
        : base(context)
    {
        OwnerService = ContextService;
        SetOnTouchListener(this);
    }

    float TouchMoveX;
    float TouchMoveY;

    public bool OnTouch(View v, MotionEvent e)
    {
        var windowService = OwnerService.GetSystemService(Android.Content.Context.WindowService);
        var windowManager = windowService.JavaCast<Android.Views.IWindowManager>();

        switch (e.Action & e.ActionMasked)
        {
            case MotionEventActions.Move:
                TouchMoveX = (int)e.GetX();
                TouchMoveY = (int)e.GetY();
                OwnerService.LOParams.X = (int)(TouchMoveX);
                OwnerService.LOParams.Y = (int)(TouchMoveY);
                windowManager.UpdateViewLayout(this, OwnerService.LOParams);                    
                Log.Debug("Point : ", "X: " + Convert.ToString(OwnerService.LOParams.X) + " Y: " + Convert.ToString(OwnerService.LOParams.Y));
                return true;                    
            case MotionEventActions.Down:
                return true;                    
            case MotionEventActions.Up:
                return true;
        }
        return false;
    }
}    

У службы есть оконный менеджер, чтобы показать значок на нем... в событии службы "OnStart" я инициализирую голову:

        private StickyHeadView MyHead;
        public Android.Views.WindowManagerLayoutParams LOParams;
        public override void OnStart(Android.Content.Intent intent, int startId)
        {
            base.OnStart(intent, startId);

            var windowService = this.GetSystemService(Android.Content.Context.WindowService);
            var windowManager = windowService.JavaCast<Android.Views.IWindowManager>();

            MyHead = new StickyHeadView(this, this);
            MyHead.SetImageResource(Resource.Drawable.Icon);
            LOParams = new Android.Views.WindowManagerLayoutParams(Android.Views.WindowManagerLayoutParams.WrapContent,
                                Android.Views.WindowManagerLayoutParams.WrapContent,
                                Android.Views.WindowManagerTypes.Phone,
                                Android.Views.WindowManagerFlags.NotFocusable,
                                Android.Graphics.Format.Translucent);

            LOParams.Gravity = GravityFlags.Top | GravityFlags.Left;
            LOParams.X = 10;
            LOParams.Y = 10;
            windowManager.AddView(MyHead, LOParams);
        } 

как видите, я объявил WindowManager и добавил к нему представление (MyHead) со специальными параметрами.

Моя проблема:

Всякий раз, когда я пытаюсь двигать вид (мою голову), он не двигается стабильно и продолжает трястись!

Я тестирую его с помощью Android 4.0.4 на реальном телефоне HTC.

я пользуюсь монодроидом

Помогите пожалуйста...если реализация тача не правильная предложите способ лучше...спасибо.


comment
Почему никто не отвечает! Я думаю, это форум для вопросов!!!!   -  person user1512094    schedule 06.05.2013
comment
это джава? какой компилятор вы используете?   -  person Kirill Kulakov    schedule 24.03.2014


Ответы (3)


В вашем коде просто используйте...

TYPE_SYSTEM_ALERT

or

TYPE_PHONE

вместо

TYPE_SYSTEM_OVERLAY

Надеюсь, что это поможет вам.

рабочий пример:

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

    windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);

    chatHead = new ImageView(this);
    chatHead.setImageResource(R.drawable.ic_launcher);

    final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
        WindowManager.LayoutParams.WRAP_CONTENT,
        WindowManager.LayoutParams.WRAP_CONTENT,
        WindowManager.LayoutParams.TYPE_SYSTEM_ALERT, //TYPE_PHONE
        WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
        PixelFormat.TRANSLUCENT);

    params.gravity = Gravity.TOP | Gravity.LEFT;
    params.x = 0;
    params.y = 100;

    windowManager.addView(chatHead, params);

    chatHead.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:
                initialX = params.x;
                initialY = params.y;
                initialTouchX = event.getRawX();
                initialTouchY = event.getRawY();
                return true;
              case MotionEvent.ACTION_UP:
                return true;
              case MotionEvent.ACTION_MOVE:
                params.x = initialX + (int) (event.getRawX() - initialTouchX);
                params.y = initialY + (int) (event.getRawY() - initialTouchY);
                windowManager.updateViewLayout(chatHead, params);
                return true;
            }
            return false;
          }
        });
}
person Amit Kumar Khare    schedule 23.02.2014

Используемые вами e.GetX()/eGetY() относятся к положению представления, поэтому при перемещении представления с помощью UpdateViewLayout следующие значения будут относиться к перемещению. Он работает с использованием GetRawX()/GetRawY(), но вы также должны отслеживать исходные значения Down rawX и rawY.

Вот моя JAVA, которая работает:

@Override
public boolean onTouch(View v, MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_MOVE:
            layoutParams.x = Math.round(event.getRawX() - downX);
            layoutParams.y = Math.round(event.getRawY() - downY);
            windowManager.updateViewLayout(floatingView, layoutParams);
            return true;                    
        case MotionEvent.ACTION_DOWN:
            downX = event.getRawX() - layoutParams.x;
            downY = event.getRawY() - layoutParams.y;
            return true;                    
        case MotionEvent.ACTION_UP:
            return true;
    }
    return false;
}

Один комментарий, есть большой недостаток в использовании windowManager.updateViewLayout(...) этот метод будет вызывать onLayout для плавающего представления для каждого перемещения, и это может быть проблемой производительности, в любом случае до сих пор я не нашел другого метода для перемещения плавающий вид.

person adex08    schedule 23.05.2013

Попробуйте это может быть полезно

сначала добавьте глобальную переменную в свою деятельность:

    WindowManager wm;
    LinearLayout lay;
    float downX,downY;

после ввода кода для oncreate вашей деятельности

    Button btnstart=(Button)findViewById(R.id.button1);
    Button btnstop=(Button)findViewById(R.id.button2);

    btnstart.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub

            if(lay==null)
            {
                wm = (WindowManager) getApplicationContext().getSystemService(
                        Context.WINDOW_SERVICE);
                final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                        LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT,
                        WindowManager.LayoutParams.TYPE_SYSTEM_ALERT
                                | WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
                        WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
                        PixelFormat.TRANSLUCENT);
                params.x = (int) wm.getDefaultDisplay().getWidth();
                params.y = 0;
                // params.height = wm.getDefaultDisplay().getHeight()/2;
                params.width = LayoutParams.WRAP_CONTENT;
                params.format = PixelFormat.TRANSLUCENT;

                params.gravity = Gravity.TOP | Gravity.LEFT;
                params.setTitle("Info");

                lay = null;

                lay = new LinearLayout(getApplicationContext());
                lay.setOrientation(LinearLayout.VERTICAL);
                // lay.setAlpha(0.5f);

                TextView txt_no = new TextView(getApplicationContext());
                txt_no.setTextSize(10.0f);
                txt_no.setText("Moving view by stack user!");

                txt_no.setTextColor(Color.BLACK);
                // txt_no.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
                // LayoutParams.WRAP_CONTENT));

                LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
                        LinearLayout.LayoutParams.WRAP_CONTENT,
                        LinearLayout.LayoutParams.WRAP_CONTENT);
                layoutParams.setMargins(0, 0, 0, 0); // margins as you wish

                txt_no.setGravity(Gravity.RIGHT);
                txt_no.setBackgroundColor(Color.WHITE);
                txt_no.setLayoutParams(layoutParams);
                txt_no.setPadding(10, 10, 10, 10);

                lay.addView(txt_no);

                AlphaAnimation alpha = new AlphaAnimation(0.5F, 0.5F);
                alpha.setDuration(0); // Make animation instant
                alpha.setFillAfter(true); // Tell it to persist after the animation ends
                // And then on your layout
                wm.addView(lay, params);
                txt_no.startAnimation(alpha);

                downX=params.x;
                downY=params.y;

                Log.v("MSES>", "x="+ downX +",y="+ downY);

                lay.setOnTouchListener(new OnTouchListener() {

                    @Override
                    public boolean onTouch(View v, MotionEvent event) {
                        // TODO Auto-generated method stub

                        switch (event.getAction()) {
                        case MotionEvent.ACTION_MOVE:

                            params.x = Math.round(event.getRawX() - downX);
                            params.y = Math.round(event.getRawY() - downY);
                            wm.updateViewLayout(lay, params);
                            Log.v("MSES EVENT>", "x="+ event.getRawX() +",y="+ event.getRawY());
                            Log.v("MSES MOVE>", "x="+ params.x +",y="+ params.y);
                            return true;                    
                        case MotionEvent.ACTION_DOWN:
                            downX = event.getRawX() - params.x;
                            downY = event.getRawY() - params.y;
                            Log.v("MSES DOWN>", "x="+ params.x +",y="+ params.y);
                           return true;                    
                        case MotionEvent.ACTION_UP:
                            //params.x = Math.round(event.getRawX() - downX);
                            //params.y = Math.round(event.getRawY() - downY);
                            //wm.updateViewLayout(lay, params);
                            return true;                   

                        }
                        return false;
                    }
                });
            }

        }
    });

    btnstop.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
            if (lay != null) {
                lay.removeAllViews();
                wm.removeViewImmediate(lay);
                lay = null;
            }
        }
    });
person Stack Overflow User    schedule 29.07.2013