Android之調節屏幕亮度(文末附源碼)

一、需求分析

在使用微信或者支付寶的付款碼支付時,若是你點擊放大付款碼,就會跳轉到一個新的頁面去顯示大尺寸的付款碼,並且你會發現屏幕變亮了,這樣會便於掃碼機識別你的付款碼。當你付款成功退出付款碼放大的界面後,屏幕就會恢復到原先的亮度。我很早就注意到了這點,因此當我本身的項目須要作二維碼點擊放大功能時,我也在放大的同時把屏幕的界面調亮一點。儘管我當時比較輕鬆地實現了這個功能,可是當我編寫屏幕亮度工具類時,發現裏面其實內有乾坤。如今就讓咱們來系統學習一下。java

首先咱們要明確「屏幕亮度」是什麼。它其實包含了兩種狀況:android

**1. 當前窗口的亮度。**若是隻改變當前窗口的亮度的話,當你退出該窗口(好比銷燬了當前的Activity或者乾脆退出了應用),那麼屏幕就會恢復原先的亮度。也就是說,此處的改變只對當前的窗口有效。微信或支付寶在點擊放大付款碼後,改變的就是這個。 **2. 改變系統屏幕亮度。**在下拉的手機設置面板中,有一個改變屏幕亮度的進度條(下圖中的紅框),這裏改變的就是系統的屏幕亮度,適用於全部的窗口。git

二、準備工做

建立一個BrightnessActivity,而後在裏面放置兩個進度條,一個改變系統亮度,一個改變窗口亮度。爲了便於之後使用,咱們會把用到的方法都封裝到一個工具類中。因此再建立一個名稱爲BrightnessUtil的Kotlin文件,可是不要建立類,由於咱們會使用擴展成員的方式來編寫工具類。github

舒適提示:最近大半年都在使用Kotlin,這實在是一門很棒的語言,推薦你們學習。之後的博客我通常都會使用Kotlin了。小程序

在這裏因爲文字較多,我總結了一份高階Android技術大綱和學習資料以及 項目源碼 免費分享給你們,文末有領取!segmentfault

三、改變當前窗口亮度

首先來看看怎麼改變窗口亮度。十分簡單,只需改變窗口屬性中的屏幕亮度(screenBrightness)一項。讓咱們直接來看代碼:微信小程序

/**
 * 當前窗口亮度
 * 範圍爲0~1.0,1.0時爲最亮,-1爲系統默認設置
 */
var Activity.windowBrightness
    get() = window.attributes.screenBrightness
    set(brightness) {
        //小於0或大於1.0默認爲系統亮度
        window.attributes = window.attributes.apply {
            screenBrightness = if (brightness > 1.0 || brightness < 0) -1.0F else brightness
        }
    }
複製代碼

改變窗口亮度的上下文必須是Activity,因此我給Activity加了一個擴展屬性windowBrightness,它的值就是當前的窗口亮度,改變它的值就能夠改變窗口亮度。它的範圍是0~1.0,從0到1.0亮度逐漸增大;若是賦值爲-1,那就表示跟隨系統的亮度。性能優化

使用起來也很簡單:bash

tvWindowBright.text = "當前窗口亮度=$windowBrightness"
        sbWindowBright.progress = if (windowBrightness > 0) (windowBrightness * 100).toInt() else 0
        sbWindowBright.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
            override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
                windowBrightness = progress.toFloat() / 100F
                tvWindowBright.text = "當前窗口亮度=$windowBrightness"
            }

            override fun onStartTrackingTouch(seekBar: SeekBar?) {
            }

            override fun onStopTrackingTouch(seekBar: SeekBar?) {
            }

        })
複製代碼

沒有接觸過Kotlin的小夥伴們可能會不知道這屬性在Java中怎麼用?畢竟咱們連類名都沒有看到。其實Kotlin會默認爲Java生成一個「類名+kt」的類,屬性則會生成getter和setter靜態方法。因此在Java代碼中只須要 這麼寫:微信

BrightnessUtilKt.getWindowBrightness(Activity);
        BrightnessUtilKt.setWindowBrightness(Activity,brightness);
複製代碼

四、改變系統亮度

比起改變窗口亮度,改變系統亮度就要麻煩一點了。做爲我的,咱們改變世界都是不容易的,那麼一個應用想要改變系統天然也不會垂手可得。

4.1 清單文件申請權限

第一步,咱們須要到AndroidManifest.xml中申請權限:

<uses-permission android:name="android.permission.WRITE_SETTINGS"
        tools:ignore="ProtectedPermissions" />
複製代碼

之因此加上tools:ignore="ProtectedPermissions"是由於改變系統設置的權限通常只歸系統App全部,因此編譯器會報一個警告,加上這個能夠忽略警告。

4.2 申請動態權限

若是你的手機系統是Android6.0以上的,那麼還得動態申請權限。系統設置權限的動態申請有點特別,它須要跳轉到系統的「可修改系統設置」界面,讓用戶決定是否容許當前應用修改系統設置,而後再在onActivityResult中處理回調結果。

咱們在進入BrightnessActivity時就動態申請權限,代碼以下:

//修改系統屏幕亮度須要修改系統設置的權限
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            //若是當前平臺版本大於23平臺
            if (!Settings.System.canWrite(mContext)) {
                val intent = with(Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS)) {
                    data = Uri.parse("package:$packageName")
                    this
                }
                startActivityForResult(intent, RQ_WRITE_SETTINGS)
            } else {
                changeSystemBrightness()
            }
        } else {
            //Android6.0如下的系統則直接修改亮度
            changeSystemBrightness()
        }
