Android 修改SystemUI 音量条的声音进度条样式

news2024/11/27 10:40:53

一、前言

        Android System UI 开发经常会遇到修改音量进度条样式的需求,主要涉及的类有VolumeDialogImpl与xml文件,接下来会逐步实现流程。先看看效果。

修改前

修改后

二、找到对应类

通过aidegen 打断点调试对应代码类VolumeDialogImpl定位到volume_dialog就是对话框布局。mDialog.setContentView(R.layout.volume_dialog);

类路径:frameworks/base/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java

private void initDialog() {
        mDialog = new CustomDialog(mContext);

        initDimens();

        mConfigurableTexts = new ConfigurableTexts(mContext);
        mHovering = false;
        mShowing = false;
        mWindow = mDialog.getWindow();
        mWindow.requestFeature(Window.FEATURE_NO_TITLE);
        mWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
        mWindow.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND
                | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR);
        mWindow.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
                | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
                | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
        mWindow.addPrivateFlags(WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY);
        mWindow.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
        mWindow.setWindowAnimations(com.android.internal.R.style.Animation_Toast);
        WindowManager.LayoutParams lp = mWindow.getAttributes();
        lp.format = PixelFormat.TRANSLUCENT;
        lp.setTitle(VolumeDialogImpl.class.getSimpleName());
        lp.windowAnimations = -1;
        lp.gravity = mContext.getResources().getInteger(R.integer.volume_dialog_gravity);
        mWindow.setAttributes(lp);
        mWindow.setLayout(WRAP_CONTENT, WRAP_CONTENT);

        mDialog.setContentView(R.layout.volume_dialog);
        mDialogView = mDialog.findViewById(R.id.volume_dialog);
        mDialogView.setAlpha(0);
        mDialog.setCanceledOnTouchOutside(true);

三、音量条代码

 @SuppressLint("InflateParams")
    private void initRow(final VolumeRow row, final int stream, int iconRes, int iconMuteRes,
            boolean important, boolean defaultStream) {
        row.stream = stream;
        row.iconRes = iconRes;
        row.iconMuteRes = iconMuteRes;
        row.important = important;
        row.defaultStream = defaultStream;
        row.view = mDialog.getLayoutInflater().inflate(R.layout.volume_dialog_row, null);
        row.view.setId(row.stream);
        row.view.setTag(row);
        row.header = row.view.findViewById(R.id.volume_row_header);
        row.header.setId(20 * row.stream);
        if (stream == STREAM_ACCESSIBILITY) {
            row.header.setFilters(new InputFilter[] {new InputFilter.LengthFilter(13)});
        }
        row.dndIcon = row.view.findViewById(R.id.dnd_icon);
        row.slider = row.view.findViewById(R.id.volume_row_slider);
        row.slider.setOnSeekBarChangeListener(new VolumeSeekBarChangeListener(row));
        row.number = row.view.findViewById(R.id.volume_number);

        row.anim = null;

        final LayerDrawable seekbarDrawable =
                (LayerDrawable) mContext.getDrawable(R.drawable.volume_row_seekbar);

        final LayerDrawable seekbarProgressDrawable = (LayerDrawable)
                ((RoundedCornerProgressDrawable) seekbarDrawable.findDrawableByLayerId(
                        android.R.id.progress)).getDrawable();

        row.sliderProgressSolid = seekbarProgressDrawable.findDrawableByLayerId(
                R.id.volume_seekbar_progress_solid);
        final Drawable sliderProgressIcon = seekbarProgressDrawable.findDrawableByLayerId(
                        R.id.volume_seekbar_progress_icon);
        row.sliderProgressIcon = sliderProgressIcon != null ? (AlphaTintDrawableWrapper)
                ((RotateDrawable) sliderProgressIcon).getDrawable() : null;

        row.slider.setProgressDrawable(seekbarDrawable);

        row.icon = row.view.findViewById(R.id.volume_row_icon);

        row.setIcon(iconRes, mContext.getTheme());

        if (row.icon != null) {
            if (row.stream != AudioSystem.STREAM_ACCESSIBILITY) {
                row.icon.setOnClickListener(v -> {
                    Events.writeEvent(Events.EVENT_ICON_CLICK, row.stream, row.iconState);
                    mController.setActiveStream(row.stream);
                    if (row.stream == AudioManager.STREAM_RING) {
                        final boolean hasVibrator = mController.hasVibrator();
                        if (mState.ringerModeInternal == AudioManager.RINGER_MODE_NORMAL) {
                            if (hasVibrator) {
                                mController.setRingerMode(AudioManager.RINGER_MODE_VIBRATE, false);
                            } else {
                                final boolean wasZero = row.ss.level == 0;
                                mController.setStreamVolume(stream,
                                        wasZero ? row.lastAudibleLevel : 0);
                            }
                        } else {
                            mController.setRingerMode(
                                    AudioManager.RINGER_MODE_NORMAL, false);
                            if (row.ss.level == 0) {
                                mController.setStreamVolume(stream, 1);
                            }
                        }
                    } else {
                        final boolean vmute = row.ss.level == row.ss.levelMin;
                        mController.setStreamVolume(stream,
                                vmute ? row.lastAudibleLevel : row.ss.levelMin);
                    }
                    row.userAttempt = 0;  // reset the grace period, slider updates immediately
                });
            } else {
                row.icon.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
            }
        }
    }

