使用“Powered By Chrome”和操作菜单打开自定义 WebView

2024-01-15

我最近注意到,当在一些 Android 应用程序中打开链接时,它们具有相似的外观和感觉,并且自定义操作菜单在自定义菜单下方带有“由 Chrome 提供支持”。这里面使用了什么组件还是仍然是 ChromiumWebView?希望我希望将它们添加到我的下一个项目中,其中涉及打开应用程序内的链接。

LinkedIn App LinkedIn App

Twitter App Twitter App

GMail App GMail App


It is Chrome 自定义标签 https://developer.chrome.com/multidevice/android/customtabs。您可以在 Google Chrome 中查看示例代码here https://github.com/GoogleChrome/custom-tabs-client.

尝试以下 util 类:

public class CustomTabs {

    private static final int TOOLBAR_SHARE_ITEM_ID = 1;

    public static void openTab(Context context, String url) {
        CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();

        enableUrlBarHiding(builder);
        setToolbarColor(context, builder);
        setSecondaryToolbarColor(context, builder);
        setCloseButtonIcon(context, builder);
        setShowTitle(builder);
        setAnimations(context, builder);
        setShareActionButton(context, builder, url);
        addToolbarShareItem(context, builder, url);
        addShareMenuItem(builder);
        addCopyMenuItem(context, builder);

        CustomTabsIntent customTabsIntent = builder.build();
        customTabsIntent.launchUrl(context, Uri.parse(url));
    }

    /* Enables the url bar to hide as the user scrolls down on the page */
    private static void enableUrlBarHiding(CustomTabsIntent.Builder builder) {
        builder.enableUrlBarHiding();
    }

    /* Sets the toolbar color */
    private static void setToolbarColor(Context context, CustomTabsIntent.Builder builder) {
        builder.setToolbarColor(ContextCompat.getColor(context, R.color.colorPrimary));
    }

    /* Sets the secondary toolbar color */
    private static void setSecondaryToolbarColor(Context context, CustomTabsIntent.Builder builder) {
        builder.setSecondaryToolbarColor(ContextCompat.getColor(context, R.color.colorPrimary));
    }    

    /* Sets the Close button icon for the custom tab */
    private static void setCloseButtonIcon(Context context, CustomTabsIntent.Builder builder) {
        builder.setCloseButtonIcon(BitmapFactory.decodeResource(context.getResources(), R.drawable.ic_arrow_back));
    }

    /* Sets whether the title should be shown in the custom tab */
    private static void setShowTitle(CustomTabsIntent.Builder builder) {
        builder.setShowTitle(true);
    }

    /* Sets animations */
    private static void setAnimations(Context context, CustomTabsIntent.Builder builder) {
        builder.setStartAnimations(context, R.anim.slide_in_right, R.anim.slide_out_left);
        builder.setExitAnimations(context, R.anim.slide_in_left, R.anim.slide_out_right);
    }

    /* Sets share action button that is displayed in the Toolbar */
    private static void setShareActionButton(Context context, CustomTabsIntent.Builder builder, String url) {
        Bitmap icon = BitmapFactory.decodeResource(context.getResources(), android.R.drawable.ic_menu_share);
        String label = "Share via";

        Intent shareIntent = new Intent(Intent.ACTION_SEND);
        shareIntent.putExtra(Intent.EXTRA_TEXT, url);
        shareIntent.setType("text/plain");

        PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, shareIntent, PendingIntent.FLAG_UPDATE_CURRENT);

