打造自己的 APP「冰与火百科」(四):WebView 交互、夜间模式
来源:互联网 发布:ps淘宝美工教程视频 编辑:程序博客网 时间:2024/06/01 17:50
给大家介绍一下简单的 WebView 交互和夜间模式在「冰与火百科」中的实现。
WebView 交互
在详情页面我是用 WebView 展示的,我想实现的交互是,点击 WebView 的内容跳转另一个页面。实现过程是,让 HTML 代码调用 JavaScript 代码,再让 JavaScript 代码调用 Android 的代码,下面看看如何实现。
HTML
先看 HTML 代码,假如在文本内容里有一个可以跳转的「凯特琳·徒利」,让他去调用 skip.js 的代码,指定 CatelynTully() 方法:
<body> <a href="javascript:void(0)" onclick="CatelynTully()">凯特琳·徒利</a> <script type="text/javascript" src="skip.js"></script></body>
JavaScript
这个 skip.js 文件我是放在客户端的,放在 assets 目录下,代码如下:
function CatelynTully(){ javascript:Android.goDetail('Catelyn_Tully');}
意思就是去调用 Android 的 goDetail(String id) 方法。
Android
在客户端添加 goDetail 方法,我把 JavaScript 和 Java 交互的代码写在一个类里,记得给方法加上 @JavascriptInterface 注解:
public class Js2Java { private Context mContext; public Js2Java(Context context) { this.mContext = context; } @JavascriptInterface public void goDetail(String id) { // 根据 id 跳转页面 }}
来到显示 WebView 的页面,添加以下代码让 WebView 支持 JavaScript:
webView.getSettings().setJavaScriptEnabled(true);webView.addJavascriptInterface(new Js2Java(this), "Android");
使用 loadDataWithBaseURL 来展示数据:
binding.webView.loadDataWithBaseURL("file:///android_asset/", htmlData, "text/html", "utf-8", null);
这样就完成了一个简单的 JavaScript 和 Android 的交互,效果如下:
夜间模式
关于夜间模式的实现,主要是参考了 D_clock爱吃葱花 大神的这篇文章,简单说一下实现过程如下:
- 在 styles 中添加「DayTheme」和「NightTheme」两个主题;
- 在布局文件中使用类似 android:background=”?attr/colorBackground” 来设置颜色,使其跟随当前主题颜色;
- 编写 DayNightHelper,利用 SharePreferences 保存、获取当前模式;
- 在页面 setContentView 之前,判断当前模式,并通过 setTheme 设置当前模式;
- 将屏幕内容转为 Bitmap,对其执行一个渐隐动画,实现切换时渐变的效果;
- 监听模式切换,通过 TypedValue 和 Theme.resolveAttribute 在代码中获取 Theme 中的颜色,重新设置控件的颜色。
更详细的内容可以查看原文,下面再补充几个控件的颜色设置方法。
Toolbar
假设已经拿到了切换后的颜色 color,修改 Toolbar 的背景颜色和字体颜色:
toolbar.setBackground(color);toolbar.setTitleTextColor(color);
除了这两项,Toolbar 上可能还有操作按钮,像我这里左边的菜单和右边的搜索按钮。它们的颜色可以这样设置:
// 菜单按钮Drawable navigationIcon = toolbar.getNavigationIcon();if (navigationIcon != null) { navigationIcon.setColorFilter(color, PorterDuff.Mode.SRC_ATOP);}// 搜索按钮Menu toolbarMenu = toolbar.getMenu();Drawable searchIcon = toolbarMenu.getItem(0).getIcon();if (searchIcon != null) { searchIcon.setColorFilter(color, PorterDuff.Mode.SRC_ATOP);}
TabLayout
对于 TabLayout,涉及到的颜色有背景颜色、文字颜色(选中和未选中)、指示条:
tabLayout.setBackgroundResource(color);tabLayout.setTabTextColors(normalColor, selectedColor);tabLayout.setSelectedTabIndicatorColor(color);
NavigationView
NavigationView 存在一个头部,需要的话可以可以这样修改头部的背景和字体颜色:
View navigationHeader = navigationView.getHeaderView(0);if (isDay) { navigationHeader.setBackgroundResource(R.drawable.side_nav_bar_day);} else { navigationHeader.setBackgroundResource(R.drawable.side_nav_bar_night);}TextView tvHeader = (TextView) navigationHeader.findViewById(R.id.text_view);tvHeader.setTextColor(color);
接下来是目录部分的背景、字体颜色及图表颜色:
navigationView.setBackgroundResource(color);navigationView.setItemTextColor(color);navigationView.setItemIconTintList(color);
RecyclerView
通过遍历所有的 ChildView,对每一项进行颜色设置:
for (int position = 0; position < recyclerView.getChildCount(); position++) { ViewGroup childView = (ViewGroup) binding.recyclerView.getChildAt(position); // 设置颜色}
但要注意的是,RecyclerView 的内部使用 Recycler 和 RecyclerViewPool 实现了缓存,有可能出现当前使用的 item 颜色改变了,但是缓存里的没有变化。
解决方法是清理缓存,调用 Recycler 和 RecyclerViewPool 的 Clear() 方法,但前者无法直接调用,只能通过反射实现:
Class<RecyclerView> recyclerViewClass = RecyclerView.class;try { Field declaredField = recyclerViewClass.getDeclaredField("mRecycler"); declaredField.setAccessible(true); Method declaredMethod = Class.forName(RecyclerView.Recycler.class.getName()).getDeclaredMethod("clear"); declaredMethod.setAccessible(true); declaredMethod.invoke(declaredField.get(binding.recyclerView)); RecyclerView.RecycledViewPool recycledViewPool = recyclerView.getRecycledViewPool(); recycledViewPool.clear();} catch (Exception e) { e.printStackTrace();}
StatusBar
在 SDK 21 以上,允许我们修改状态栏的颜色:
if (Build.VERSION.SDK_INT >= 21 { TypedValue typedValue = new TypedValue(); Resources.Theme theme = getTheme(); theme.resolveAttribute(R.attr.color, typedValue, true); getWindow().setStatusBarColor( ContextCompat.getColor(mContext, typedValue.resourceId));}
夜间模式的实现就到此,在重新设置颜色的部分比较繁琐,但这是我目前看到效果比较好的实现方式。效果如下:
项目地址