괴도군의 블로그

[android]네이버 퀵메뉴만들기(바탕화면 플로팅버튼) 본문

#프로그래밍/Android

[android]네이버 퀵메뉴만들기(바탕화면 플로팅버튼)

괴도군 2016. 4. 7. 10:04
반응형

안녕하세요 괴도입니다.


오늘은 네이버 퀵메뉴같은 어플종료와 상관없이 떠있는 버튼을 만들어보겠습니다.



프로젝트 구조는 다음과 같습니다.





1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class MainActivity extends AppCompatActivity {
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
    }
 
    @Override
    protected void onResume() {
        super.onResume();
        stopService(new Intent(this, FloatWindow.class));
    }
 
    @Override
    protected void onPause() {
        super.onPause();
 
        startService(new Intent(this, FloatWindow.class));
    }
}
 
 
 
 
 

cs


메인은 별거없습니다.. 화면도 기본화면이고..


앱 종료시나 가운데버튼으로 잠시 내릴때에 서비스 실행하는 코드입니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
public class FloatWindow extends Service {
 
    private Context context;
 
    private boolean flagClick;
    private boolean flagView;
 
    private FloatView testView;
    private View inflateView;
    private WindowManager wm;
    private WindowManager.LayoutParams params;
    private WindowManager.LayoutParams floatWindowParams;
 
    private int start_x;
    private int start_y;
    private int prev_x;
    private int prev_y;
 
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
 
    @Override
    public void onCreate() {
        super.onCreate();
        context = this;
 
        testView = new FloatView(this);
        testView.setOnTouchListener(onTouchListener);
        params = new WindowManager.LayoutParams(
                70,
                70,
                WindowManager.LayoutParams.TYPE_PHONE,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, //터치 인식
                PixelFormat.TRANSLUCENT); //투명
 
        params.gravity = Gravity.LEFT | Gravity.TOP;
        wm = (WindowManager) getSystemService(WINDOW_SERVICE);
        wm.addView(testView, params);
 
        inflateView = View.inflate(this, R.layout.floatwindow, null);
        floatWindowParams = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.TYPE_PHONE,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, //터치 인식
                PixelFormat.TRANSLUCENT); //투명
 
 
    }
 
    private View.OnTouchListener onTouchListener = new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
 
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN: {
                    flagClick = true;
 
                    int x = (int) event.getRawX();
                    int y = (int) event.getRawY();
 
                    start_x = x;
                    start_y = y;
                    prev_x = params.x;
                    prev_y = params.y;
                }
                break;
                case MotionEvent.ACTION_MOVE: {
                    flagClick = false;
                    int x = (int) (event.getRawX() - start_x);    //이동한 거리
                    int y = (int) (event.getRawY() - start_y);    //이동한 거리
                    params.x = prev_x + x;
                    params.y = prev_y + y;
                    wm.updateViewLayout(testView, params);
 
                }
                break;
                case MotionEvent.ACTION_UP: {
                    if (flagClick) {
                        floatWindowParams.x = params.x + 70;
                        floatWindowParams.y = params.y - 50;
                        Log.v("@@@@@@@@@""@@@@@@ floatWindowParams.x: " +
floatWindowParams.x + " floatWindowParams.y: " + floatWindowParams.y);
 
                        inflateView = View.inflate(context, R.layout.floatwindow, null);
                        inflateView.setOnClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                ((WindowManager) getSystemService(WINDOW_SERVICE)).removeView(inflateView);
                                inflateView = null;
                            }
                        });
                        Button btn = (Button) inflateView.findViewById(R.id.btnend);
                        btn.setX(floatWindowParams.x);
                        btn.setY(floatWindowParams.y + 50);
                        btn.setOnClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                onDestroy();
                                if (inflateView != null)      //서비스 종료시 뷰 제거. *중요 : 뷰를 꼭 제거 해야함.
                                {
                                    ((WindowManager) getSystemService(WINDOW_SERVICE)).removeView(inflateView);
                                    inflateView = null;
                                }
                            }
                        });
 
                        Button bt = (Button) inflateView.findViewById(R.id.btn);
                        bt.setX(floatWindowParams.x);
                        bt.setY(floatWindowParams.y);
                        bt.setOnClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                Intent intent = context.getPackageManager().getLaunchIntentForPackage("com.nhn.android.search");
                                if (intent != null) {
                                    context.startActivity(intent);
                                }
                                if (inflateView != null)      //서비스 종료시 뷰 제거. *중요 : 뷰를 꼭 제거 해야함.
                                {
                                    ((WindowManager) getSystemService(WINDOW_SERVICE)).removeView(inflateView);
                                    inflateView = null;
                                }
                            }
                        });
                        wm.addView(inflateView, floatWindowParams);
                        flagView = true;
                    }
                }
            }
            return false;
        }
    };
 
    @Override
    public void onDestroy() {
        super.onDestroy();
        if (testView != null)      //서비스 종료시 뷰 제거. *중요 : 뷰를 꼭 제거 해야함.
        {
            ((WindowManager) getSystemService(WINDOW_SERVICE)).removeView(testView);
            testView = null;
        }
        if (inflateView != null)      //서비스 종료시 뷰 제거. *중요 : 뷰를 꼭 제거 해야함.
        {
            if (flagView) {
                ((WindowManager) getSystemService(WINDOW_SERVICE)).removeView(inflateView);
            }
            inflateView = null;
        }
        stopSelf();
    }
 
 
 

 cs


서비스 클래스 입니다.


 onCreate()시에 View를 생성하고 WindowManager에 addView하는 형식입니다.


터치리스너안에 코드가 더러워서.. 리팩토링이 필요하긴 합니다...


버튼을 누르고 움직일때는 클릭이 아니기때문에 업 이벤트시에 모든걸 처리합니다.


버튼을 눌렀을때 메뉴가 어떻게 나올지 고민을 하다가..


그냥 전체화면 dim처리하고.. 버튼위치로 메뉴위치정해서 옆에 나오게끔 해놨습니다.


그리고 서비스 종료시에는.. 메뉴화면이나 버튼뷰를 삭제시켜야 하기때문에..


onDestroy()에 코드를 넣어놨습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class FloatView extends View {
 
    public FloatView(Context context) {
        super(context);
 
 
    }
 
    public FloatView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
 
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
 
        Paint paint = new Paint();
        paint.setColor(Color.BLUE);
        canvas.drawOval(new RectF(0,0,70,70),paint);
    }
 
}
 
 
 
 
cs


버튼을 만들 뷰는.. 그냥 원하나 그립니다..ㅎㅎ


디자인을 수정하실분은 여기서 하시거나..


xml로 구성하셔서 view추가하시면 될듯합니다.


어디까지나 샘플.. 공부용이기 때문에.. 간단합니다



아참.. 

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

이 권한이 필요한데


target version을 23 (마쉬멜로우)으로 하시면


권한을 받아오는 코드를 해줘야하니..


22 이하로 하시기 바랍니다.


프로젝트도 첨부합니다.


안드로이드 스튜디오 버전입니다.


ttesst.zip









반응형
Comments