UI State建模|如何一步步設(shè)計(jì)UI State。

在【探討UI架構(gòu)演化】一文中介紹,在UI架構(gòu)發(fā)展到一定階段,為了實(shí)現(xiàn)UI和業(yè)務(wù)邏輯解耦,引入了UI State。

UI State(UI 狀態(tài))指能夠完整決定UI長(zhǎng)什么樣的“最小”信息集合。

UI State引入后,可以說(shuō)UI架構(gòu)的演化就是圍繞它進(jìn)行的,統(tǒng)一狀態(tài)管理解決狀態(tài)分散問(wèn)題;引入U(xiǎn)I State 狀態(tài)機(jī),使?fàn)顟B(tài)變化必須可追蹤、可推導(dǎo);構(gòu)建聲明式UI框架,使得UI可以自動(dòng)從狀態(tài)生成等等。

UI State是如此重要,但如何給UI State一步步建模的文章卻很少,本文就來(lái)一起探討下這個(gè)問(wèn)題。

在探討這個(gè)話題之前,我們有必要再次深挖下 UI State到底是什么,它具備哪些核心特性。


一、UI State是什么?

狀態(tài)(State)是在設(shè)計(jì)者的認(rèn)知下,能夠完整決定 UI長(zhǎng)什么樣的最小信息集合。

它具備四個(gè)特性:

  • 充分性:“State+UI設(shè)計(jì)完全可推導(dǎo)出界面;
  • 最小性:沒(méi)有冗余信息,任何一個(gè)信息都不能由其他信息推斷而來(lái);
  • 一致性:不存在“非法組合”,就是說(shuō)要避免狀態(tài)字段組合出“不可能業(yè)務(wù)”狀態(tài);
  • 可演化性:當(dāng)需求變化時(shí),State 能以“最小范圍、最少修改、最低風(fēng)險(xiǎn)”完成新增能力。

注意

  1. 由于設(shè)計(jì)者認(rèn)知有限,所以這些特性都是相對(duì)的:UI State 建模不是“一次性正確”,而是一個(gè)不斷逼近最優(yōu)的過(guò)程。
  2. UI State是狀態(tài)自由度,UI設(shè)計(jì)是視覺(jué)自由度,State 決定“為什么變”,設(shè)計(jì)決定“怎么變”,** 若一個(gè)變量在UI設(shè)計(jì)變的時(shí)候就要改變,那就不能加入到UI State中。**
    ?比如:
  • 在游戲中, 高興是狀態(tài),每個(gè)角色高興起來(lái)什么樣子是UI設(shè)計(jì);
  • 在天氣App中,陰、晴、雨、雪是天氣類型狀態(tài),陰天、晴天、雨天、雪天圖標(biāo)或者頁(yè)面什么樣子是UI設(shè)計(jì)。

二、UI State建模流程

UI State 建模 = 從“UI變化”反推“變化原因”,再?gòu)脑蛑泻Y選“最小控制變量集合”。

有4個(gè)關(guān)鍵流程:

  • ① 看變化(UI有哪些不同狀態(tài))

  • ② 找觸發(fā)(這些變化為什么發(fā)生)

  • ③ 抽語(yǔ)義(抽象出“業(yè)務(wù)含義”)

  • ④ 壓狀態(tài)(只保留最小集合)

接下來(lái)我以一個(gè)手機(jī)天氣頁(yè)面為例來(lái)具體展開(kāi):

天氣頁(yè)面哈哈哈

?? Step 1:列出所有的UI變化

這一步,我們要從UI交互中把“會(huì)變化的東西”全部列出來(lái)。

目前我總結(jié)一套方法,按照這套方法基本可以保證找全變化不遺漏。

1、拿到UI 交互稿,從上到下,從左到右,進(jìn)行掃描,觀察和思考每一項(xiàng)是否會(huì)變化;

2、對(duì)于每一項(xiàng)UI思考進(jìn)行4個(gè)維度思考,來(lái)確定有哪些變化:

  • 業(yè)務(wù)數(shù)據(jù)變化(Data)

?? 這個(gè)UI 組件會(huì)不會(huì)因?yàn)椤皹I(yè)務(wù)數(shù)據(jù)”變化而變化?比如溫度、天氣類型。

  • 數(shù)據(jù)過(guò)程(LoadState)

?? 這個(gè)UI 組件 會(huì)不會(huì)因?yàn)椤皵?shù)據(jù)狀態(tài)”不同而變化?比如loading態(tài)、error態(tài)、成功態(tài)

  • 交互狀態(tài)(Interaction)

?? 這個(gè)UI組件會(huì)不會(huì)因?yàn)?“用戶行為”不同而變化?比如 選中、展開(kāi)/收起、滑動(dòng)

  • 系統(tǒng)狀態(tài)