        builder.setActionButton(icon, label, pendingIntent);
    }

    /* Adds share item that is displayed in the secondary Toolbar */
    private static void addToolbarShareItem(Context context, CustomTabsIntent.Builder builder, String url) {
        Bitmap icon = BitmapFactory.decodeResource(context.getResources(), android.R.drawable.ic_menu_share);
        String label = "Share via";

        Intent shareIntent = new Intent(Intent.ACTION_SEND);
        shareIntent.putExtra(Intent.EXTRA_TEXT, url);
        shareIntent.setType("text/plain");

        PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, shareIntent, PendingIntent.FLAG_UPDATE_CURRENT);

        builder.addToolbarItem(TOOLBAR_SHARE_ITEM_ID, icon, label, pendingIntent);

    }

    /* Adds a default share item to the menu */
    private static void addShareMenuItem(CustomTabsIntent.Builder builder) {
        builder.addDefaultShareMenuItem();
    }

    /* Adds a copy item to the menu */
    private static void addCopyMenuItem(Context context, CustomTabsIntent.Builder builder) {
        String label = "Copy";
        Intent intent = new Intent(context, CopyBroadcastReceiver.class);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);

        builder.addMenuItem(label, pendingIntent);
    }

    public static class CopyBroadcastReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            String url = intent.getDataString();

            ClipboardManager clipboardManager = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
            ClipData data = ClipData.newPlainText("Link", url);
            clipboardManager.setPrimaryClip(data);

            Toast.makeText(context, "Copied " + url, Toast.LENGTH_SHORT).show();
        }
    }
}

不要忘记将依赖项添加到您的app/build.gradle

dependencies {
    ...
    compile 'com.android.support:customtabs:25.2.0'
}

并注册您的BroadcastReceiver在你的AndroidManifest.xml

<application>
    ...
    <receiver android:name=".CustomTabs$CopyBroadcastReceiver" />
</application>

这是动画 xml:

Slide_in_left.xml

<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromXDelta="100%p" android:toXDelta="0%p"
    android:duration="@android:integer/config_longAnimTime"
    android:interpolator="@android:anim/overshoot_interpolator" />

Slide_in_right.xml

<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromXDelta="-100%p" android:toXDelta="0%p"
    android:duration="@android:integer/config_longAnimTime"
    android:interpolator="@android:anim/overshoot_interpolator" />

Slide_out_left.xml

<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromXDelta="0" android:toXDelta="-100%p"
    android:duration="@android:integer/config_longAnimTime"
    android:interpolator="@android:anim/overshoot_interpolator" />

Slide_out_right.xml

<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromXDelta="0" android:toXDelta="100%p"
    android:duration="@android:integer/config_longAnimTime"
    android:interpolator="@android:anim/overshoot_interpolator" />
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用“Powered By Chrome”和操作菜单打开自定义 WebView 的相关文章