四、音量条布局则位于volume_dialog_row.xml中

<!--
     Copyright (C) 2015 The Android Open Source Project

     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:tag="row"
    android:layout_height="wrap_content"
    android:layout_width="@dimen/volume_dialog_panel_width"
    android:clipChildren="false"
    android:clipToPadding="false"
    android:gravity="center"
    android:paddingTop="@dimen/volume_dialog_ringer_rows_padding"
    android:paddingBottom="@dimen/volume_dialog_ringer_rows_padding"
    android:background="@drawable/volume_row_rounded_background"
    android:theme="@style/volume_dialog_theme">

    <LinearLayout
        android:layout_height="wrap_content"
        android:layout_width="@dimen/volume_dialog_panel_width"
        android:gravity="center"
        android:layout_gravity="center"
        android:orientation="vertical" >
        <TextView
            android:id="@+id/volume_row_header"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:ellipsize="end"
            android:maxLength="10"
            android:maxLines="1"
            android:visibility="gone"
            android:textColor="?android:attr/colorControlNormal"
            android:textAppearance="@style/TextAppearance.Volume.Header" />
        <FrameLayout
            android:id="@+id/volume_row_slider_frame"
            android:layout_width="match_parent"
            android:layout_height="@dimen/volume_row_slider_height">
            <SeekBar
                android:id="@+id/volume_row_slider"
                android:paddingLeft="0dp"
                android:paddingRight="0dp"
                android:paddingStart="0dp"
                android:paddingEnd="0dp"
                android:clickable="true"
                android:layout_width="@dimen/volume_row_slider_height"
                android:layout_height="match_parent"
                android:layout_gravity="center"
                android:thumb="@null"
                android:splitTrack="false"
                android:progressDrawable="@drawable/volume_row_seekbar"
                android:background="@null"
                android:layoutDirection="ltr"
                android:rotation="270" />
            <include layout="@layout/volume_dnd_icon"/>
        </FrameLayout>

        <com.android.keyguard.AlphaOptimizedImageButton
            android:visibility="gone"
            android:id="@+id/volume_row_icon"
            style="@style/VolumeButtons"
            android:layout_width="@dimen/volume_dialog_tap_target_size"
            android:layout_height="@dimen/volume_dialog_tap_target_size"
            android:background="@drawable/ripple_drawable_20dp"
            android:layout_marginBottom="@dimen/volume_dialog_row_margin_bottom"
            android:tint="@color/accent_tint_color_selector"
            android:soundEffectsEnabled="false" />
    </LinearLayout>

</FrameLayout>

对SeekBar音量条进行修改增加样式

android:thumb="@drawable/ic_launcher_round"
android:progressDrawable="@drawable/volume_row_seekbar"

