안 드 로 이 드 360 데스크 톱 모 바 일 디 스 플레이 창 효과 모방
자신 도 모 르 게 저 는 안 드 로 이 드 를 접 한 지 3 년 이 되 었 습 니 다.그 동안 각종 성장 은 여러분 의 고수 들 의 도움 이 빠 질 수 없 었 습 니 다.항상 많은 고수 들 이 자신의 경험 을 인터넷 에 쓰 고 여러분 들 이 공부 할 수 있 도록 해 주 었 습 니 다.저도 그 중에서 많은 혜택 을 받 았 습 니 다.여기 서 깊 은 감 사 를 드 립 니 다.그러나 저 는 제 가 평소에 느 낀 것 을 여러분 과 나 누고 같이 공부 한 적 이 없다 는 것 을 알 게 되 었 습 니 다.너무 봉사 정신 이 없습니다.그래서 저 는 통 증 을 가 라 앉 히 고 오늘부터 블 로 그 를 쓰기 로 결 정 했 습 니 다.제 뒤에 있 는 개발 자 를 지적 하여 안 드 로 이 드 개발 자의 대열 에 빨리 들 어 갈 수 있 기 를 바 랍 니 다.
자,쓸데없는 말 을 이렇게 많이 하 자.다음은 오늘 의 주제 로 들 어가 자.
360 휴대 전화 위 사 는 많은 사람들 이 휴대 전화 에 이 소프트웨어 를 설치 할 것 이 라 고 믿는다.그러면 우 리 는 그것 의 데스크 톱 부상 창 효과 에 대해 낯 설 지 않 을 것 이다.다음 그림 을 보십시오.
먼저 작은 부상 창 은 현재 몇%의 메모 리 를 사 용 했 는 지 보 여 줍 니 다.작은 부상 창 을 클릭 하면 큰 부상 창 이 나타 나 고 한 번 의 클릭 으로 가속 할 수 있 습 니 다.자,이제 비슷 한 효 과 를 모 의 해 보 자.
기본 적 인 실현 원 리 를 말씀 드 리 겠 습 니 다.이 데스크 톱 부상 창의 효 과 는 Widget 과 유사 하지만 Widget 보다 훨씬 유연 합 니 다.주로 Window Manager 라 는 종 류 를 통 해 이 루어 집 니 다.이 종류의 addView 방법 을 사용 하여 부상 창 을 추가 합 니 다.updateViewLayout 방법 은 부상 창의 인 자 를 업데이트 하 는 데 사 용 됩 니 다.removeView 는 부상 창 을 제거 하 는 데 사 용 됩 니 다.그 중에서 부상 창의 매개 변 수 는 상세 하 게 설명 할 필요 가 있다.
Window Manager.LayoutParams 라 는 종 류 는 부상 창 에 필요 한 인 자 를 제공 하 는 데 사 용 됩 니 다.그 중에서 자주 사용 되 는 변수 가 몇 개 있 습 니 다.
type 값 은 부상 창의 종 류 를 확인 하 는 데 사 용 됩 니 다.일반적으로 2002 로 설정 되 어 있 으 며 모든 프로그램 위 에 있 지만 상태 표시 줄 아래 에 있 습 니 다.
flags 값 은 부상 창의 행동 을 확인 하 는 데 사 용 됩 니 다.예 를 들 어 초점 을 맞 출 수 없고 비 모드 대화 상자 등 속성 이 매우 많 습 니 다.문 서 를 볼 수 있 습 니 다.
gravity 값 은 부상 창의 정렬 방식 을 확정 하 는 데 사용 되 며,일반적으로 왼쪽 상단 을 정렬 하 는 것 으로 설정 되 어 있 으 며,이렇게 하면 부상 창 을 드래그 할 때 좌 표를 계산 하기에 편리 하 다.
x 값 은 부상 창의 위 치 를 확인 하 는 데 사 용 됩 니 다.부상 창 을 가로로 이동 하려 면 이 값 을 바 꿔 야 합 니 다.
y 값 은 부상 창의 위 치 를 확인 하 는 데 사 용 됩 니 다.부상 창 을 세로 로 이동 하려 면 이 값 을 바 꿔 야 합 니 다.
width 값 은 부상 창의 폭 을 지정 하 는 데 사 용 됩 니 다.
height 값 은 부상 창의 높이 를 지정 하 는 데 사 용 됩 니 다.
이 창 을 만 들 려 면 사용자 에 게 권한 을 신청 해 야 하기 때문에 AndroidManifest.xml 에 추가 해 야 합 니 다.
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
원 리 를 소 개 했 으 니 다음은 코드 로 실현 하 겠 습 니 다.우선 Eclipse 에 안 드 로 이 드 프로젝트 를 새로 만 듭 니 다.프로젝트 이름 은 360 Float Window Demo 입 니 다.그리고 레이아웃 파일 을 쓰 세 요.레이아웃 파일 은 매우 간단 합 니 다.단 하나의 버튼 만 있 습 니 다.열 거나 새 activitymain.xml,다음 코드 추가:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
tools:context=".MainActivity" >
<Button
android:id="@+id/start_float_window"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Start Float Window" >
</Button>
</RelativeLayout>
그리고 플 로 트 라 는 이름 을 새로 만 듭 니 다.window_small.xml 의 레이아웃 파일 은 작은 부상 창의 레이아웃 으로 사용 되 며,다음 코드 를 추가 합 니 다:
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/small_window_layout"
android:layout_width="60dip"
android:layout_height="25dip"
android:background="@drawable/bg_small"
>
<TextView
android:id="@+id/percent"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center"
android:textColor="#ffffff"
/>
</LinearLayout>
플 로 트 라 는 이름 을 새로 만 듭 니 다.window_big.xml 의 레이아웃 파일 은 큰 부상 창의 레이아웃 으로 사용 되 며,다음 코드 를 추가 합 니 다:
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/big_window_layout"
android:layout_width="200dip"
android:layout_height="100dip"
android:background="@drawable/bg_big"
android:orientation="vertical"
>
<Button
android:id="@+id/close"
android:layout_width="100dip"
android:layout_height="40dip"
android:layout_gravity="center_horizontal"
android:layout_marginTop="12dip"
android:text=" "
/>
<Button
android:id="@+id/back"
android:layout_width="100dip"
android:layout_height="40dip"
android:layout_gravity="center_horizontal"
android:text=" "
/>
</LinearLayout>
두 개의 부상 창 레이아웃 파일 에 사용 되 는 그림 자원 은 여러분 이 마음대로 그림 을 찾 아서 대체 할 수 있 습 니 다.그리고 저 는 소스 코드 를 드릴 것 입 니 다.여러분 도 소스 코드 에서 꺼 낼 수 있 습 니 다.그리고 MainActivity 를 열거 나 만 듭 니 다.이것 은 프로젝트 의 메 인 인터페이스 입 니 다.
다음 코드 를 추가 합 니 다:
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button startFloatWindow = (Button) findViewById(R.id.start_float_window);
startFloatWindow.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
Intent intent = new Intent(MainActivity.this, FloatWindowService.class);
startService(intent);
finish();
}
});
}
}
여기에서 볼 수 있 듯 이 MainActivity 의 코드 는 창 이 아 닌 간단 합 니 다.바로 부상 창 을 여 는 버튼 에 클릭 이 벤트 를 등록 하여 서 비 스 를 열 고 현재 Activity 를 닫 는 것 입 니 다.부상 창 을 만 드 는 논 리 는 모두 서비스 에 맡 겼 다.자,이제 이 서 비 스 를 만 들 겠 습 니 다.Float Window Service 라 는 클래스 를 새로 만 듭 니 다.이 클래스 는 Service 에서 계승 합 니 다.다음 코드 를 추가 합 니 다:
public class FloatWindowService extends Service {
/**
* 。
*/
private Handler handler = new Handler();
/**
* , 。
*/
private Timer timer;
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// , 0.5
if (timer == null) {
timer = new Timer();
timer.scheduleAtFixedRate(new RefreshTask(), 0, 500);
}
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
// Service
timer.cancel();
timer = null;
}
class RefreshTask extends TimerTask {
@Override
public void run() {
// , , 。
if (isHome() && !MyWindowManager.isWindowShowing()) {
handler.post(new Runnable() {
@Override
public void run() {
MyWindowManager.createSmallWindow(getApplicationContext());
}
});
}
// , , 。
else if (!isHome() && MyWindowManager.isWindowShowing()) {
handler.post(new Runnable() {
@Override
public void run() {
MyWindowManager.removeSmallWindow(getApplicationContext());
MyWindowManager.removeBigWindow(getApplicationContext());
}
});
}
// , , 。
else if (isHome() && MyWindowManager.isWindowShowing()) {
handler.post(new Runnable() {
@Override
public void run() {
MyWindowManager.updateUsedPercent(getApplicationContext());
}
});
}
}
}
/**
*
*/
private boolean isHome() {
ActivityManager mActivityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
List<RunningTaskInfo> rti = mActivityManager.getRunningTasks(1);
return getHomes().contains(rti.get(0).topActivity.getPackageName());
}
/**
*
*
* @return
*/
private List<String> getHomes() {
List<String> names = new ArrayList<String>();
PackageManager packageManager = this.getPackageManager();
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
List<ResolveInfo> resolveInfo = packageManager.queryIntentActivities(intent,
PackageManager.MATCH_DEFAULT_ONLY);
for (ResolveInfo ri : resolveInfo) {
names.add(ri.activityInfo.packageName);
}
return names;
}
}
Float Window Service 의 onStart Command 방법 에서 타 이 머 를 켜 면 500 밀리초 마다 Refresh Task 를 실행 합 니 다.RefreshTask 에서 판단 을 하려 면 핸드폰 이 현재 데스크 톱 에 있다 면 부상 창 을 표시 해 야 한다.만약 에 핸드폰 이 어떤 프로그램 을 열 었 다 면 부상 창 을 제거 해 야 한다.만약 에 핸드폰 이 데스크 톱 에 있다 면 메모리 사용 백분율 의 데 이 터 를 업데이트 해 야 한다.Float Window Service 가 소각 되 었 을 때 타 이 머 를 멈 춰 야 합 니 다.그렇지 않 으 면 계속 실 행 될 것 입 니 다.위의 코드 를 통 해 알 수 있 듯 이 부상 창 을 만 들 고 제거 하 며 부상 창 에 있 는 데 이 터 를 업데이트 하 는 것 은 모두 MyWindow Manager 와 같은 종류 로 관리 하 는 것 입 니 다.이 코드 를 Activity 나 Service 에 직접 쓰 는 것 보다 전문 적 인 도구 류 를 사용 하여 관리 하 는 것 이 좋 습 니 다.그러나 부상 창 을 만 들 려 면 먼저 부상 창의 View 를 써 야 한다.
Float Window SmallView 라 는 클래스 를 새로 만 들 고 LinearLayout 에서 계승 합 니 다.Float Window BigView 라 는 클래스 를 새로 만 들 고 LinearLayout 에서 도 계승 합 니 다.
Float Window SmallView 에 다음 코드 를 추가 합 니 다.
public class FloatWindowSmallView extends LinearLayout {
/**
*
*/
public static int viewWidth;
/**
*
*/
public static int viewHeight;
/**
*
*/
private static int statusBarHeight;
/**
*
*/
private WindowManager windowManager;
/**
*
*/
private WindowManager.LayoutParams mParams;
/**
*
*/
private float xInScreen;
/**
*
*/
private float yInScreen;
/**
*
*/
private float xDownInScreen;
/**
*
*/
private float yDownInScreen;
/**
* View
*/
private float xInView;
/**
* View
*/
private float yInView;
public FloatWindowSmallView(Context context) {
super(context);
windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
LayoutInflater.from(context).inflate(R.layout.float_window_small, this);
View view = findViewById(R.id.small_window_layout);
viewWidth = view.getLayoutParams().width;
viewHeight = view.getLayoutParams().height;
TextView percentView = (TextView) findViewById(R.id.percent);
percentView.setText(MyWindowManager.getUsedPercentValue(context));
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// ,
xInView = event.getX();
yInView = event.getY();
xDownInScreen = event.getRawX();
yDownInScreen = event.getRawY() - getStatusBarHeight();
xInScreen = event.getRawX();
yInScreen = event.getRawY() - getStatusBarHeight();
break;
case MotionEvent.ACTION_MOVE:
xInScreen = event.getRawX();
yInScreen = event.getRawY() - getStatusBarHeight();
//
updateViewPosition();
break;
case MotionEvent.ACTION_UP:
// ,xDownInScreen xInScreen , yDownInScreen yInScreen , 。
if (xDownInScreen == xInScreen && yDownInScreen == yInScreen) {
openBigWindow();
}
break;
default:
break;
}
return true;
}
/**
* , 。
*
* @param params
*
*/
public void setParams(WindowManager.LayoutParams params) {
mParams = params;
}
/**
* 。
*/
private void updateViewPosition() {
mParams.x = (int) (xInScreen - xInView);
mParams.y = (int) (yInScreen - yInView);
windowManager.updateViewLayout(this, mParams);
}
/**
* , 。
*/
private void openBigWindow() {
MyWindowManager.createBigWindow(getContext());
MyWindowManager.removeSmallWindow(getContext());
}
/**
* 。
*
* @return 。
*/
private int getStatusBarHeight() {
if (statusBarHeight == 0) {
try {
Class<?> c = Class.forName("com.android.internal.R$dimen");
Object o = c.newInstance();
Field field = c.getField("status_bar_height");
int x = (Integer) field.get(o);
statusBarHeight = getResources().getDimensionPixelSize(x);
} catch (Exception e) {
e.printStackTrace();
}
}
return statusBarHeight;
}
그 중에서 이 View 의 onTouchEvent 이 벤트 를 다시 써 서 드래그 와 클릭 효 과 를 실현 합 니 다.사용자 가 ACTION 을 촉발 한 것 을 발견 하면DOWN 이벤트,눌 렀 을 때의 좌표 등 데 이 터 를 기록 합 니 다.사용자 가 ACTION 을 촉발 한 것 을 발견 하면MOVE 이 벤트 는 현재 이동 하 는 좌표 에 따라 화면 에 떠 있 는 창 위 치 를 업데이트 합 니 다.사용자 가 ACTION 을 촉발 한 것 을 발견 하면UP 이벤트,ACTIONDOWN 에 기 록 된 좌표 대 비 는 동일 한 것 을 발견 하면 사용자 가 부상 창 을 클릭 한 것 으로 간주한다.작은 부상 창 을 클릭 하면 큰 부상 창 을 열 고 큰 부상 창의 View 를 실현 합 니 다.Float Window BigView 에 다음 코드 를 추가 합 니 다.
public class FloatWindowBigView extends LinearLayout {
/**
*
*/
public static int viewWidth;
/**
*
*/
public static int viewHeight;
public FloatWindowBigView(final Context context) {
super(context);
LayoutInflater.from(context).inflate(R.layout.float_window_big, this);
View view = findViewById(R.id.big_window_layout);
viewWidth = view.getLayoutParams().width;
viewHeight = view.getLayoutParams().height;
Button close = (Button) findViewById(R.id.close);
Button back = (Button) findViewById(R.id.back);
close.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// , , Service
MyWindowManager.removeBigWindow(context);
MyWindowManager.removeSmallWindow(context);
Intent intent = new Intent(getContext(), FloatWindowService.class);
context.stopService(intent);
}
});
back.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// , ,
MyWindowManager.removeBigWindow(context);
MyWindowManager.createSmallWindow(context);
}
});
}
}
Float Window SmallView 보다 Float Window BigView 는 두 개의 버튼 만 있 고 close 단 추 를 누 르 면 부상 창 을 모두 제거 하고 Service 를 종료 합 니 다.back 단 추 를 누 르 면 큰 부상 창 을 제거 하고 작은 부상 창 을 다시 만 듭 니 다.현재 두 개의 부상 창의 View 가 모두 작성 되 었 습 니 다.MyWindow Manager 를 만 들 겠 습 니 다.
코드 는 다음 과 같 습 니 다:
public class MyWindowManager {
/**
* View
*/
private static FloatWindowSmallView smallWindow;
/**
* View
*/
private static FloatWindowBigView bigWindow;
/**
* View
*/
private static LayoutParams smallWindowParams;
/**
* View
*/
private static LayoutParams bigWindowParams;
/**
*
*/
private static WindowManager mWindowManager;
/**
*
*/
private static ActivityManager mActivityManager;
/**
* 。 。
*
* @param context
* Context.
*/
public static void createSmallWindow(Context context) {
WindowManager windowManager = getWindowManager(context);
int screenWidth = windowManager.getDefaultDisplay().getWidth();
int screenHeight = windowManager.getDefaultDisplay().getHeight();
if (smallWindow == null) {
smallWindow = new FloatWindowSmallView(context);
if (smallWindowParams == null) {
smallWindowParams = new LayoutParams();
smallWindowParams.type = LayoutParams.TYPE_PHONE;
smallWindowParams.format = PixelFormat.RGBA_8888;
smallWindowParams.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL
| LayoutParams.FLAG_NOT_FOCUSABLE;
smallWindowParams.gravity = Gravity.LEFT | Gravity.TOP;
smallWindowParams.width = FloatWindowSmallView.viewWidth;
smallWindowParams.height = FloatWindowSmallView.viewHeight;
smallWindowParams.x = screenWidth;
smallWindowParams.y = screenHeight / 2;
}
smallWindow.setParams(smallWindowParams);
windowManager.addView(smallWindow, smallWindowParams);
}
}
/**
* 。
*
* @param context
* Context.
*/
public static void removeSmallWindow(Context context) {
if (smallWindow != null) {
WindowManager windowManager = getWindowManager(context);
windowManager.removeView(smallWindow);
smallWindow = null;
}
}
/**
* 。 。
*
* @param context
* Context.
*/
public static void createBigWindow(Context context) {
WindowManager windowManager = getWindowManager(context);
int screenWidth = windowManager.getDefaultDisplay().getWidth();
int screenHeight = windowManager.getDefaultDisplay().getHeight();
if (bigWindow == null) {
bigWindow = new FloatWindowBigView(context);
if (bigWindowParams == null) {
bigWindowParams = new LayoutParams();
bigWindowParams.x = screenWidth / 2 - FloatWindowBigView.viewWidth / 2;
bigWindowParams.y = screenHeight / 2 - FloatWindowBigView.viewHeight / 2;
bigWindowParams.type = LayoutParams.TYPE_PHONE;
bigWindowParams.format = PixelFormat.RGBA_8888;
bigWindowParams.gravity = Gravity.LEFT | Gravity.TOP;
bigWindowParams.width = FloatWindowBigView.viewWidth;
bigWindowParams.height = FloatWindowBigView.viewHeight;
}
windowManager.addView(bigWindow, bigWindowParams);
}
}
/**
* 。
*
* @param context
* Context.
*/
public static void removeBigWindow(Context context) {
if (bigWindow != null) {
WindowManager windowManager = getWindowManager(context);
windowManager.removeView(bigWindow);
bigWindow = null;
}
}
/**
* TextView , 。
*
* @param context
* 。
*/
public static void updateUsedPercent(Context context) {
if (smallWindow != null) {
TextView percentView = (TextView) smallWindow.findViewById(R.id.percent);
percentView.setText(getUsedPercentValue(context));
}
}
/**
* ( ) 。
*
* @return true, false。
*/
public static boolean isWindowShowing() {
return smallWindow != null || bigWindow != null;
}
/**
* WindowManager , WindowManager 。 WindowManager。
*
* @param context
* Context.
* @return WindowManager , 。
*/
private static WindowManager getWindowManager(Context context) {
if (mWindowManager == null) {
mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
}
return mWindowManager;
}
/**
* ActivityManager , ActivityManager 。 ActivityManager。
*
* @param context
* 。
* @return ActivityManager , 。
*/
private static ActivityManager getActivityManager(Context context) {
if (mActivityManager == null) {
mActivityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
}
return mActivityManager;
}
/**
* , 。
*
* @param context
* 。
* @return , 。
*/
public static String getUsedPercentValue(Context context) {
String dir = "/proc/meminfo";
try {
FileReader fr = new FileReader(dir);
BufferedReader br = new BufferedReader(fr, 2048);
String memoryLine = br.readLine();
String subMemoryLine = memoryLine.substring(memoryLine.indexOf("MemTotal:"));
br.close();
long totalMemorySize = Integer.parseInt(subMemoryLine.replaceAll("\\D+", ""));
long availableSize = getAvailableMemory(context) / 1024;
int percent = (int) ((totalMemorySize - availableSize) / (float) totalMemorySize * 100);
return percent + "%";
} catch (IOException e) {
e.printStackTrace();
}
return " ";
}
/**
* , 。
*
* @param context
* 。
* @return 。
*/
private static long getAvailableMemory(Context context) {
ActivityManager.MemoryInfo mi = new ActivityManager.MemoryInfo();
getActivityManager(context).getMemoryInfo(mi);
return mi.availMem;
}
}
이 종 류 는 큰 부상 창 을 제어 하고 작은 부상 창의 생 성과 제거,시스템 메모리 사용 백분율 의 계산 등 을 책임 진다.여기까지 기본 적 인 모든 코드 를 다 썼 습 니 다.그리고 AndroidManifest.xml 파일 을 살 펴 보 겠 습 니 다.
내부 코드 는 다음 과 같 습 니 다.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.demo.floatwindowdemo"
android:versionCode="1"
android:versionName="1.0" >
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="8" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.demo.floatwindowdemo.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".FloatWindowService"></service>
</application>
</manifest>
간단 합 니 다.Activity 와 Service 를 안에 등록 하고 추가 해 야 할 권한 성명 도 있 습 니 다android.permission.SYSTEM_ALERT_WINDOW
사용자 권한 이 필요 하 다 는 것 은 시스템 알림 창,즉 데스크 톱 부상 창 을 만 들 수 있 도록 해 야 한 다 는 것 을 의미 합 니 다.자,이제 프로젝트 를 실행 합 시다.효 과 는 다음 그림 과 같 습 니 다.메 인 화면 에는 간단 한 버튼 만 있 습 니 다.단 추 를 누 르 면 Activity 가 닫 히 고 작은 부상 창 이 데스크 톱 에 표 시 됩 니 다.현재 메모리 에 사용 되 는 백분율 을 표시 합 니 다.
작은 부상 창 은 자 유 롭 게 끌 수 있 습 니 다.다른 프로그램 을 열 면 작은 부상 창 이 자동 으로 숨겨 지고 데스크 톱 으로 돌아 가면 작은 부상 창 이 표 시 됩 니 다.
작은 부상 창 을 누 르 면 큰 부상 창 이 튀 어 나 옵 니 다.여기 서 우리 의 큰 부상 창 은 비교적 간단하게 만 들 수 있 습 니 다.단 두 개의 버튼 만 있 습 니 다.큰 부상 창 이 전 시 될 때 휴대 전화의 모든 다른 프로그램 은 점 을 찍 을 수 없다.왜냐하면 초점 이 부상 창 에 있 기 때문이다.되 돌아 가기 단 추 를 누 르 면 작은 부상 창 을 다시 보 여주 고 부상 창 닫 기 단 추 를 누 르 면 Service 도 함께 멈춘다.
360 핸드폰 가 디 언 의 원 클릭 가속 기능 은 하지 않 겠 습 니 다.독고 구 검 처럼 중요 한 것 은 검 의 의미 가 아니 라 검 의 의미 입 니 다.저 는 여러분 들 이 부상 창 을 만 드 는 기본 원 리 를 배 워 서 360 보다 더 창의 적 인 것 을 만 들 수 있 을 것 이 라 고 믿 습 니 다.
질문 이 있 으 시 면 아래 에 메 시 지 를 남 겨 주세요.
데스크 톱 부상 창 에 관심 이 있 는 친 구 는 계속 읽 을 수 있 습 니 다.
안 드 로 이 드 데스크 톱 부상 창 진급
보충:친구 가 저 에 게 반응 을 했 습 니 다.위의 코드 가 안 드 로 이 드 3.0 이상 의 시스템 에서 실 행 될 때 무 너 질 것 입 니 다.제 가 봤 는데 그렇습니다.주로 3.0 이후 에 실행 중인 작업 을 얻 으 려 면 권한 성명 을 추가 해 야 합 니 다.AndroidManifest.xml 에 추가
<uses-permission android:name="android.permission.GET_TASKS" />
이 문 제 를 해결 할 수 있다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Kotlin의 기초 - 2부지난 글에서는 Kotlin이 무엇인지, Kotlin의 특징, Kotlin에서 변수 및 데이터 유형을 선언하는 방법과 같은 Kotlin의 기본 개념에 대해 배웠습니다. 유형 변환은 데이터 변수의 한 유형을 다른 데이터...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.