Android Launcher浅析(二)

1,如何修改主菜单图标的位置?
[DESCRIPTION]
默认主菜单图标在中间,如何修改它的位置?
这里写图片描述

Launcher3:
DynamicGrid.java文件
hotseatAllAppsRank = (int) (numColumns/2); //默认是列数除以2取整,可以设置为需要的值

Launcher2:
1. 请修改packages/apps/Laucher2/res/values/config.xml 中hotseat_all_apps_index的值,例如修改为1
2. 默认在hotseat配置时1的位置是contact,需要重新修改packages/apps/Laucher2/res/xml/default_workspace.xml 来重新配置hotseat图标位置

2,Launcher3如何增加默认的HomeScreen数目?
[DESCRIPTION]
Launcher3如何增加默认的Home Screen数目?
Launcher3默认的Home Screen数目是由预置的桌面应用(default_workspace.xml)决定的。如果要增加Home Screen数目,需要在default_workspace.xml中将桌面应用配置在不同screen id上。
请修改res/xml/default_workspace.xml文件,添加如下代码:

L:
1. AppsCustomizePagedView.java修改两处如下:
1) private void setupPage(AppsCustomizeCellLayout layout) {
layout.setGridSize(mCellCountX, mCellCountY);
// Note: We force a measure here to get around the fact that when we do layout calculations
// immediately after syncing, we don't have a proper width. That said, we already know the
// expected page width, so we can actually optimize by hiding all the TextView-based
// children that are expensive to measure, and let that happen naturally later.
setVisibilityOnChildren(layout, View.GONE);
int widthSpec = MeasureSpec.makeMeasureSpec(mContentWidth, MeasureSpec.AT_MOST);
int heightSpec = MeasureSpec.makeMeasureSpec(mContentHeight, MeasureSpec.AT_MOST);
layout.measure(widthSpec, heightSpec);
if(!Launcher.DISABLE_APPLIST_WHITE_BG) {//mtk add
Drawable bg = getContext().getResources().getDrawable(R.drawable.quantum_panel);
if (bg != null) {
bg.setAlpha(mPageBackgroundsVisible ? 255: 0);
layout.setBackground(bg);
}
} else {//mtk add
layout.setBackground(null);//mtk add
}//mtk add
setVisibilityOnChildren(layout, View.VISIBLE);
}
2) public void syncAppsPageItems(int page, boolean immediate) {
......
AppInfo info = mApps.get(i);
BubbleTextView icon = (BubbleTextView) mLayoutInflater.inflate(
R.layout.apps_customize_application, layout, false);
if(Launcher.DISABLE_APPLIST_WHITE_BG) {//mtk add
icon.setTextColor(getContext().getResources().getColor(R.color.quantum_panel_transparent_bg_text_color))
;//mtk add
}//mtk add
icon.applyFromApplicationInfo(info);
icon.setOnClickListener(mLauncher);
icon.setOnLongClickListener(this);
......
2. colors.xml中新增:
<color name="quantum_panel_transparent_bg_text_color">#FFFFFF</color>
3. DeviceProfile.java修改layout(Launcher launcher)方法如下:
......
pagedView.setWidgetsPageIndicatorPadding(pageIndicatorHeight);
if(Launcher.DISABLE_APPLIST_WHITE_BG) {//mtk add
fakePage.setBackground(null);//mtk add
} else {//mtk add
fakePage.setBackground(res.getDrawable(R.drawable.quantum_panel));
}//mtk add
// Horizontal padding for the whole paged view
int pagedFixedViewPadding =
res.getDimensionPixelSize(R.dimen.apps_customize_horizontal_padding);
......
4. Launcher.java
1) 新增:
//mtk add begin
/// M: Disable applist white background for jitter performance issue {@
public static boolean DISABLE_APPLIST_WHITE_BG = true;
public static final String PROP_DISABLE_APPLIST_WHITE_BG = "launcher.whitebg.disable";
// should kill and restart launcher process to re-execute static block if reset properties
// adb shell setprop launcher.applist.whitebg.disable true/false
// adb shell stop
// adb shell start
static {
DISABLE_APPLIST_WHITE_BG = android.os.SystemProperties.getBoolean(PROP_DISABLE_APPLIST_WHITE_BG, true);
}
/// @}
//mtk add end
2) showAppsCustomizeHelper方法修改如下:
......
if (isWidgetTray) {
revealView.setBackground(res.getDrawable(R.drawable.quantum_panel_dark));
} else {
if(Launcher.DISABLE_APPLIST_WHITE_BG) {//mtk add
revealView.setBackground(null);//mtk add
} else {//mtk add
revealView.setBackground(res.getDrawable(R.drawable.quantum_panel));
}//mtk add
}
......
3) hideAppsCustomizeHelper方法修改如下:
......
if (isWidgetTray) {
revealView.setBackground(res.getDrawable(R.drawable.quantum_panel_dark));
} else {
if(Launcher.DISABLE_APPLIST_WHITE_BG) {//mtk add
revealView.setBackground(null);//mtk add
} else {//mtk add
revealView.setBackground(res.getDrawable(R.drawable.quantum_panel));
}//mtk add
}
......
JB2/JB3:
1. 请修改 packages\apps\Launcher2\res\layout\apps_customize_pane.xml
<com.android.launcher2.AppsCustomizeTabHost
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher"
android:background="#00000000"> // 原值为#FF000000
2. 请修改packages\apps\Launcher2\src\com\android\launcher2\Launcher.java的hideAppsCustomizeHelper(boolean animated, final boolean
springLoaded)方法,如下:
......
setPivotsForZoom(fromView, scaleFactor);
updateWallpaperVisibility(true);
showHotseat(animated);
if(mDockDivider != null) { //mtk add
mDockDivider.setVisibility(View.VISIBLE); //mtk add
} //mtk add
......
3. 请修改Launcher.java的showAppsCustomizeHelper(boolean animated, final boolean springLoaded) 方法,如下:
......
// Shrink workspaces away if going to AppsCustomize from workspace
mWorkspace.changeState(Workspace.State.SMALL, animated);
// and hide hotseat and dock divider
hideHotseat(false); //mtk add
if(mDockDivider != null) {//mtk add
mDockDivider.setVisibility(View.INVISIBLE); //mtk add
}//mtk add
if(mWorkspace != null) {//mtk add
mWorkspace.setVisibility(View.INVISIBLE);//mtk add
}//mtk add
......
4. 请修改Launcher.java 文件,将showAppsCustomizeHelper(boolean animated, final boolean springLoaded)方法中出现的两处
updateWallpaperVisibility(false);注释掉
第一处是在此函数内的 public void onAnimationEnd(Animator animation) 方法的最后
第二处是在showAppsCustomizeHelpe方法的最后
5. 请修改Launcher.java的enterSpringLoadedDragMode()方法,如下:
void enterSpringLoadedDragMode() {
if (mState == State.APPS_CUSTOMIZE) {
mWorkspace.setVisibility(View.VISIBLE); //mtk add
mWorkspace.changeState(Workspace.State.SPRING_LOADED);
hideAppsCustomizeHelper(true, true);
hideDockDivider();
mState = State.APPS_CUSTOMIZE_SPRING_LOADED;
}
}
6. 请修改Launcher.java 中disableWallpaperIfInAllApps() 方法,如下:
void disableWallpaperIfInAllApps() {
// Only disable it if we are in all apps
if (isAllAppsVisible()) {
if (mAppsCustomizeTabHost != null &&
!mAppsCustomizeTabHost.isTransitioning()) {
updateWallpaperVisibility(true); //mtk modify }
}
}
7. 请修改packages\apps\Launcher2\res\layout\apps_customize_pane.xml中id 为 animation_buffer 的这个控件, 将其 android:background 设
置为 #0000000
8. 请修改Launcher.java的onResume()方法:
将setWorkspaceBackground(mState == State.WORKSPACE);
修改为
setWorkspaceBackground(true);
注意: 修改了第7步之后, 在切换 widget 及 app 的时候, 可能会短时间的看到 widget 与 app 相叠加的画面。
这是 appsCustomizeTabHost.java 的 onTabChanged 方法内的 animSet.playTogether(outAnim, inAnim); 所指定的效果,可以自行客制化。

11,如何让Launcher3的主菜单和桌面支持循环滑动?
如果项目不是operator定制项目,请找到DefaultWorkspaceExt.java,将其中的supportAppListCycleSliding()返回值修改为true。
如果项目是operator定制项目,请找到OP0XWorkspaceExt.java(例如移动是OP01WorkspaceExt.java),将其中的supportAppListCycleSliding()返回值修改为true。

12,如何将桌面和主菜单较长的图标名称显示完整?

1. 请修改styles.xml,将
<style name="WorkspaceIcon.Portrait">
<item name="android:drawablePadding">0dp</item>
<item name="android:paddingLeft">4dp</item>
<item name="android:paddingRight">4dp</item>
<item name="android:paddingTop">@dimen/app_icon_padding_top</item>
<item name="android:paddingBottom">4dp</item>
<item name="android:textSize">13sp</item>
</style>
修改为:
<style name="WorkspaceIcon.Portrait">
<item name="android:drawablePadding">0dp</item>
<item name="android:paddingLeft">4dp</item>
<item name="android:paddingRight">4dp</item>
<item name="android:paddingTop">@dimen/app_icon_padding_top</item>
<item name="android:paddingBottom">4dp</item>
<item name="android:textSize">13sp</item>
<item name="android:singleLine">false</item>
<item name="android:lines">2</item>
</style>
2. BubbleTextView.javaapplyFromShortcutInfo
setCompoundDrawablePadding((int) ((grid.folderIconSizePx - grid.iconSizePx) / 2f));
3. PagedViewIcon.javaapplyFromApplicationInfo
public void applyFromApplicationInfo(AppInfo info, boolean scaleUp,
PagedViewIcon.PressedCallback cb) {
mIcon = info.iconBitmap;
mPressedCallback = cb;
setCompoundDrawablesWithIntrinsicBounds(null, Utilities.createIconDrawable(mIcon), null, null);
setCompoundDrawablePadding(xxxx);//mtk addxxxx
setText(info.title);

13,如何将主菜单图标改成按安装时间排序?

1. 在 LauncherModel.java 中加入如下方法:
public static final Comparator<AppInfo> getInstallTimeComparator() {
return new Comparator<AppInfo>() {
public final int compare(AppInfo a, AppInfo b) {
return a.firstInstallTime == b.firstInstallTime ? 0 : a.firstInstallTime >
b.firstInstallTime ? 1:-1;
}
};
}
public static class InstallTimeComparator implements
Comparator<ResolveInfo> {
private PackageManager mPackageManager;
List<ResolveInfo> mapps;
InstallTimeComparator(PackageManager pm, List<ResolveInfo> apps)
{
mPackageManager = pm;
mapps = apps;
}
public final int compare(ResolveInfo a, ResolveInfo b) {
String packageNameA = a.activityInfo.applicationInfo.packageName;
String packageNameB = b.activityInfo.applicationInfo.packageName;
long firstInstallTimeA = 0, firstInstallTimeB = 0;
try{
firstInstallTimeA = mPackageManager.getPackageInfo(packageNameA,
0).firstInstallTime;
firstInstallTimeB = mPackageManager.getPackageInfo(packageNameB,
0).firstInstallTime;
}catch(Exception e){
e.printStackTrace();
return 0;
}
return firstInstallTimeA == firstInstallTimeB ? 0 : firstInstallTimeA >
firstInstallTimeB ? 1:-1;
}
};
2. 修改 LauncherModel.java 的 loadAllAppsByBatch() 方法:
将
Collections.sort(apps,new
LauncherModel.ShortcutNameComparator(packageManager, mLabelCache));
替换成:
Collections.sort(apps,new InstallTimeComparator(packageManager, apps));
3. 修改 AppsCustomizePagedview.java 的 setApps 方法
将
Collections.sort(mApps, LauncherModel.getAppNameComparator());
替换成:
Collections.sort(mApps, LauncherModel.getInstallTimeComparator());
4. reorderApps()在某些条件下会被调用,如果要求在那些条件下也要达到按照安装时间排序,请在调用reorderApps方法前增加
Collections.sort(mApps, LauncherModel.getInstallTimeComparator());

14,如何将Launcher2的状态栏修改为透明?
KK:
请修改packages/apps/Launcher2/res/value/Style.xml,增加下图的属性即可:
这里写图片描述

15,如何客制化Launcher的主菜单图标?

1、请修改packages/apps/Launcher2的ApplicationInfo.java 或者
packages/apps/Launcher3的AppInfo.java,如下:
public ApplicationInfo(ResolveInfo info, IconCache iconCache) {
this.componentName = new ComponentName(
info.activityInfo.applicationInfo.packageName,
info.activityInfo.name);
this.container = ItemInfo.NO_ID;
this.setActivity(componentName,
Intent.FLAG_ACTIVITY_NEW_TASK |
Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
iconCache.getTitleAndIcon(this, info);
// mtk add
if ( (info.activityInfo.applicationInfo.flags &
android.content.pm.ApplicationInfo.FLAG_SYSTEM) != 0) {
this.iconBitmap=Bitmap.createBitmap(72, 72, Bitmap.Config.ARGB_8888); //
具体方法可以自行决定,这里只是例子
}
// mtk add
}
2、如果是用户安装的第三方app,请修改packages/apps/Launcher2的
AllAppsList.java,修改updatePackage方法如下:
......
ApplicationInfo applicationInfo = findApplicationInfoLocked(pkgName,
className);
if (applicationInfo == null) {
add(new ApplicationInfo(context.getPackageManager(), info, mIconCache,
null));
} else {
mIconCache.remove(applicationInfo.componentName);
mIconCache.getTitleAndIcon(applicationInfo, info, null);
//mtk add
在此处添加修改applicationInfo.iconBitmap的代码(同上)
//mtk add
modified.add(applicationInfo);
}
......
2、如果是系统预置的某个特定的应用图标,请修改IconCache.java文件的
cacheLocked方法
最后修改原来的entry.icon为您需要的数据
entry.icon = Utilities.createIconBitmap(
getFullResIcon(info), mContext);
举例如下:
if("com.android.contacts".equals(componentName.getPackageName())) {
Drawable drawable;
drawable = getFullResIcon(mContext.getResources(),
R.drawable.ic_hw_allbackup);
entry.icon = Utilities.createIconBitmap(drawable, mContext);
LauncherLog.d(TAG, "change");
}
else{
entry.icon = Utilities.createIconBitmap(
getFullResIcon(info), mContext);
LauncherLog.d(TAG, "no change");
}
}
PS:72/72表示主菜单Icon的图标大小,color format是ARGB8888。这个设置默认把
用户自己安装的apk Icon刷成黑色。createBitmap这个方法有多种重载方式,用户可
以根据实际需求,通过方法参数(颜色/bitmap/图片资源id等)来构造自己的主菜单
Icon风格。

16,如何定制Launcher主菜单中应用程序图标的显示顺序?

请修改Launcher2/res/xml/default_toppackage.xml文件:
<toppackages xmlns:launcher="
http://schemas.android.com/apk/res/com.android.launcher2bird13gb">
<app
launcher:topPackageName="com.yahoo.mobile.client.android.odp"
launcher:topClassName="com.yahoo.mobile.client.android.odp.YahooODP"
launcher:topOrder="4"
/>
<app
launcher:topPackageName="com.yahoo.mobile.client.android.im"
launcher:topClassName="com.yahoo.mobile.client.android.im.YahooMessenger"
launcher:topOrder="5"
/>
<app
launcher:topPackageName="com.yahoo.mobile.client.android.mail"
launcher:topClassName=
"com.yahoo.mobile.client.android.mail.activity.YahooMail"
launcher:topOrder="6"
/>
<app
launcher:topPackageName="com.yahoo.mobile.client.android.news"
launcher:topClassName="com.yahoo.mobile.client.android.news.activity.Main"
launcher:topOrder="7"
/>
<app
launcher:topPackageName="com.yahoo.mobile.client.android.finance"
launcher:topClassName=
"com.yahoo.mobile.client.android.finance.activity.Main"
launcher:topOrder="10"
/>
</toppackages>
请按照上面的格式来编辑,编辑为特定app的topPackageName,topClassName以及order的值(从0开始)。
备注:如果是运营商项目,会有resource_overlay机制,请以resource_overlay路径下的default_toppackage.xml内
容为准。

17,如何在小部件列表中隐藏某个widget或者shortcut?
小部件列表包括两种类型:widget和shortcut。如何在小部件列表中隐藏某个widget或者shortcut?例如隐藏设置的电量控制小部件(Power Control)?
这里写图片描述

请修改AppsCustomizePagedView.java的onPackagesUpdated方法,如下图所示:
这里写图片描述

18,如何在Launcher的主菜单中隐藏某个应用?

mIconCache, mLabelCache));
}
//mtk add begin
mBgAllAppsList.removePackage("packageName");
//mtk add end
mBgAllAppsList.reorderApplist();
......
2. 请在LauncherModel.java的PackageUpdatedTask的run()方法开头,将mPackages变量中要求不显示的package
name移除掉。
KK以前版本:
请修改LauncherModel.java的loadAllAppsByBatch()方法,如下:
......
if (!LauncherExtPlugin.getAllAppsListExt(mApp).isShowWifiSettings()) {
mBgAllAppsList.removeWifiSettings();
}
//mtk add begin
mBgAllAppsList.removeSpecificApp("packageName", "className");
//mtk add end
mBgAllAppsList.reorderApplist();