其中icon progress 就是一张ic_launcher_round图片
而volume_row_seekbar.xml

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@android:id/background"
          android:gravity="center_vertical|fill_horizontal">
        <shape android:shape="rectangle">
            <size android:height="@dimen/seek_bar_height" />
            <solid android:color="#eeeeee" />
            <corners android:radius="@dimen/seek_bar_corner_radius" />
        </shape>
    </item>
    <item android:id="@android:id/progress"
          android:gravity="center_vertical|fill_horizontal">
        <scale android:scaleWidth="100%">
            <shape android:shape="rectangle">
                <size android:height="@dimen/seek_bar_height" />
                <solid android:color="#0091ff" />
                <corners android:radius="@dimen/seek_bar_corner_radius" />
            </shape>
        </scale>
    </item>
</layer-list>

五、待续

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2060697.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

中国第一起名大师的老师颜廷利: 名字中的姓氏家谱字辈的最新解析

在探讨文化和文明的深层含义时&#xff0c;我们常常发现&#xff0c;对传统的尊重与现代价值观之间存在着一种微妙的张力。这种张力在一个简单的例子中得到了生动的体现&#xff1a;姓名的选择。 在古代社会&#xff0c;名字不仅仅是个体的标识&#xff0c;更是家族传承和社会结…

JavaScript_11_练习:小米搜索框案例(焦点事件)

效果图 代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>练习&#xff1a;小米搜索框案例&#…

第十二届青少年蓝桥杯Python组省赛试题

一、选择题 1.设s’Hello Lan Qiao’,执行print(s[4:11])输出的结果为()。 *选择题严禁使用程序验证 A、lo Lan Qi B、lo Lan Q C、o Lan Qi D、o Lan Q 提示&#xff1a;切片 2.循环语句for i in range(8,-4,-2):执行了几次循环()。 *选择题严禁使用程序验证 A、4 B、5 C、6…

LabVIEW锅炉燃烧远程监控系统

随着信息技术的发展&#xff0c;远程监控技术已经广泛应用于各种工业过程。开发了一个基于LabVIEW和互联网技术的锅炉燃烧远程监控系统&#xff0c;该系统不仅提高了锅炉运行的安全性和效率&#xff0c;还具备了故障远程诊断的功能&#xff0c;为锅炉管理提供了一种全新的解决方…

[论文笔记]Improving Retrieval Augmented Language Model with Self-Reasoning

引言 今天带来一篇百度提出的关于提升RAG准确率的论文笔记&#xff0c;Improving Retrieval Augmented Language Model with Self-Reasoning。 为了简单&#xff0c;下文中以翻译的口吻记录&#xff0c;比如替换"作者"为"我们"。 检索增强语言模型(Retrie…

谷歌浏览器自动填充密码怎么设置

谷歌浏览器的自动填充密码功能为用户提供了一种安全而便捷的在线体验&#xff0c;让用户在下次登录网站的时候&#xff0c;减去重复输入密码的麻烦。下面就给大家分享一下关于谷歌浏览器自动填充密码的相关内容&#xff0c;让你更加轻松的管理自己的账户。 谷歌浏览器自动填充密…

26.删除有序数组中的重复项---力扣

题目链接&#xff1a; . - 力扣&#xff08;LeetCode&#xff09;. - 备战技术面试&#xff1f;力扣提供海量技术面试资源&#xff0c;帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。https://leetcode.cn/problems/remove-duplicates-from-sorted-array/descript…

使用maven快速生成打包文件

最近在部署基于SpringBoot开发的项目时&#xff0c;由于微服务较多&#xff0c;本地工程编译后只得出一个JAR包&#xff0c;部署起来实在不方便&#xff0c;因此总想着怎么偷偷懒&#xff0c;执行一次命令编译出整个部署的文件。先说结果&#xff0c;最后期望打包的目录如下&am…

【数据结构篇】~双向链表(附源码)

前言 学完了单链表&#xff0c;还有其他等着我们去攻克&#xff0c;链表其实分为8种 &#xff0c;共2 * 2 * 28种 之前的单链表是不带头单向不循环链表 一、双向链表 注意&#xff1a;这里的“带头”跟前面我们说的“头结点”是两个概念&#xff0c;实际前面的在单链表阶段称…

百度地图路书实现历史轨迹回放、轨迹回放进度、聚合点、自定义弹框和实时监控视频、多路视频轮巡播放