??這個(gè)UI 會(huì)不會(huì)因?yàn)椤跋到y(tǒng)和環(huán)境”不同而變化?比如系統(tǒng)主題變了,系統(tǒng)定位城市變化了

3、若這個(gè)變化會(huì)因UI設(shè)計(jì)不同而變,那就不能加入變化清單中。

最后輸出的是→UI變化清單 ?

?? 主區(qū)域

城市名稱
當(dāng)前溫度
天氣描述

?? 環(huán)境信息

當(dāng)前PM2.5
當(dāng)前UV(紫外線強(qiáng)度)
當(dāng)前風(fēng)力

?? 曲線區(qū)域

溫度曲線
天氣曲線
風(fēng)力曲線
空氣質(zhì)量曲線
當(dāng)前時(shí)間標(biāo)記

?? 數(shù)據(jù)過(guò)程狀態(tài)變化

加載中
加載失敗
加載成功


? Step 2:逐個(gè)問(wèn)“為什么會(huì)變”

?? 對(duì)每個(gè)UI變化問(wèn):

? 是什么導(dǎo)致它變?

?? 主區(qū)域

溫度變化 → 溫度數(shù)據(jù)變化
天氣描述 → 天氣類型數(shù)據(jù)變化
城市變化 → 定位 +用戶選擇

?? 環(huán)境信息

PM2.5 → 空氣質(zhì)量數(shù)據(jù)
UV → 天氣紫外線數(shù)據(jù)
風(fēng) → 風(fēng)力數(shù)據(jù)

?? 曲線

溫度曲線變化 → 小時(shí)天氣數(shù)據(jù)
當(dāng)前溫度 → 當(dāng)前時(shí)間

?? 狀態(tài)

loading 加載中 → 數(shù)據(jù)請(qǐng)求過(guò)程中
error 錯(cuò)誤 → 數(shù)據(jù)請(qǐng)求請(qǐng)求失敗
success 成功→ 數(shù)據(jù)請(qǐng)求請(qǐng)求成功

?? 到這里你得了→“UI變化原因”集合。


?? Step 3:合并“同類原因”

把“本質(zhì)相同或者屬于一類的原因”做抽象+合并

溫度/ 天氣類型/風(fēng)力/PM2.5/UV
   ↓
??都屬于:天氣數(shù)據(jù)的一個(gè)維度
   ↓
?? 合并+抽象為
   ↓
WeatherData
loading  / success / error
   ↓
??本質(zhì)都是:數(shù)據(jù)加載狀態(tài)
   ↓
?? 抽象為:LoadState
當(dāng)前時(shí)間
 ↓
CurrentTime
定位中/定位成功/定位失敗
 ↓
合并為:LocationState

?? Step 4:識(shí)別“獨(dú)立變化維度”(關(guān)鍵能力)

?? 問(wèn)一個(gè)核心問(wèn)題:

它們之間會(huì)互相決定嗎?就是說(shuō) 把某一個(gè)數(shù)據(jù)去掉,是否可以由其他數(shù)據(jù)推算出來(lái)。

狀態(tài) 是否獨(dú)立
WeatherData ?
LoadState ?
LocationState ?
CurrentTime ?

?? 這些是:

? 獨(dú)立維度(正交)


?? Step 5:每個(gè)維度內(nèi)部建模

① WeatherData(核心數(shù)據(jù))

data class WeatherData(
    val currentTemp: Int,
    val minTemp: Int,
    val maxTemp: Int,
    val weather: String,
    val feelsLike: Int,  
    val pm25: Int,  
    val uvLevel: String,  
    val wind: String,  
    val airQuality: String,  
    val hourly: List<HourlyWeather\> ) 

② LoadState(互斥)

sealed class LoadState {
    object Loading
    object Success
    data class Error(val message: String)
}
// 注意 sealed 類似枚舉 狀態(tài)只能是其中一個(gè)

③ LocationState(互斥)

sealed class LocationState {
    object Locating
    data class Success(val city: String)
    object Failed
}

④ CurrentTimeState

data class CurrentTimeState(
    val currentHourIndex: Int
)

?? Step 6:組合為一個(gè)(不是混合)

data class WeatherPageState(
    val loadState: LoadState,
    val locationState: LocationState,
    val weatherData: WeatherData?,
    val currentTimeState: CurrentTimeState
)


小結(jié)

UI State 建模是一個(gè)逐步抽象的過(guò)程:從UI交互現(xiàn)象出發(fā),追溯原因,合并抽象,拆分維度,最終組為為一個(gè)最小且正交的狀態(tài)集合。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容