android 9.0 launcher3 去掉抽屜式顯示所有 app(代碼詳解)
效果圖
修改思路
1、增加全局控制變量 sys.launcher3.is_full_app,用來(lái)動(dòng)態(tài)切換
2、增加兩套布局,對(duì)應(yīng)有抽屜和無(wú)抽屜
3、去除 allAppsButton
4、將 AllAppsContainerView 中的圖標(biāo)加載到 Workspace
5、新安裝的 app 自動(dòng)添加圖標(biāo)到 Workspace
6、替換 Workspace 圖標(biāo)長(zhǎng)按刪除選項(xiàng)為取消
7、屏蔽上拉顯示抽屜頁(yè)面手勢(shì)
8、修改頁(yè)面指示線為圓點(diǎn)
上代碼
1、增加全局控制變量 sys.launcher3.is_full_app
1) 在 LauncherAppState 中增加靜態(tài)方法 isDisableAllApps(), 通過(guò)修改 Settings 中自定義的值 sys.launcher3.is_full_app
vendor\mediatek\proprietary\packages\apps\Launcher3\src\com\android\launcher3\LauncherAppState.java
private static Context mContext;
public static boolean isDisableAllApps() {
if (mContext != null) {
return Settings.System.getInt(mContext.getContentResolver(),
"sys.launcher3.is_full_app", 0) == 1;
}
return true;
}
vendor\mediatek\proprietary\packages\apps\Launcher3\AndroidManifest-common.xml
2) AndroidManifest-common.xml 中增加權(quán)限
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
3) 在 SettingsActivity 中增加 SwitchPreference 用以動(dòng)態(tài)修改 sys.launcher3.is_full_app
vendor\mediatek\proprietary\packages\apps\Launcher3\src\com\android\launcher3\SettingsActivity.java
在內(nèi)部類(lèi) LauncherSettingsFragment 中重寫(xiě) onPreferenceTreeClick() 用以監(jiān)聽(tīng) SwitchPreference 點(diǎn)擊
/**
* This fragment shows the launcher preferences.
*/
public static class LauncherSettingsFragment extends PreferenceFragment {
.....
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
....
//讀取保存的值,初始化 SwitchPreference 的初始狀態(tài),是否選中
int isFull = Settings.System.getInt(getActivity().getContentResolver(),
"sys.launcher3.is_full_app", 0);
Log.d("Launcher3", "sys.launcher3.is_full_app="+isFull);
SwitchPreference fullSwitch = (SwitchPreference) findPreference("pref_is_full_app");
fullSwitch.setChecked(isFull==1);
}
//add for change is_full_app value
@Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
boolean result = true;
final String key = preference.getKey();
if ("pref_is_full_app".equals(key)) {
boolean checked = ((SwitchPreference) preference).isChecked();
Settings.System.putInt(getActivity().getContentResolver(), "sys.launcher3.is_full_app",
checked ? 1 : 0);
Log.e("Launcher3", "SwitchPreference checked="+checked);
// Value has changed
ProgressDialog.show(getActivity(),
null /* title */,
getActivity().getString(R.string.full_app_override_progress),
true /* indeterminate */,
false /* cancelable */);
new LooperExecutor(LauncherModel.getWorkerLooper()).execute(
new OverrideApplyHandler(getActivity()));
}
return result;
}
}
點(diǎn)擊 SwitchPreference 后需要保存 sys.launcher3.is_full_app 新值,同時(shí)清除 Launcher3 的緩存,延時(shí)啟動(dòng)并結(jié)束當(dāng)前進(jìn)程
清除緩存方法 clearApplicationUserData 在 Launcher3 中編譯報(bào)錯(cuò),所以通過(guò)發(fā)送廣播到 Setting 中進(jìn)行真正的清緩存操作
//add for change is_full_app value
private static class OverrideApplyHandler implements Runnable {
private final Context mContext;
private OverrideApplyHandler(Context context) {
mContext = context;
}
@Override
public void run() {
// Clear the icon cache.
LauncherAppState.getInstance(mContext).getIconCache().clear();
// Wait for it
try {
Thread.sleep(1000);
} catch (Exception e) {
Log.e("Launcher3", "Error waiting", e);
}
// Schedule an alarm before we kill ourself.
Intent homeIntent = new Intent(Intent.ACTION_MAIN)
.addCategory(Intent.CATEGORY_HOME)
.setPackage(mContext.getPackageName())
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pi = PendingIntent.getActivity(mContext, 42,
homeIntent, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
mContext.getSystemService(AlarmManager.class).setExact(
AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + 50, pi);
//clear data will kill process
Intent intent = new Intent("com.android.action.CLEAR_APP_DATA");
intent.putExtra("pkgName", "com.android.launcher3");
intent.addFlags(0x01000000);
mContext.sendBroadcast(intent);
Log.i("Launcher3", "Clearing user data com.android.launcher3");
// Kill process
android.os.Process.killProcess(android.os.Process.myPid());
}
}
4) SettingsActivity 對(duì)應(yīng)的 xml 文件修改 launcher_preferences
vendor\mediatek\proprietary\packages\apps\Launcher3\res\xml\launcher_preferences.xml
<SwitchPreference android:key="pref_is_full_app" android:title="@string/is_full_app_title" android:summary="@string/is_full_app_desc" android:defaultValue="false" android:persistent="true" />
對(duì)應(yīng)的 string 文件就不貼了,自己增加下就行
2、增加兩套布局,對(duì)應(yīng)有抽屜和無(wú)抽屜
加載布局文件對(duì)應(yīng)的 xml 為 vendor\mediatek\proprietary\packages\apps\Launcher3\res\xml\device_profiles.xml
Launcher3 通過(guò)獲取 minWidthDps 和 minHeightDps 來(lái)確定加載哪一個(gè) profile,我的平板分辨率是 1280*800 的,增加兩個(gè) profile 節(jié)點(diǎn)
<profile launcher:name="Tablet" launcher:minWidthDps="376" launcher:minHeightDps="586" launcher:numRows="4" launcher:numColumns="5" launcher:numFolderRows="4" launcher:numFolderColumns="5" launcher:iconSize="50" launcher:iconTextSize="11" launcher:numHotseatIcons="5" launcher:defaultLayoutId="@xml/default_workspace_tb_5x6" /> <profile launcher:name="Tablet_no_all_app" launcher:minWidthDps="380" launcher:minHeightDps="590" launcher:numRows="4" launcher:numColumns="5" launcher:numFolderRows="4" launcher:numFolderColumns="5" launcher:iconSize="50" launcher:iconTextSize="11" launcher:numHotseatIcons="4" launcher:defaultLayoutId="@xml/default_workspace_tb_5x6_no_all_app" />
對(duì)應(yīng)的你需要在 xml 文件下增加 4 個(gè)文件,分別是 default_workspace_tb_5x6.xml dw_hotseat_tb.xml default_workspace_tb_5x6_no_all_app.xml dw_hotseat_tb_no_all_app.xml
這樣的好處是你可以自定義不同的布局文件加載內(nèi)容,上面的配置含義簡(jiǎn)單說(shuō)一下,分別是最小寬度、最小高度、布局的行和列、文件夾中布局行和列、圖標(biāo)大小、圖標(biāo)文字大小、HotSeat 個(gè)數(shù),加載的布局文件
在 InvariantDeviceProfile() 判斷是否需要加載 Tablet_no_all_app profile
vendor\mediatek\proprietary\packages\apps\Launcher3\src\com\android\launcher3\InvariantDeviceProfile.java
public InvariantDeviceProfile(Context context) {
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
DisplayMetrics dm = new DisplayMetrics();
display.getMetrics(dm);
Point smallestSize = new Point();
Point largestSize = new Point();
display.getCurrentSizeRange(smallestSize, largestSize);
// This guarantees that width < height
minWidthDps = Utilities.dpiFromPx(Math.min(smallestSize.x, smallestSize.y), dm);
minHeightDps = Utilities.dpiFromPx(Math.min(largestSize.x, largestSize.y), dm);
Log.i("Launcher3.profiles", "orignalminWidthDps="+minWidthDps + " orignalminHeightDps="+minHeightDps);
//add for load no_all_app xml
if (LauncherAppState.isDisableAllApps()) {
Log.e("Launcher3.profiles", "load no all app profiles");
//對(duì)應(yīng) device_profiles.xml 中 Tablet_no_all_app 的值
minWidthDps = 380.0f;
minHeightDps = 590.0f;
}
.....
}
3、去除 allAppsButton
vendor\mediatek\proprietary\packages\apps\Launcher3\src\com\android\launcher3\Hotseat.java
將 resetLayout() 中 FeatureFlags.NO_ALL_APPS_ICON 替換為 LauncherAppState.isDisableAllApps()
void resetLayout(boolean hasVerticalHotseat) {
mContent.removeAllViewsInLayout();
mHasVerticalHotseat = hasVerticalHotseat;
InvariantDeviceProfile idp = mLauncher.getDeviceProfile().inv;
if (hasVerticalHotseat) {
mContent.setGridSize(1, idp.numHotseatIcons);
} else {
mContent.setGridSize(idp.numHotseatIcons, 1);
}
//if (!FeatureFlags.NO_ALL_APPS_ICON) {
/// add for check is need allappbutton
if (!LauncherAppState.isDisableAllApps()) {
// Add the Apps button
Context context = getContext();
DeviceProfile grid = mLauncher.getDeviceProfile();
...
}
4、將 AllAppsContainerView 中的圖標(biāo)加載到 Workspace
vendor\mediatek\proprietary\packages\apps\Launcher3\src\com\android\launcher3\model\LoaderTask.java
run() 中增加判斷,添加 verifyApplications(), 修改 InstallShortcutReceiver 中 PendingInstallShortcutInfo 為 public
public void run() {
synchronized (this) {
// Skip fast if we are already stopped.
if (mStopped) {
return;
}
}
....
// second step
TraceHelper.partitionSection(TAG, "step 2.1: loading all apps");
loadAllApps();
//add for load all app on workspace
if (LauncherAppState.isDisableAllApps()) {
android.util.Log.e("Launcher3", "verifyApplications()");
verifyApplications();
}
....
}
//add for load all app on workspace
private void verifyApplications() {
final Context context = mApp.getContext();
ArrayList<Pair<ItemInfo, Object>> installQueue = new ArrayList<>();
final List<UserHandle> profiles = mUserManager.getUserProfiles();
for (UserHandle user : profiles) {
final List<LauncherActivityInfo> apps = mLauncherApps.getActivityList(null, user);
ArrayList<InstallShortcutReceiver.PendingInstallShortcutInfo> added = new ArrayList<InstallShortcutReceiver.PendingInstallShortcutInfo>();
synchronized (this) {
for (LauncherActivityInfo app : apps) {
InstallShortcutReceiver.PendingInstallShortcutInfo pendingInstallShortcutInfo = new InstallShortcutReceiver.PendingInstallShortcutInfo(app, context);
added.add(pendingInstallShortcutInfo);
installQueue.add(pendingInstallShortcutInfo.getItemInfo());
}
}
if (!added.isEmpty()) {
mApp.getModel().addAndBindAddedWorkspaceItems(installQueue);
}
}
}
vendor\mediatek\proprietary\packages\apps\Launcher3\src\com\android\launcher3\model\BaseModelUpdateTask.java
注釋 run() 中的 return
@Override
public final void run() {
if (!mModel.isModelLoaded()) {
if (DEBUG_TASKS) {
Log.d(TAG, "Ignoring model task since loader is pending=" + this);
}
// Loader has not yet run.
//annotaion for load all app on workspace
// return;
}
execute(mApp, mDataModel, mAllAppsList);
}
5、新安裝的 app 自動(dòng)添加圖標(biāo)到 Workspace
vendor\mediatek\proprietary\packages\apps\Launcher3\src\com\android\launcher3\model\PackageUpdatedTask.java
execute() 中增加判斷,添加 updateToWorkSpace()
public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList appsList) {
....
final ArrayList<AppInfo> addedOrModified = new ArrayList<>();
addedOrModified.addAll(appsList.added);
//add for load new install app on workspace
if (LauncherAppState.isDisableAllApps()) {
android.util.Log.e("cczLauncher3", "updateToWorkSpace()");
updateToWorkSpace(context, app, appsList);
}
...
}
//add for load new install app on workspace
public void updateToWorkSpace(Context context, LauncherAppState app , AllAppsList appsList){
ArrayList<Pair<ItemInfo, Object>> installQueue = new ArrayList<>();
final List<UserHandle> profiles = UserManagerCompat.getInstance(context).getUserProfiles();
ArrayList<InstallShortcutReceiver.PendingInstallShortcutInfo> added
= new ArrayList<InstallShortcutReceiver.PendingInstallShortcutInfo>();
for (UserHandle user : profiles) {
final List<LauncherActivityInfo> apps = LauncherAppsCompat.getInstance(context).getActivityList(null, user);
synchronized (this) {
for (LauncherActivityInfo info : apps) {
for (AppInfo appInfo : appsList.added) {
if(info.getComponentName().equals(appInfo.componentName)){
InstallShortcutReceiver.PendingInstallShortcutInfo mPendingInstallShortcutInfo
= new InstallShortcutReceiver.PendingInstallShortcutInfo(info,context);
added.add(mPendingInstallShortcutInfo);
installQueue.add(mPendingInstallShortcutInfo.getItemInfo());
}
}
}
}
}
if (!added.isEmpty()) {
app.getModel().addAndBindAddedWorkspaceItems(installQueue);
}
}
6、替換 Workspace 圖標(biāo)長(zhǎng)按刪除選項(xiàng)為取消
vendor\mediatek\proprietary\packages\apps\Launcher3\src\com\android\launcher3\DeleteDropTarget.java
在 setTextBasedOnDragSource() 、setControlTypeBasedOnDragSource()、onAccessibilityDrop() 中分別增加判斷是否需要?jiǎng)h除圖標(biāo)
private void setTextBasedOnDragSource(ItemInfo item) {
if (!TextUtils.isEmpty(mText)) {
mText = getResources().getString(item.id != ItemInfo.NO_ID
? R.string.remove_drop_target_label
: android.R.string.cancel);
//add for hide deletedroptarget
if (LauncherAppState.isDisableAllApps()) {
android.util.Log.e("Launcher3", "hide delete drop target");
mText = getResources().getString(isCanDrop(item)
? R.string.remove_drop_target_label
: android.R.string.cancel);
}
requestLayout();
}
}
private void setControlTypeBasedOnDragSource(ItemInfo item) {
mControlType = item.id != ItemInfo.NO_ID ? ControlType.REMOVE_TARGET
: ControlType.CANCEL_TARGET;
//add for hide deletedroptarget [S]
if (LauncherAppState.isDisableAllApps()) {
mControlType = isCanDrop(item) ? ControlType.REMOVE_TARGET
: ControlType.CANCEL_TARGET;
}
}
public void onAccessibilityDrop(View view, ItemInfo item) {
// Remove the item from launcher and the db, we can ignore the containerInfo in this call
// because we already remove the drag view from the folder (if the drag originated from
// a folder) in Folder.beginDrag()
//add if juge is need remove item from workspace
if (!LauncherAppState.isDisableAllApps() || isCanDrop(item)) {
mLauncher.removeItem(view, item, true /* deleteFromDb */);
mLauncher.getWorkspace().stripEmptyScreens();
mLauncher.getDragLayer()
.announceForAccessibility(getContext().getString(R.string.item_removed));
}
}
private boolean isCanDrop(ItemInfo item){
return !(item.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
item.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER);
}
vendor\mediatek\proprietary\packages\apps\Launcher3\src\com\android\launcher3\dragndrop\DragController.java
drop() 中增加判斷,取消當(dāng)前拖拽操作
private void drop(DropTarget dropTarget, Runnable flingAnimation) {
....
boolean accepted = false;
if (dropTarget != null) {
dropTarget.onDragExit(mDragObject);
if (dropTarget.acceptDrop(mDragObject)) {
if (flingAnimation != null) {
flingAnimation.run();
} else {
dropTarget.onDrop(mDragObject, mOptions);
}
accepted = true;
//add for cancel canceldroptarget handle
if (LauncherAppState.isDisableAllApps() && dropTarget instanceof DeleteDropTarget &&
isNeedCancelDrag(mDragObject.dragInfo)) {
cancelDrag();
}
}
}
...
}
private boolean isNeedCancelDrag(ItemInfo item){
return (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
item.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER);
}
7、屏蔽上拉顯示抽屜頁(yè)面手勢(shì)
vendor\mediatek\proprietary\packages\apps\Launcher3\quickstep\src\com\android\launcher3
\uioverrides\OverviewToAllAppsTouchController.java
canInterceptTouch() 中增加判斷是否直接攔截
@Override
protected boolean canInterceptTouch(MotionEvent ev) {
//add for forbidden workspace drag change GradientView alph
if (LauncherAppState.isDisableAllApps()){
android.util.Log.e("Launcher3", "canInterceptTouch()");
return false;
}
if (mCurrentAnimation != null) {
// If we are already animating from a previous state, we can intercept.
return true;
}
if (AbstractFloatingView.getTopOpenView(mLauncher) != null) {
return false;
}
if (mLauncher.isInState(ALL_APPS)) {
// In all-apps only listen if the container cannot scroll itself
return mLauncher.getAppsView().shouldContainerScroll(ev);
} else if (mLauncher.isInState(NORMAL)) {
return true;
} else if (mLauncher.isInState(OVERVIEW)) {
RecentsView rv = mLauncher.getOverviewPanel();
return ev.getY() > (rv.getBottom() - rv.getPaddingBottom());
} else {
return false;
}
}
8、修改頁(yè)面指示線為圓點(diǎn)
vendor\mediatek\proprietary\packages\apps\Launcher3\res\layout\launcher.xml
WorkspacePageIndicator 改為 PageIndicatorDots
<com.android.launcher3.pageindicators.PageIndicatorDots android:id="@+id/page_indicator" android:layout_width="match_parent" android:layout_height="4dp" android:layout_gravity="bottom|center_horizontal" android:theme="@style/HomeScreenElementTheme" /> vendor\mediatek\proprietary\packages\apps\Launcher3\src\com\android\launcher3
\pageindicators\PageIndicatorDots.java
增加 PageIndicatorDots 繼承 Insettable,復(fù)寫(xiě)setInsets(), 調(diào)整圓點(diǎn)的位置
public class PageIndicatorDots extends View implements PageIndicator, Insettable {
// add for change WorkspacePageIndicator line to dot
@Override
public void setInsets(Rect insets) {
DeviceProfile grid = mLauncher.getDeviceProfile();
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
if (grid.isVerticalBarLayout()) {
Rect padding = grid.workspacePadding;
lp.leftMargin = padding.left + grid.workspaceCellPaddingXPx;
lp.rightMargin = padding.right + grid.workspaceCellPaddingXPx;
lp.bottomMargin = padding.bottom;
} else {
lp.leftMargin = lp.rightMargin = 0;
lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
lp.bottomMargin = grid.hotseatBarSizePx + insets.bottom;
}
setLayoutParams(lp);
}
@Override
public void setScroll(int currentScroll, int totalScroll) {
if (mNumPages > 1) {
if (mIsRtl) {
currentScroll = totalScroll - currentScroll;
}
int scrollPerPage = totalScroll / (mNumPages - 1);
// add for change WorkspacePageIndicator line to dot
if (scrollPerPage == 0) {
return;
}
int pageToLeft = currentScroll / scrollPerPage;
int pageToLeftScroll = pageToLeft * scrollPerPage;
int pageToRightScroll = pageToLeftScroll + scrollPerPage;
...
}
vendor\mediatek\proprietary\packages\apps\Launcher3\src\com\android\launcher3
\states\SpringLoadedState.java
注釋 setShouldAutoHide(),避免長(zhǎng)按 workSpace 時(shí)發(fā)生崩潰
@Override
public void onStateEnabled(Launcher launcher) {
Workspace ws = launcher.getWorkspace();
ws.showPageIndicatorAtCurrentScroll();
//annotaion for WorkspacePageIndicator line to dot
// ws.getPageIndicator().setShouldAutoHide(false);
// Prevent any Un/InstallShortcutReceivers from updating the db while we are
// in spring loaded mode
InstallShortcutReceiver.enableInstallQueue(InstallShortcutReceiver.FLAG_DRAG_AND_DROP);
launcher.getRotationHelper().setCurrentStateRequest(REQUEST_LOCK);
}
@Override
public void onStateDisabled(final Launcher launcher) {
//annotaion for WorkspacePageIndicator line to dot
// launcher.getWorkspace().getPageIndicator().setShouldAutoHide(true);
// Re-enable any Un/InstallShortcutReceiver and now process any queued items
InstallShortcutReceiver.disableAndFlushInstallQueue(
InstallShortcutReceiver.FLAG_DRAG_AND_DROP, launcher);
}
總結(jié)
以上所述是小編給大家介紹的android 9.0 launcher3 去掉抽屜式顯示所有 app代碼詳解,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)我們網(wǎng)站的支持!
如果你覺(jué)得本文對(duì)你有幫助,歡迎轉(zhuǎn)載,煩請(qǐng)注明出處,謝謝!
上一篇:Android自定義View仿QQ運(yùn)動(dòng)步數(shù)效果
欄 目:Android
下一篇:Android9.0 SystemUI 網(wǎng)絡(luò)信號(hào)欄定制修改的流程解析
本文標(biāo)題:android 9.0 launcher3 去掉抽屜式顯示所有 app(代碼詳解)
本文地址:http://www.jygsgssxh.com/a1/Android/9107.html
您可能感興趣的文章
- 01-10Android自定義View之繪制圓形頭像功能
- 01-10Android實(shí)現(xiàn)雙擊返回鍵退出應(yīng)用實(shí)現(xiàn)方法詳解
- 01-10android實(shí)現(xiàn)記住用戶(hù)名和密碼以及自動(dòng)登錄
- 01-10android實(shí)現(xiàn)簡(jiǎn)單計(jì)算器功能
- 01-10Android 友盟第三方登錄與分享的實(shí)現(xiàn)代碼
- 01-10android實(shí)現(xiàn)指紋識(shí)別功能
- 01-10Emoji表情在Android JNI中的兼容性問(wèn)題詳解
- 01-10Android實(shí)現(xiàn)圓形漸變加載進(jìn)度條
- 01-10android開(kāi)發(fā)環(huán)境中SDK文件夾下的所需內(nèi)容詳解
- 01-10android異步消息機(jī)制 源碼層面徹底解析(1)


閱讀排行
- 1C語(yǔ)言 while語(yǔ)句的用法詳解
- 2java 實(shí)現(xiàn)簡(jiǎn)單圣誕樹(shù)的示例代碼(圣誕
- 3利用C語(yǔ)言實(shí)現(xiàn)“百馬百擔(dān)”問(wèn)題方法
- 4C語(yǔ)言中計(jì)算正弦的相關(guān)函數(shù)總結(jié)
- 5c語(yǔ)言計(jì)算三角形面積代碼
- 6什么是 WSH(腳本宿主)的詳細(xì)解釋
- 7C++ 中隨機(jī)函數(shù)random函數(shù)的使用方法
- 8正則表達(dá)式匹配各種特殊字符
- 9C語(yǔ)言十進(jìn)制轉(zhuǎn)二進(jìn)制代碼實(shí)例
- 10C語(yǔ)言查找數(shù)組里數(shù)字重復(fù)次數(shù)的方法
本欄相關(guān)
- 01-10Android自定義View之繪制圓形頭像功能
- 01-10Android實(shí)現(xiàn)雙擊返回鍵退出應(yīng)用實(shí)現(xiàn)方
- 01-10android實(shí)現(xiàn)簡(jiǎn)單計(jì)算器功能
- 01-10android實(shí)現(xiàn)記住用戶(hù)名和密碼以及自動(dòng)
- 01-10C++自定義API函數(shù)實(shí)現(xiàn)大數(shù)相乘算法
- 01-10Android 友盟第三方登錄與分享的實(shí)現(xiàn)代
- 01-10android實(shí)現(xiàn)指紋識(shí)別功能
- 01-10如何給Flutter界面切換實(shí)現(xiàn)點(diǎn)特效
- 01-10Android實(shí)現(xiàn)圓形漸變加載進(jìn)度條
- 01-10Emoji表情在Android JNI中的兼容性問(wèn)題詳
隨機(jī)閱讀
- 08-05織夢(mèng)dedecms什么時(shí)候用欄目交叉功能?
- 01-10SublimeText編譯C開(kāi)發(fā)環(huán)境設(shè)置
- 01-11Mac OSX 打開(kāi)原生自帶讀寫(xiě)NTFS功能(圖文
- 01-10使用C語(yǔ)言求解撲克牌的順子及n個(gè)骰子
- 08-05DEDE織夢(mèng)data目錄下的sessions文件夾有什
- 01-10C#中split用法實(shí)例總結(jié)
- 01-10delphi制作wav文件的方法
- 04-02jquery與jsp,用jquery
- 01-11ajax實(shí)現(xiàn)頁(yè)面的局部加載
- 08-05dedecms(織夢(mèng))副欄目數(shù)量限制代碼修改