前言 分享一个刚做完项目集成技术&#xff0c;一个车辆行驶轨迹监控、行车视频监控、对特种车辆安全监管平台&#xff0c;今年政府单位有很多监管平台项目&#xff0c;例如&#xff1a;渣土车监控、租出车监管、危害气体运输车监管等平台&#xff0c;这些平台都有车辆行驶轨迹…

QT基础知识5

思维导图 client.cpp #include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget), socket(new QTcpSocket(this))//给客户端实例化分配空间 {ui->setupUi(this);//初始化界面ui->msgEdit-&…

微盟年中报:聚焦主业降本增效,经调整净亏损同比大幅收窄81.4%

8月21日&#xff0c;微盟集团&#xff08;2013.HK&#xff09;发布2024年中期业绩报告。在充满挑战的市场环境中&#xff0c;公司积极进行业务布局优化调整&#xff0c;战略性聚焦核心业务&#xff0c;集团总收入达8.67亿元人民币&#xff0c;整体毛利率保持平稳。报告期内&…

语言基础/单向链表的构建和使用(含Linux中SLIST的解析和使用)

文章目录 概述简单的链表描述链表的术语简单实现一个单链表 Linux之SLIST机理分析结构定义单链表初始化单链表插入元素单链表遍历元素单链表删除元素 Linux之SLIST使用实践纯C中typedef重命名带来的问题预留 概述 本文讲述了数据结构中单链表的基本概念&#xff0c;头指针、头…

监控状态流图中的测试点

此示例展示了如何将数据或状态指定为测试点&#xff0c;你可以在仿真过程中使用浮动范围绘制这些测试点或将其记录到MATLAB基本工作区。 关于状态流图中的测试点 Stateflow测试点是您可以在模拟过程中观察到的信号&#xff0c;例如&#xff0c;通过使用浮动范围块。您可以使用…

进阶SpringBoot之 SpringSecurity(1)环境搭建

Spring Security 中文文档 Spring Security 是一个 Java 框架&#xff0c;用于保护应用程序的安全性 它提供认证&#xff08;authentication&#xff09;、授权&#xff08;authorization&#xff09;和保护&#xff0c;以抵御常见的攻击 Spring Security 基于过滤器链的概念…

Linux虚拟机磁盘管理-创建新磁盘分区

1.查看新加的硬盘情况 b英文为block表示块 查看磁盘信息方法一&#xff1a;ll /dev/sd* 查看磁盘信息方法二&#xff1a;lsblk 2.创建分区 1&#xff09;创建磁盘分区 以sdb这块磁盘进行分区为例 一个磁盘最多分4个分区 输入w进行确认创建一个房间&#xff0c;这个房间就能…

Nginx: 配置项之main段核心参数用法梳理

概述 我们了解下配置文件中的一个全局段&#xff0c;有哪些配置参数&#xff0c;包括后面的 events 字段&#xff0c;有哪些配置参数这里面也有一些核心参数, 对于我们Nginx运行的性能也是有很重要的帮助我们现在首先关注整个 main 段的一个核心参数用法所谓 main 段&#xff…

前后端分离开发:用 Apifox 高效管理 API

目录 1.前后台分离开发介绍 2.API 2.1 APIfox介绍 2.2 接口文档管理 1.前后台分离开发介绍 前端开发有2种方式&#xff1a;「前后台混合开发」和「前后台分离开发」。 前后台混合开发&#xff0c;顾名思义就是前台后台代码混在一起开发&#xff0c;如下图所示&#xff1a…

5. 数据结构—栈的实际案例

1. 10进制转8进制 void conversion(int n){LinkStack S;InitStack(S);while(n){Push(S,n%8);nn/8;}while(!StackEmpty(S)){int x;Pop(S,x);printf("%d",x);} } 2. 括号匹配 bool Matching(){LinkStack S;char ch,x;InitStack(S);while(cin>>ch){if(ch#)bre…

tomcat的session会话保持

1.Memcached简介 Memcached 只支持能序列化的数据类型&#xff0c;不支持持久化&#xff0c;基于 Key-Value 的内存缓存系统。 memcached虽然没有像redis 所具备的数据持久化功能&#xff0c;比如 RDB 和 AOF 都没有&#xff0c;但是可以通过做集群同步的方式&#xff0c; 让各…