2

화면 주위를 돌아 다니는 작은 스프라이트 애니메이션을 만드는 앱을 만들고 있습니다.방향을 변경 한 후에 전체 화면 오버레이를 전체 화면으로 유지하려면 어떻게해야합니까?

"start service"버튼이있는 주요 활동이 있습니다. 그러면 (onCreate()에서) 전체 화면보기가 만들어지고 루트 창 관리자에 연결되는 서비스가 시작됩니다.

이 부분은 완벽하게 작동합니다. 그것은 화면을 채우고, 당신은 응용 프로그램을 떠날 수 있고, 애니메이션은 모든 것을 볼 수 있습니다. 당신이 장치를 회전 할 때

initial render is fine

문제

가 나온다.

view does not rotate with device

스프라이트가 화면의 중앙으로 이동하지만,이 관계가없는 문제가있다; 여기서 중요한 것은 어두운 경계 상자입니다.이 상자는 내가 그릴 수있는 캔버스를 보여주고 전체 화면을 채울 필요가 있습니다.

다른 모든 레이아웃이 보이지만보기가 여전히 세로 모드입니다. 올바르게 업데이트되었습니다.


일부 문제는 뷰의 크기를 어떻게 지정했는지에 따라 결정됩니다. "전체 화면"을 지정하기 위해 플래그를 사용했으나 이 아니며은 화면의 크기와 일치하도록 화면의 widthheight을 설정했습니다. 따라서 나는 시작할 때 수동으로 설정해야했다.

보기를 만든 후에보기의 너비와 높이를 업데이트하는 방법을 모르지만 필자는보기의 크기가 캔버스의 크기를 결정하므로 필자는 필자에게 그렇게 느낀다.

public class WalkerService extends Service { 
    private WalkerView view; 

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

     final WindowManager wm = (WindowManager)getSystemService(WINDOW_SERVICE); 

     final DisplayMetrics metrics = new DisplayMetrics(); 
     wm.getDefaultDisplay().getMetrics(metrics); 

     view = new WalkerView(this); // extends SurfaceView 
     final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
       WindowManager.LayoutParams.FLAG_FULLSCREEN, 
       WindowManager.LayoutParams.FLAG_FULLSCREEN, 
       WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY, // TYPE_SYSTEM_ALERT is denied in apiLevel >=19 
       WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN, 
       PixelFormat.TRANSLUCENT 
     ); 
     view.setFitsSystemWindows(false); // allow us to draw over status bar, navigation bar 

     // here I _manually_ set the dimensions, because otherwise it defaults to a square (something like 1024x1024) 
     params.width = metrics.widthPixels; 
     params.height = metrics.heightPixels; 

     wm.addView(view, params); 
    } 
} 

나는 방향 변경을 수신했는데, 그렇게되면 뷰를 회전 한 :

@Override 
public void onConfigurationChanged(Configuration newConfig) { 
    super.onConfigurationChanged(newConfig); 

    view.setRotation(
      newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE 
        ? 90.0f 
        : 0.0f 
    ); 
} 

그러나 setRotation()가 영향을 보이지 않았다

내 서비스는보기과 같이 생성 내보기의 widthheight도 캔버스가 렌더링 된 각도를 변경하지 않았습니다.


전체 화면 오버레이를 만드는 방법을 근본적으로 잘못 알고 있습니까? 방향에 관계없이 (심지어 내 앱이 활성 앱이 아닌 경우에도) 전체 화면을 그릴 수있는 기능을 유지하려면 어떻게해야합니까?

아마 Window Service의 윈도우 관리자에 내 뷰를 첨부하는 것과 관련이 있습니다. 아마도 내 뷰에 이상한 부모가 있습니다 (아마도 루트 뷰가 오리 엔테이션의 영향을받지 않을 것이라고 생각할 수 있습니다. 어린이가 채우기 위해 스트레칭 할 경계가 정의되지 않음).

여기서 유용한 정보를 생략 한 경우 전체 소스 코드는 public on GitHub입니다.

WalkerView.java이 특히 적합 할 수 있으므로 here it is 일 수 있습니다.

+0

이건이 문제와 중복되는 것 같아요. http://stackoverflow.com/a/10107525/5870896 –

+0

조회수 2는 어떻습니까?하나는 세로 용이고 다른 하나는 올바른 너비와 높이가있는 가로 용입니다. 방향 변경이 발생하면 관련없는보기를 제거하고 유효한보기를 windowmanager에 추가하십시오. –

+0

@SecretCoder 내 코드가 내 코드를 작성하는 데 사용한 참조 중 하나이기 때문에 내 코드가 이미 해당 질문에 대한 답을 닮았다고 생각합니다. 유일한 차이점은 링크 된 응답은 인플레이레이터를 사용하여 뷰에 대한 참조를 잡는 반면 내 코드는 서비스에서 뷰 인라인의 인스턴스를 구성한다는 것입니다. 나는 그 대답에 필적할만한 코드를 가지고 있고 문제를 경험할 때 : 나는 연결된 문제가 내 질문에 답하지 않고 따라서 같은 문제가 아니라고 말할 것이다. – Birchlabs