19,如何去除Launcher默认的googlesearch bar?

L1:
请修改Launcher3/src/com/android/launcher3/Launcher.java的getQsbBar()方法,直接return null。
L0/KK:
1. 请修改Launcher3/res/layout-port/qsb.xml(L0)或者Launcher3/res/layout-port/search_bar.xml(KK),如下:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/search_frame"
android:visibility="gone">
2.请修改Launcher3/res/layout-port/launcher.xml,将voice_button_proxy这个view的clickable设置为false,并去
掉onClick="onClickVoiceButton",如下:
<com.android.launcher3.DrawableStateProxyView
android:id="@+id/voice_button_proxy"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_gravity="top|end"
android:clickable="false"
android:importantForAccessibility="no"
launcher:sourceViewId="@+id/voice_button" />
3. 请修改Launcher3/src/com/android/launcher3/SearchDropTargetBar.java的setup()方法,如下:
......
if (mEnableDropDownDropTargets) {
mQSBSearchBarAnim = ObjectAnimator.ofFloat(mQSBSearchBar, "translationY", -mBarHeight,
-mBarHeight);
} else {
mQSBSearchBarAnim = ObjectAnimator.ofFloat(mQSBSearchBar, "alpha", 0f, 0f);
}
......
4.请修改Launcher3/src/com/android/launcher3/SearchDropTargetBar.java的showSearchBar()方法,如下:
public void showSearchBar(boolean animated) {
boolean needToCancelOngoingAnimation = mQSBSearchBarAnim.isRunning() && !animated;
if (!mIsSearchBarHidden && !needToCancelOngoingAnimation) return;
if (animated) {
prepareStartAnimation(mQSBSearchBar);
mQSBSearchBarAnim.reverse();
} else {
mQSBSearchBarAnim.cancel();
if (mEnableDropDownDropTargets) {
mQSBSearchBar.setTranslationY(0);
} else {
mQSBSearchBar.setAlpha(0f);
}
}
mIsSearchBarHidden = false;
}
5.请修改Launcher3/src/com/android/launcher3/Workspace.java的getChangeStateAnimation()方法,如下:
......
float finalSearchBarAlpha = !stateIsNormal ? 0f : 0f;
......
JB2/JB3/JB5/JB9:
1. 请修改Launcher2/res/layout/qsb_bar.xml,如下:
<include android:id="@+id/qsb_search_bar"
layout="@layout/search_bar"
android:visibility="gone"/>
2.请修改Launcher2/res/layout-port/launcher.xml,将voice_button_proxy这个view的clickable设置为false,并去
掉onClick="onClickVoiceButton",如下:
<com.android.launcher2.DrawableStateProxyView
android:id="@+id/voice_button_proxy"
android:layout_width="80dp"
android:layout_height="@dimen/qsb_bar_height"
android:layout_gravity="top|right"
android:clickable="false"
android:importantForAccessibility="no"
launcher:sourceViewId="@+id/voice_button" />
3. 请修改Launcher2/src/com/android/launcher2/SearchDropTargetBar.java的onFinishInflate()方法,如下:
......
// Create the various fade animations
if (mEnableDropDownDropTargets) {
mDropTargetBar.setTranslationY(-mBarHeight);
mDropTargetBarAnim = ObjectAnimator.ofFloat(mDropTargetBar, "translationY",
-mBarHeight, 0f);
mQSBSearchBarAnim = ObjectAnimator.ofFloat(mQSBSearchBar, "translationY",-mBarHeight,
-mBarHeight);
} else {
mDropTargetBar.setAlpha(0f);
mDropTargetBarAnim = ObjectAnimator.ofFloat(mDropTargetBar, "alpha", 0f, 1f);
mQSBSearchBarAnim = ObjectAnimator.ofFloat(mQSBSearchBar, "alpha",0f, 0f);
}
......
4.请修改Launcher2/src/com/android/launcher2/SearchDropTargetBar.java的showSearchBar()方法,如下:
public void showSearchBar(boolean animated) {
if (!mIsSearchBarHidden) return;
if (animated) {
prepareStartAnimation(mQSBSearchBar);
mQSBSearchBarAnim.reverse();
} else {
mQSBSearchBarAnim.cancel();
if (mEnableDropDownDropTargets) {
mQSBSearchBar.setTranslationY(0);
} else {
mQSBSearchBar.setAlpha(0f);
}
}
mIsSearchBarHidden = false;
}