随机推荐

  • 如何在 mongodb 中按周对文档进行分组

    id ObjectId 568b650543712795bf864a45 companyId 55e2d7cfdc8f74d14f5c900f timeStamp ISODate 2014 12 03T18 30 00 000Z id Ob
  • NLog 无法与 MSTest 一起使用,配置应该放在哪里?

    我们最近将测试从 NUnit 迁移到 MSTest 我正在努力让之前通过的测试运行 据我所知 MSTest 无法检测到 NLog 配置 我的 App config 中有 Nlog 配置 这不会导致 NUnit 出现问题 有人有什么想法吗 改
  • Gettext自动评论生成

    我正在使用 gettext 为 php 项目执行 i18n 操作 我想使用自动评论功能 http www gnu org software gettext manual gettext html PO Files在翻译用 id 替换的长短语
  • int* x[n][m] 和 int (*x) [n][m] 有什么区别?

    照我看来int x n m 宣称x是一个指向整数的指针的二维数组 因此分配内存应该像x i j new int正如预期的那样 它工作得很好 现在 如果我将声明更改为 int x n m x i j new int不再有效并导致编译错误 x
  • iOS SpriteKit SKAction 完成调用不起作用/创建奇怪的结果

    我试图让 SKNode 根据命令移动到屏幕上 我设置了以下 SKAction 链 以便 1 节点向上移动并移出屏幕 然后 2 节点向下移动到起始位置 然后 3 开始四处移动 我使用以下代码来尝试实现这一点 SKAction moveUp S
  • Malloc 分配方案

    是的 我正在学习计算机系统课程 我对实现 malloc 的各种分配方案有一些疑问 对于显式列表 如果我使用类似 LIFO 的堆栈实现 malloc 那么拥有指向先前释放的内存的指针的确切目的是什么 比如为什么需要双向链表 单链表不是也能工作
  • 如何使用 jasmine 自定义记者制作失败规格列表并发布到 Slack?

    我正在尝试使用自定义 jasmine 报告器并获取 specDone 函数中所有失败规格的列表 specDone function result if result status failed failedExpectations push
  • 如何在 ggplot 中为地图中的多个图层自定义图例?

    我正在尝试修复我的标题 但在创建它时遇到问题 我想要类 填充 形状限制 颜色 点 颜色 和网格 填充 NA 的标题 我把它们全部放进去aes 但我没有得到预期的结果 有谁能够帮助我 谢谢 library geobr library sf l
  • 旋转 y 轴标签

    我正在尝试旋转 Y 轴的标题 使其处于水平位置 我不希望刻度标签只是 Y 轴标题的水平方向 我必须使用子图 因为我要同时制作多个图 这是下面的脚本 我在其中尝试旋转 Y 轴标题 import matplotlib pyplot as plt
  • Xstream jodatime 本地日期显示

    我正在使用 xstrem 将 jodatime 本地日期序列化为 xml 然而 当输出生成的 xml 时 LocalDate 的格式并不易于阅读 见下文
  • 在 javac 中禁用 StringBuilder 优化

    在 Java 中使用普通字符串连接时 javac 会在可以使用的地方对其进行优化StringBuilder相反 或 Java 5 之前的 StringBuffer 就我而言 关闭所有这些 然后使用 bog 标准 append 方法进行字符串
  • 如何自动调整tinyMCE的大小?

    我有一个设置在 TextArea 上的 TinyMCE 并且我希望该编辑器区域始终占据其父 div 的所有空间 我有一个 JS 函数 可以获取当前空间并将 textarea style height 设置为它 但是当我启用 TinyMCE
  • 在 Android 应用程序中更改 HttpClient 的 OpenSSL 库

    我需要使用自定义 OpenSSL 库Http客户端在我的项目中 我已经编译了libcrypto so and libssl so对于 Android 并将文件放在 jniLibs 文件夹中 应用程序 Heartbleed Scanner 可
  • NodeJS 无限循环内存消耗

    我不知道这是否是 Node 或 V8 的错误 但如果我运行以下代码 节点进程会泄漏内存 GC 似乎从未启动 并且在几秒钟内它就消耗了 gt 1GB 的内存 这是意想不到的行为 我错过了什么吗 这是代码 for console log 1 1
  • WPF 中的身份验证和角色

    我正在WPF中做一个项目 我需要对用户进行身份验证并根据角色提供模块的可访问性 我有更好的方法在 WPF 中实现这一目标吗 这部分取决于您需要代码的安全程度 不过 对于所有用例 请使用模型 视图 视图模型模式 在每个 ViewModel 中
  • ContextWrapper 中的 NullPointer 异常

    我有一个名为 FileGeneration 的类 它扩展了 Activity在 FileGeneration 中我有一个名为 protected OutputStream openAndWriteFile Set the Context m
  • Internet Explorer 9 拖放 (DnD)

    有谁知道为什么以下网站拖放示例 以及许多其他在线教程 在 Internet Explorer 9 中不起作用 Chrome FireFox 和 Safari 都可以 http www html5rocks com tutorials dnd
  • Java 密钥库未通过 PKCS12 完整性检查,但 keytool 可以工作

    我有一些 PCKS12 证书 由两个环境以不同的方式提供服务 当我们上传到DEV环境时 java就可以解析它了 但它在产品上失败了 服务器是 Microsoft DotNet 解决方案 负责证书操作 生成的密钥库的密码为空 当我在 Wind
  • 如何修复 iframe 页面重新加载时的 chrome 闪烁

    在 iframe 中重新加载内容时 Chrome 会闪烁 是否可以通过任何方式避免这种情况 考虑 用 js 包装 a links 会产生一些神奇的效果 content html 中的元标记 我对 iframe 中的 html 有源代码控制
  • 使用“Powered By Chrome”和操作菜单打开自定义 WebView

    我最近注意到 当在一些 Android 应用程序中打开链接时 它们具有相似的外观和感觉 并且自定义操作菜单在自定义菜单下方带有 由 Chrome 提供支持 这里面使用了什么组件还是仍然是 ChromiumWebView 希望我希望将它们添加