답변

1

이전 질문 "How to create always-top fullscreen overlay activity in Android"에 대한 대답으로 잘못 인도되었습니다. 이전 API 수준에서 작동했을 수도 있습니까? 나는 특히 대답이 추천 한 24

그건 API 레벨을 사용하고 있습니다 :

final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
    WindowManager.LayoutParams.FLAG_FULLSCREEN, 
    WindowManager.LayoutParams.FLAG_FULLSCREEN, 
    WindowManager.LayoutParams.TYPE_SYSTEM_ALERT, 
    WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN, 
    PixelFormat.TRANSLUCENT 
); 

이 문제가 있습니다.

enter image description here

는 그래서 WindowManager.LayoutParams.FLAG_FULLSCREEN 플래그가 int wint h에 대한 명시 적 값으로 사용됩니다 다음과 같이 WindowManager.LayoutParams을 위해 존재하는 생성자입니다. 이것은 좋지 않다! 이것은 우리가 더 이상 명시 적으로은 폭과 높이를 지정하는 의미

final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
    WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY, // TYPE_SYSTEM_ALERT is denied in apiLevel >=19 
    WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_FULLSCREEN, 
    PixelFormat.TRANSLUCENT 
); 

:


나는 전체 화면 오버레이에 대한 올바른 건설과 같이 것으로 나타났습니다. 레이아웃은 대신 우리 플래그에 전적으로 의존합니다.

예, WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN은 필수 플래그입니다. 상태 표시 줄과 같은 장식을 그릴 필요가있을 때 필요합니다.

WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY은 API 레벨> = 19에서 TYPE_SYSTEM_ALERT 대신 사용해야합니다.

당신의 다음과 같은 권한이 필요합니다 매니페스트 (설명 here을) :


보너스 노트 (당신이이 글을 읽고 있다면, 당신은 아마 전체 화면 오버레이를 만들려고 노력하고 있습니다)

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

필자의 이해로는 SYSTEM_ALERT_WINDOW이 필요하지만 실제로는 ACTION_MANAGE_OVERLAY_PERMISSION이 필요합니다. 즉, 런타임에 사용자에게 SYSTEM_ALERT_WINDOW 권한을 요청할 수 있습니다.

0

나는 당신의 상황이 다른 접근법으로 해결 될 수 있다고 생각합니다.

  1. 는 전체 화면 사용자 지정보기 만들기 사용자 정의보기에
  2. 재정 onSizeChanged() (당신은 사용자 지정보기의 생성자에서 적절한 플래그를 설정할 수 있습니다). 그러면 캔버스 높이와 너비가 지정됩니다. 이것은 선택 사항입니다. 전체 사용자 정의보기를 반투명 색상으로 채우려면이 작업이 필요하지 않습니다.
  3. 위의 너비와 높이를 사용하거나 사용자 정의보기의 onDraw()에서 canvas.drawColor()을 사용하면됩니다.

이렇게하면보기를 다시 만들 때마다 전체 화면 (캔버스)을 채우도록 다시 그려집니다.

+0

내 전체 캔버스 경계 위에 색을 그리는 것이 내 목표는 ** 아닙니다 ** - 그 상자 만 그렸습니다. 설명의 목적 (내 견해가 회전을 무시하고 치수가 초기 값과 비교하여 업데이트되지 않음을 증명). 그러나 2 단계는 내가 원하는대로 들리므로 시도해 보았습니다. 불행히도 내 view의'onSizeChanged()'는 _only_ 한 번 (시작시 0x0에서 1080x1920으로 변경됨) 트리거됩니다. 장치 회전은 **이 이벤트를 유발하지 않습니다 **. (그리고 내 서비스는 내 매니페스트에서'android : configChanges = "keyboardHidden | orientation | screenSize"'에 가입되어 있습니다.) – Birchlabs

+0

수정안 : 오리엔테이션 변경시'onSizeChanged()'_does_가 발생하지만 레이아웃에 동적 치수가있을 경우 _only_가됩니다. 원래 사용했던'WindowManager.LayoutParams()'구조는 _explicitly_-set dimensions -'WindowManager.LayoutParams.FLAG_FULLSCREEN'가 너비와 높이에 대해 정수 값 1024로 해석되어 결과적으로 뷰의 크기가 변경되지 않았습니다. 그러나'onSizeChanged()'_does_는 [my answer] (http://stackoverflow.com/a/41474994/5257399)의'WindowManager.LayoutParams()'구조와 함께 사용될 경우 트리거됩니다. – Birchlabs

관련 문제