***20***Launcher如何去掉进入应用时的动画效果?

请修改Launcher.java的startActivity方法,如下:
boolean startActivity(View v, Intent intent, Object tag) {
if (LauncherLog.DEBUG) {
LauncherLog.d(TAG, "startActivity v = " + v + ", intent = " + intent + ", tag = " + tag);
}
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
// Only launch using the new animation if the shortcut has not opted out (this is a
// private contract between launcher and may be ignored in the future).
//boolean useLaunchAnimation = (v != null) && //mtkmodify
// !intent.hasExtra(INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION); //mtk modify
boolean useLaunchAnimation = false; //mtkadd
/// M: add systrace to analyze application launche time.
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "Launcher.startActivity");
if (useLaunchAnimation) {
ActivityOptions opts = ActivityOptions.makeScaleUpAnimation(v, 0, 0,
v.getMeasuredWidth(), v.getMeasuredHeight());
startActivity(intent, opts.toBundle());
} else {
startActivity(intent);
}
/// M: add systrace to analyze application launche time.
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
return true;
} catch (SecurityException e) {
Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
Log.e(TAG, "Launcher does not have the permission to launch " + intent +
". Make sure to create a MAIN intent-filter for the corresponding activity " +
"or use the exported attribute for this activity. "
+ "tag=" + tag + " intent=" + intent, e);
}
return false;
}
KK:
直接将useLaunchAnimation 设置为false就好

21.Launcher3中主菜单的布局如何调整(譬如从5*4调整为4*4)?
Launcher3主菜单布局的行数和列数,都是在DynamicGrid.java中动态计算的,xml中无法配置。
如果想修改主菜单的布局,调整行数和列数,请修改DynamicGrid.java中allAppsNumRows和allAppsNumCols的值。

22,Launcher2的主菜单一直卡在加载状态,如何解决?
1、请修改Launcher.java的onDestroy方法,将如下code:
mModel.stopLoader();
app.setLauncher(null);
修改为:
// It’s possible to receive onDestroy after a new Launcher activity has
// been created. In this case, don’t interfere with the new Launcher.
if (mModel.isCurrentCallbacks(this)) {
mModel.stopLoader();
app.setLauncher(null);
}
2、请在LauncherModel.java中增加如下code:
public boolean isCurrentCallbacks(Callbacks callbacks) {
return (mCallbacks != null && mCallbacks.get() == callbacks);
}

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值