修改React Native原生包:实现谷歌商店样式Android Button并动态切换
实现Google商店风格的Android按钮(含动态切换)
嘿,作为刚接触Android原生的React Native开发者,我完全懂你想还原Google商店里「卸载/打开」按钮样式的需求!咱们一步步来搞定这个问题,不用依赖XML资源,纯代码实现也没问题~
一、先搞懂两种按钮的核心样式
Google商店的按钮其实是带状态切换的自定义背景,而不是单纯依赖系统的borderlessButtonStyle:
- 「卸载」按钮:正常状态是透明背景+灰色边框,按下时背景变浅灰;
- 「打开」按钮:正常状态是实心蓝色背景+白色文字,按下时背景变暗蓝。
二、纯代码实现两种按钮样式
我们可以用StateListDrawable来创建带状态的背景,同时自定义按钮的文字颜色、边框这些属性。
1. 实现「卸载」按钮(透明边框)
// 创建边框形状 GradientDrawable borderDrawable = new GradientDrawable(); borderDrawable.setShape(GradientDrawable.RECTANGLE); borderDrawable.setStroke(2, ContextCompat.getColor(context, android.R.color.darker_gray)); // 2dp边框,灰色 borderDrawable.setCornerRadius(convertDpToPx(context, 4)); // 圆角,和Google商店一致 // 创建按下时的背景 GradientDrawable pressedBorderBg = new GradientDrawable(); pressedBorderBg.setShape(GradientDrawable.RECTANGLE); pressedBorderBg.setColor(ContextCompat.getColor(context, android.R.color.darker_gray)); pressedBorderBg.setAlpha(20); // 半透明浅灰 pressedBorderBg.setCornerRadius(convertDpToPx(context, 4)); // 组装状态列表背景 StateListDrawable borderButtonBg = new StateListDrawable(); borderButtonBg.addState(new int[]{android.R.attr.state_pressed}, pressedBorderBg); borderButtonBg.addState(new int[]{}, borderDrawable); // 创建按钮 Button uninstallBtn = new Button(context); uninstallBtn.setText("卸载"); uninstallBtn.setTextColor(ContextCompat.getColor(context, android.R.color.darker_gray)); uninstallBtn.setBackground(borderButtonBg); uninstallBtn.setPadding(convertDpToPx(context, 16), convertDpToPx(context, 8), convertDpToPx(context, 16), convertDpToPx(context, 8)); // 去掉系统默认的阴影和凸起 uninstallBtn.setElevation(0); uninstallBtn.setTranslationZ(0);
2. 实现「打开」按钮(实心背景)
// 创建正常状态的实心背景 GradientDrawable solidDrawable = new GradientDrawable(); solidDrawable.setShape(GradientDrawable.RECTANGLE); solidDrawable.setColor(ContextCompat.getColor(context, android.R.color.holo_blue_dark)); solidDrawable.setCornerRadius(convertDpToPx(context, 4)); // 创建按下时的背景 GradientDrawable pressedSolidBg = new GradientDrawable(); pressedSolidBg.setShape(GradientDrawable.RECTANGLE); pressedSolidBg.setColor(ContextCompat.getColor(context, android.R.color.holo_blue_light)); pressedSolidBg.setCornerRadius(convertDpToPx(context, 4)); // 组装状态列表背景 StateListDrawable solidButtonBg = new StateListDrawable(); solidButtonBg.addState(new int[]{android.R.attr.state_pressed}, pressedSolidBg); solidButtonBg.addState(new int[]{}, solidDrawable); // 创建按钮 Button openBtn = new Button(context); openBtn.setText("打开"); openBtn.setTextColor(ContextCompat.getColor(context, android.R.color.white)); openBtn.setBackground(solidButtonBg); openBtn.setPadding(convertDpToPx(context, 16), convertDpToPx(context, 8), convertDpToPx(context, 16), convertDpToPx(context, 8)); openBtn.setElevation(0); openBtn.setTranslationZ(0);
辅助方法:DP转PX
上面用到的convertDpToPx工具方法,用来保证不同屏幕尺寸下的样式一致:
private int convertDpToPx(Context context, int dp) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, context.getResources().getDisplayMetrics()); }
三、动态切换按钮样式(比如从「打开」切到「卸载」)
如果你需要在运行时切换按钮的样式(比如APP安装完成后从「安装」切到「打开」),直接替换按钮的背景和文字颜色即可:
// 假设我们有一个按钮实例btn,现在要切换到卸载样式 public void switchToUninstallStyle(Button btn) { // 重新创建卸载样式的背景(或者提前缓存好两个StateListDrawable) StateListDrawable borderBg = createBorderButtonBg(context); btn.setBackground(borderBg); btn.setText("卸载"); btn.setTextColor(ContextCompat.getColor(context, android.R.color.darker_gray)); } // 切换到打开样式 public void switchToOpenStyle(Button btn) { StateListDrawable solidBg = createSolidButtonBg(context); btn.setBackground(solidBg); btn.setText("打开"); btn.setTextColor(ContextCompat.getColor(context, android.R.color.white)); }
四、关于android.R.attr.borderlessButtonStyle的说明
你之前用的borderlessButtonStyle是系统提供的无边框、无背景、无阴影的按钮样式,适合做纯文字按钮,但和Google商店的「卸载」按钮不一样——后者是有边框的。如果要在代码中给按钮应用这个样式,可以用ContextThemeWrapper:
// 创建带borderless样式的按钮 Button borderlessBtn = new Button(new ContextThemeWrapper(context, android.R.style.Widget_Material_Button_Borderless));
但如果要动态切换是否使用这个样式,其实更简单的是直接修改按钮的背景和阴影属性,因为borderlessButtonStyle本质就是去掉了背景和阴影,所以直接设置setBackground(null)、setElevation(0)就能达到同样效果。
内容的提问来源于stack exchange,提问作者Noitidart
相关产品推荐
相关产品推荐