複製代碼

首先調用Settings.System.canWrite(Context)判斷手機系統,Android6.0如下的直接容許修改亮度的操做;Android6.0以上的則要進一步判斷是否已經得到了修改系統設置的權限,沒有的話就要打開以下界面去設置。

不管用戶是否受權,咱們都須要一個回調,這時onActivityResult就能夠派上用場了:

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        when (requestCode) {
            RQ_WRITE_SETTINGS -> {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    if (Settings.System.canWrite(mContext)) {
                        shortToast("已獲取權限")
                        changeSystemBrightness()
                    } else {
                        shortToast("你拒絕了權限")
                    }
                }
            }
        }
    }
複製代碼

代碼很簡單,就不作過多解釋了。

4.3 去除自動亮度

前面咱們雖然解決了權限問題,可是還要考慮到一個實際狀況,那就是用戶可能會設置了自動亮度,在這個前提下是沒法改變系統屏幕亮度的。因此這裏要作兩步處理:

  1. 判斷用戶是否開啓了自動亮度;
  2. 若是當前開啓了自動亮度,則須要將其關閉。
4.3.1 判斷是否自動亮度

咱們在工具類中添加isAutoBrightness屬性,它只有Getter方法,返回一個布爾值。這裏調用Settings.System.getInt()方法,第二個參數傳入Settings.System.SCREEN_BRIGHTNESS_MODE表示咱們要獲取系統屏幕亮度模式,若是是Settings.System.SCREEN_BRIGHTNESS_MODE,則表示當前自動亮度模式。

val isAutoBrightness:Boolean
    get() = try {
        Settings.System.getInt(
            AndUtil.appContext.contentResolver,
            Settings.System.SCREEN_BRIGHTNESS_MODE
        ) == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC
    } catch (e: Settings.SettingNotFoundException) {
        e.printStackTrace()
        false
    }
複製代碼
4.3.2 設置開啓和關閉自動亮度

前面咱們獲取了系統亮度模式,經過設置它的值,咱們就能夠控制自動亮度模式的開關了。 在工具類中建立一個setAutoBrightness()函數,若是設置成功就返回true。這裏用到的是Settings.System.putInt(),第二個參數即爲咱們要設置的亮度模式。當參數enable爲true時就是自動模式了。

/**
 * 設置是否開啓自動亮度
 * @param enable : 爲true時開啓,false時關閉
 * @return 設置成功返回true
 */
fun setAutoBrightness(enable: Boolean) = Settings.System.putInt(
    AndUtil.appContext.contentResolver, Settings.System.SCREEN_BRIGHTNESS_MODE,
    if (enable) Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC else Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL
)
複製代碼

4.4 封裝改變系統屏幕亮度屬性

如今咱們總算能夠編寫修改系統亮度的代碼了。跟修改窗口亮度同樣,咱們這裏也使用了一個屬性,命名爲systemBrightness

/**
 * 系統屏幕亮度,須要WRITE_SETTINGS權限,並在代碼中申請系統設置權限
 * 範圍爲0~255
 */
var systemBrightness
    get() = try {
        Settings.System.getInt(AndUtil.appContext.contentResolver, Settings.System.SCREEN_BRIGHTNESS)
    } catch (e: Settings.SettingNotFoundException) {
        e.printStackTrace()
        -1
    }
    @RequiresPermission(Manifest.permission.WRITE_SETTINGS)
    set(@IntRange(from = 0, to = 255) brightness) {
        if (isAutoBrightness) {
            //若是當前是自動亮度,則關閉自動亮度
            setAutoBrightness(false)
        }
        val uri = Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS)
        Settings.System.putInt(AndUtil.appContext.contentResolver, Settings.System.SCREEN_BRIGHTNESS, brightness)
        AndUtil.appContext.contentResolver.notifyChange(uri, null)
    }
複製代碼

這裏咱們重點來看設置系統亮度,也就是set()裏面的代碼。首先判斷當前是否開啓了自動亮度模式,若是是則將其關閉。後面的代碼相似於setAutoBrightness(),都是在Settings.System.putInt()中賦值,不一樣的是還要調用Context.contentResolver.notifyChange()方法去通知系統咱們已經修改了屏幕亮度,這樣設置的值纔會起做用。另外,要注意系統屏幕亮度的取值範圍是0~255。

最後固然是設置SeekBar的監聽了:

private fun changeSystemBrightness() {
        sbSystemBright.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
            override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
                systemBrightness = progress * 255 / 100
                tvSystemBright.text = "系統亮度=$systemBrightness"
            }

            override fun onStartTrackingTouch(seekBar: SeekBar?) {
            }

            override fun onStopTrackingTouch(seekBar: SeekBar?) {
            }

        })
    }
複製代碼

實現的效果以下:

視頻錄製看不出亮度的變化,但真機上是沒有問題的。

五、後記

本文分析了屏幕亮度的類型,並給出了設置的方法。其中,設置系統屏幕亮度時要格外注意動態權限申請和自動亮度模式的影響。

最後給一下主要的源碼:

BrightnessUtil

BrightnessActivity

本人近十年開發經驗,按期分享Android高級技術及經驗分享,歡迎你們關注~(分享內容包括不限於高級UI、性能優化、移動架構師、NDK、混合式開發(ReactNative+Weex)微信小程序、Flutter等全方面的Android進階實踐技術;但願能幫助到你們,也節省你們在網上搜索資料的時間來學習,也能夠分享動態給身邊好友一塊兒學習!)

相關文章
相關標籤/搜索