WouoUI-PageVersion
寫在前面
簡介&致謝
-
Air001的TestUI例子的b站的演示視頻
-
Air001的LittleClock例子的b站演示視頻: https://www.bilibili.com/video/BV1J6421g7H1/
-
Stm32的TestUI例子的b站演示視頻: https://www.bilibili.com/video/BV1mS421P7CZ/
所有演示的工程文件都使用zip壓縮包上傳在對應(yīng)的文件夾下。
本項目的Github鏈接為:https://github.com/Sheep118/WouoUI-PageVersion
這是一個改動自WouoUI(1.2版本)的純C語言,無依賴庫,只適用于128*64OLED的代碼框架,將WouoUI抽象出一部分統(tǒng)一的接口,以方便快速構(gòu)建一個具有類似WouoUI風格的OLEDUI。
在此十分感謝WouoUI作者開源WouoUI的源碼????,這是WouoUI的Github鏈接和作者的b站鏈接。
(推薦大家可以去閱讀下WouoUI的源代碼(Arduino),寫得非常好,邏輯相當清晰)。
想法由來和一些啰嗦
WouoUIPage版的想法是源自我自己想將使用WouoUI用到自己設(shè)置的一個很簡單時鐘上,但由于使用的芯片是合宙的Air001(為啥用這個芯片,因為手頭這個芯片剩的比較多??),不過,因為這個芯片只有4k的RAM和32k的Flash,移植U8g2后再移植WouoUI,芯片的Flash和RAM基本上就用完了,很難再寫應(yīng)用層的代碼,因此,我自己根據(jù)128*64的OLED的需要,參考很多資料自己寫了圖形層的繪制驅(qū)動(oled_g.c和oled_g.h)。同時,把WouoUI用尚不成熟面向?qū)ο蟮乃枷胗肅語言重寫了一遍并抽象出接口(oled_ui.c和oled_ui.h),根據(jù)自己的需要,還加入了滾動的時鐘的頁面,至此,WouoUI Page版就此成型。
至于為何取名叫WouoUI Page版,一方面是由于這個項目本來就是從原來WouoUI改動而來,另一方面,抽象出來的接口都以一個頁面(Page)為最小單位,所以取名叫WouoUI Page版??。
WouoUIPage版和WouoUI不同
因為我參考原作者的WouoUI是1.2版本的,因此,作者后來更新的一些新的動畫沒有加進來(之后看是否有空,再決定是否加進來了??, 到時候估計也需要換個芯片了,air001Falsh太小了,而且提供的例程也只支持keil內(nèi)的O0優(yōu)化)。
WouoUI | Page版 | |
---|---|---|
依賴庫 | 依賴U8g2庫,適用性廣,拓展性強 ;但消耗的RAM和FLASH可能會較多(特別是對于使用C語言開發(fā)而不是使用Arduino開發(fā)的情況) | 自己寫的圖形層驅(qū)動文件,功能比較少只提供必須用到的,純C語言編寫,對內(nèi)存有限,使用C開發(fā)單片機來說比較合適;但由于沒有使用U8g2庫,適用性、拓展性差。(后面看看自己有沒有時間將上面的這部分抽象移植到U8g2圖形庫上) |
接口 | 原作者的所有代碼都在一個.ino文件中完成,方便查看源碼; 但需要讀懂一部分源碼才能二次開發(fā) | 統(tǒng)一了一部分接口,并做了抽象,二次開發(fā)時只需要按接口文檔來使用提供的接口函數(shù) |
適用性 | 原作者開發(fā)了適應(yīng)多個屏幕尺寸的版本??(這點我自己覺得可能很難做到) | 因為項目的需要,Page版只有128*64這一個尺寸適配,我也沒有做其他屏幕的開發(fā)。 |
移植說明
WouoUIPage版源代碼非常簡單,只有oled_g.c , oled_ui.c 兩個.c文件和 oled_g.h , oled_ui.h ,oled_conf.h , oledfont.h 和 oled_port.h 5個.h文件組成。
本項目的文件說明
|---Csource
|---src (這個文件夾是WouoUIPage最主要的源代碼文件,移植時主要用這里面的幾個文件)
|---example (這個是使用WouoUIPage所提供的接口構(gòu)建的一些應(yīng)用的例子,只有對應(yīng).c.h文件)
|---ProjectExamples (這個文件夾內(nèi)放著使用WouoUIPage的工程的參考,按主控的類型劃分,為移植時提供一些參考)
|---Image (存放一些展示用的圖片)
移植大致流程
移植時,可以參考ProjectExamples文件夾下的工程(工程有目前有使用Air001和STM32的例子)
-
將上述說明的7個文件包含在工程中。
-
根據(jù)自己128*64的OLED屏和自己使用的MCU完成一個oled_port.c文件,這個文件包含提供的oled_port.h文件,并實現(xiàn)oled_port.h中聲明的兩個函數(shù)
OLED_Init
OLED_SendBuff
。一般這兩個函數(shù)OLED廠商都會提供對應(yīng)的代碼,或者根據(jù)廠商的代碼簡單修改也能得到。
(這里建議先測試廠商的代碼,確保能夠驅(qū)動OLED屏,再移植WouoUIPage)
void OLED_Init(void);
這個函數(shù)需要實現(xiàn)OLED的底層初始化,如IIC接口/SPI接口 和 D/C 、RST 等IO口的初始化
void OLED_SendBuff(uint8_t buff[8][128]);
這個函數(shù)需要實現(xiàn)128*64的OLED顯存的刷新,即將傳入的數(shù)組全部寫到OLED顯存中
(這里建議硬件上使用SPI或者至少是硬件IIC,軟件IIC刷新速率可能太慢,對動畫效果有影響)
OLED_LOG
這個宏是用于打印一些錯誤提示信息的,但因為現(xiàn)在暫時還沒有使用到??,不用理會。
OK ,到這里的話,就算移植結(jié)束了(感覺說是復(fù)制更為合適,因為基本沒有改啥??),可以開始使用WouoUIPage提供的接口了。
整體框架說明和配置文件oled_conf.h
整體框架說明
如下圖所示,WouoUIPage版以6種頁面為基礎(chǔ)來構(gòu)建UI,內(nèi)部有一個消息隊列用于接收外界的消息,每個頁面都有一個回調(diào)函數(shù),會將當前頁面選中項的信息傳入,對應(yīng)操作便可以寫在回調(diào)函中。

配置文件oled_conf.h
配置文件中主要有幾個宏,具體的宏的解釋可以直接看代碼注釋。
#define UI_CONWIN_ENABLE 1 //是否使能 以"$ " 為開頭的選項使用確認彈窗
#define UI_MAX_PAGE_NUM 32 //頁面的最大數(shù)量,這個數(shù)字需要大于所有頁面的page_id
#define UI_INPUT_MSG_QUNEE_SIZE 4 //ui內(nèi)部消息對列的大小(至少需要是2)
//頁面類型使能宏,使用對應(yīng)的頁面類型,則需要開啟該宏,將宏置為1,默認都開啟
#define PAGE_WAVE_ENABLE 1
#define PAGE_RADIO_ENABLE 1
#define PAGE_RADERPIC_ENABLE 1
#define PAGE_DIGITAL_ENABLE 1
接口函數(shù)的使用
這個部分會說明一部分構(gòu)建UI可能用到的結(jié)構(gòu)體類型(類)和一些函數(shù)。構(gòu)建的時候也參考CSource/example的例子(其實只有兩個??)。
類(結(jié)構(gòu)體類型)
一共有6種頁面類型 TitlePage
、ListPage
、WavePage
、 RadioPage
、RaderPicPage
和DigitalPage
,還有3個比較重要的類 InputMsg
、 Option
和 CallBackFunc
。其他的一些枚舉類型一些只有個別函數(shù)才會用到的結(jié)構(gòu)體就不一一說明了,根據(jù)函數(shù)說明填入對應(yīng)類型即可。
-
InputMsg
: 輸入信息枚舉類型,作為void OLED_MsgQueSend(InputMsg msg);
的參數(shù)類型,用于給UI輸入一個外界動作的消息,枚舉的消息共有以下幾種:typedef enum { msg_none = 0x00, //none表示沒有操作 msg_up, //上,或者last消息,表上一個 msg_down, //下,或者next消息,表下一個 msg_return, //返回消息,表示返回,從一個頁面退出 msg_click, //點擊消息,表確認,確認某一選項,回調(diào)用一次回調(diào) msg_home, //home消息,表回主界面(尚未設(shè)計,目前還沒有設(shè)計對應(yīng)的功能,默認以page_id為0的頁面為主頁面) } InputMsg; //輸入消息類型,UI設(shè)計只供輸入5種消息
-
Option
:選項類,其結(jié)構(gòu)體成員如下:typedef struct { uint8_t order; //該選項在列表/磁貼中的排序(0-255) int16_t item_max; //列表項對應(yīng)變量可取的最大值(若是單選/多選框,該值無意義,可為0) int16_t item_min; //列表項對應(yīng)變量可取的最小值(若是單選/多選框,該值無意義,可為0) int16_t step;//列表項對應(yīng)變量的步長變化,只對數(shù)值彈窗有效(若是單選/多選框,該值無意義,可為0) int16_t val; //這個列表項關(guān)聯(lián)的顯示的值(可以用于設(shè)置初值) String text; //這個列表項顯示的字符串 //(通過選項的第一個字符判斷為數(shù)值彈窗(~)/確認彈窗($)/其他項(-)/二值選項框(+)/單選項(=), /*注意只有WavePage和DigitalPage的字符串不需要前綴)*/ //其中二值選項框由于二值項只能在列表中展示,因此只在列表選擇頁面中有效,在磁帖頁面中如果出現(xiàn)+開頭的字串默認為其他項 //其實單選列表項,需使用其他項在應(yīng)用層關(guān)聯(lián)跳轉(zhuǎn)單選終端頁面實現(xiàn)(單選列表項必須使用=做字符串開頭)。 } Option; //通用選項類
Option變量的初始化需要注意以下兩點:
-
字符串成員 text, 在ListPage和TitlePage頁面都是有前綴的,且前綴是有意義的(用于識別彈窗和選框);text的第一個字符判斷為數(shù)值彈窗(~)/確認彈窗($)/其他項(-)/二值選項框(+)/單選項(=)。
-
如果想要一個選項不會受接收消息的控制,如某個數(shù)值變量(如電量,由外部來更改,不是需要設(shè)置的)只是用于展示的,step成員可以設(shè)置為0,這樣即使收到對應(yīng)的up/down消息也不會改變其值。同時,因為將step設(shè)為0時,通常將數(shù)值彈窗當作展示使用,所以此時會在進入數(shù)值彈窗前調(diào)用一次回調(diào)函數(shù)用于給數(shù)值賦值,若step不為0,則只有在數(shù)值彈窗內(nèi)收到click才會調(diào)用回調(diào) 。
同樣的,對于二值選框(text以"+ "開頭) , 如果step為0,收到up/down消息時也不會取反,只有step不為0時才會取反。
-
-
CallBackFunc
: 回調(diào)函數(shù)類型,每個頁面都需要一個回調(diào)函數(shù)(如果沒有回調(diào)函數(shù),在對應(yīng)初始化函數(shù)中置NULL即可)。通常需要定義一個形如
void MainPage_CallBack(uint8_t self_page_id,Option* select_item)
的函數(shù)(其中,MainPage_CallBack是由我們定義的回調(diào)函數(shù)名(地址)),并該函數(shù)地址作為參數(shù)給對應(yīng)的頁面初始化函數(shù)。在頁面中的選項被click時,該頁面的回調(diào)函數(shù)會被調(diào)用,
傳入回調(diào)函數(shù)的參數(shù)
self_page_id
為當前頁面的id(每個頁面都有唯一的id,需要在對應(yīng)頁面初始化時傳入);傳入回調(diào)函數(shù)的參數(shù)
select_item
為當前頁面被選中且click的選項(類型為Option),可以通過讀取該函數(shù)的order得知當前選中的是哪個選項,并在回調(diào)函數(shù)中進行對應(yīng)的處理。
下面會分成6個基礎(chǔ)頁面類型來介紹對應(yīng)的頁面類型,同時說明接口函數(shù)的使用(其實,大部分接口函數(shù)直接看注釋都能明白的??)。
TitlePage類和接口函數(shù)
-
TiltlePage頁面的演示效果如下:
-
接口函數(shù)只有一個
void OLED_TitlePageInit(TitlePage * title_page, uint8_t page_id,uint8_t item_num,Option* option_array,Icon *icon_array,CallBackFunc call_back);
-
參數(shù)需要有TitlePage 頁面對象的指針,唯一的page_id(每個頁面必須有一個唯一的id);
-
需要注意的有 :item_num 表示后面 option_array(選項數(shù)組)和 icon_arra(圖標數(shù)組)的數(shù)組大小,三者必須保持一致;
-
同時,option_array 中的選項內(nèi)的text字符串需要有前綴,用于表示該選項的類型
-
"~ "
前綴表示該選項為數(shù)值彈窗(在TitlePage頁面使用數(shù)值彈窗可以參考CSource/example下LittleClock的例子)
-
"$ "
前綴表示該選項為確認彈窗 -
其他前綴為一般選項,沒有特殊意義,需要注意的是TitlePage頁面不會顯示選項的text前綴,因此,對于一般選項,字符串前最好空出兩個空格或者使用
"- "
前綴。 -
TitlePage會在選中選項上收到msg_click消息時,調(diào)用一次回調(diào)函數(shù),并將選中的選項傳入。
-
ListPage類和接口函數(shù)
- ListPage頁面的演示效果如下:
-
同樣地,接口函數(shù)只有一個
void OLED_ListPageInit(ListPage * lp,uint8_t page_id,uint8_t item_num,Option *option_array,CallBackFunc call_back);
- 參數(shù)需要有ListPage 頁面對象的指針,唯一的page_id(每個頁面必須有一個唯一的id);
- 同樣需要注意的是:item_num 表示后面option_array(選項數(shù)組)的數(shù)組大小,必須保持一致
- 同時,option_array選項數(shù)組中text字符串使用前綴表示選項的類型
"~ "
前綴表示數(shù)值彈窗"$ "
前綴表示確認彈窗-
"+ "
前綴表示二值選項框 (會在選項后用一個框,表示是否框選) - 其他前綴沒有特殊意義,與TitlePage不同的是,ListPage 會顯示字符串的前綴,用于對齊選項,因此,強烈建議,其他選項使用
"- "
作為字符串前綴。 - 同樣,ListPage會在選中選項上收到msg_click消息時,調(diào)用回調(diào)函數(shù),并將選中選項傳入回調(diào)函數(shù)。
RadioPage類和接口函數(shù)
-
RadioPage頁面的演示效果如下:
-
其實,**RadioPage頁面和ListPage頁面是基本一樣的,不同的是,對于使用
"= "
作為text前綴的選項來說,RadioPage頁面會將其處理為單選項,即,這個頁面內(nèi),所有使用"= "
為text前綴的選項只能有一個能被選中,以實現(xiàn)單選的效果。**因為,通常對于這樣的選項頁面,我們一整個頁面內(nèi)都是這種單選項,所以將其單獨作為一個頁面類型拿出。 -
其接口函數(shù)與ListPage基本一致:(注意事項也請參考上面??)
void OLED_RadioPageInit(RadioPage * rp, uint8_t page_id, uint8_t item_num,Option *option_array,CallBackFunc call_back);
唯一一點區(qū)別,可能就是第一個參數(shù)的類型,需要是RadioPage類型。
WavePage類和接口函數(shù)
-
WavePage頁面的演示效果
-
WavePage頁面有兩個接口函數(shù)
-
void OLED_WavePageInit(WavePage * wp, uint8_t page_id, uint8_t item_num, Option *option_array, CallBackFunc call_back);
(照例是初始化函數(shù))-
參數(shù)需要有WavePage 頁面對象的指針,唯一的page_id(每個頁面必須有一個唯一的id);
-
同樣需要注意的是:item_num 表示后面option_array(選項數(shù)組)的數(shù)組大小,必須保持一致
-
與其他頁面不同的是,WavePage 頁面選項text的字符串前綴均沒有特殊意義,同時也不建議在WavePage頁面使用選項前綴,因為需要顯示波形的關(guān)系,選項字符串的大小最好不要超過5個字符,因此就不加前綴占用多余的字符了
-
同樣的,WavePage頁面也在選中項上收到msg_click消息時會調(diào)用一次回調(diào)函數(shù)。
-
-
void OLED_UIWaveUpdateVal(Option * op, int16_t val);
-
這個函數(shù)用于更新每個選項的波形值,對應(yīng)的參數(shù)就是要 更新選項的指針 和 更新的值。
-
需要注意以下的是,波形的繪制是與
void OLED_UIProc(void);
這個函數(shù)的調(diào)用一致的。
因此,建議波形的橫坐標為一個隨著
OLED_UIProc()
函數(shù)調(diào)用 一起自增的變量比較合適。(可以參考CSource/example下的UITest例子)
-
分割線在此,因為,以上的頁面均是WouoUI原作者中的主要頁面元素(再次感謝原作者????);以下是我自己因為項目需要自己增加的兩個頁面,兩個頁面的過渡動畫都使用了和WouoUI一致的動畫。
RaderPicPage類和接口函數(shù)
-
RaderPicPage頁面演示效果:
-
RaderPicPage 類只有一個接口函數(shù)(就是初始化函數(shù))
void OLED_RaderPicPageInit(RaderPicPage* rpp,uint8_t page_id,uint8_t pic_num,RaderPic * pic_array,RaderPicMode mode,CallBackFunc cb);
-
參數(shù)需要有RaderPicPage 頁面對象的指針,唯一的page_id(每個頁面必須有一個唯一的id);
-
需要注意的是,pic_num是后面pic_array數(shù)組的數(shù)組大小,必須保持一致 ,同時,這里有一個RaderPicPage頁面才會用到的類(結(jié)構(gòu)體類型)RaderPic,詳情在下方。
-
同時,mode成員為一個枚舉類型,用于設(shè)置頁面圖片全部繪制完成后的操作,有兩個可取值
-
Rader_Pic_Mode_Loop
: 全部圖片繪制結(jié)束后,清空頁面,從頭重新繪制 -
Rader_Pic_Mode_Hold
: 全部圖片繪制結(jié)束后,保持繪制完成的頁面。 -
需要注意的另外一點是, RaderPicPage頁面沒有選項,所以回調(diào)函數(shù)會在每一個圖片繪制完成后調(diào)用,將該圖片的順序( 1 ~ pic_num ), 作為Option的order傳入RaderPicPage的回調(diào)函數(shù),可以在回調(diào)函數(shù)中接收Option的order以判斷第幾張圖片已經(jīng)繪制完成,再執(zhí)行對應(yīng)的操作。
-
這兒需要注意,如果是頁面處于
Rader_Pic_Mode_Hold
模式的話,所有圖片繪制結(jié)束后,處于保持狀態(tài),會持續(xù)調(diào)用回調(diào)函數(shù),并傳入第pic_num張圖片已繪制完成的Option(Option的order成員的值為pic_num)。
-
-
RaderPic類,鐳射圖片類型,其結(jié)構(gòu)體成員如下:
typedef struct { const uint8_t * pic; //圖片指針 int16_t start_x; //起始x坐標 int16_t start_y; //起始y坐標 uint8_t w; //圖片的寬 uint8_t h; //圖片的高 RaderDirection rd; //控制繪制時的射線方向選擇,枚舉類型 } RaderPic; //鐳射圖片對象
其中結(jié)構(gòu)體成員
rd
為一個枚舉類型RaderDirection
變量,其可以有的取值有:typedef enum { RD_LEFT_UP = 0x00, //射線從左上角出發(fā) RD_LEFT_DOWN, //射線從左下角出發(fā) RD_RIGHT_UP, //射線從右上角出發(fā) RD_RIGHT_DOWN, //射線從右下角出發(fā) RD_RIGHT, //射線從水平向右 RD_LEFT, //射線從水平向左 } RaderDirection;
DigitalPage類和接口函數(shù)
DigitalPage 頁面演示效果:
DigitalPage 頁面相關(guān)的接口函數(shù)有三個:
-
void OLED_DigitalPageInit(DigitalPage* dp, uint8_t page_id, Option * option_array, uint8_t label_array_num, String * label_array, char gap_char, uint8_t gap_shine_time, uint8_t uline_shine_time,CallBackFunc cb);
-
參數(shù)需要有DigitalPage 頁面對象的指針,唯一的page_id(每個頁面必須有一個唯一的id);
-
需要注意的參數(shù)有:
-
option_array
: 這個選項數(shù)組的大小必須為3,因為3個選項分別表示DigitalPage頁面中3個兩位的十進制數(shù)字。 -
label_array_num
為后面參數(shù)label_array
標簽數(shù)組的數(shù)組大小,必須保持一致。(其中,String
類型就是char*
, 在使用時,可以直接使用String
類型,具體可以參考 CSource/example下的UITest例子) -
gap_char
為3個兩位十進制數(shù)字間的單個分隔字符,gap_shine_time
、uline_shine_time
用于控制 分隔字符 和 編輯時出現(xiàn)的下劃線 的閃爍間隔,閃爍周期為OLED_UIProc()
函數(shù)運行一次的時間間隔 乘以 參數(shù)設(shè)置值。 -
在DigitalPage 頁面,編輯每個數(shù)字(或者是標簽)后收到msg_click 消息 是會觸發(fā)一次回調(diào),將 對應(yīng)數(shù)字的Option 或者 標簽賦值的text的Option 傳入回調(diào)函數(shù),以便接收click時的選中的數(shù)字或者標簽字符串的值。 建議在回調(diào)函數(shù)中檢查option中的order時,使用DigitalPosIndex枚舉類型進行判斷。
typedef enum //Digital頁面從右往左為indexRigit到indexLeft { Digital_Pos_IndexRight = 0x00, //用于指示當前光標或者編輯的位置 Digital_Pos_IndexMid, Digital_Pos_IndexLeft, Digital_Pos_IndexLabel, //在標簽處 Digital_Pos_Complete, //編輯完成 }DigitalPosIndex; //用于在回調(diào)函數(shù)中檢驗選中項的op->order值,表示選中哪個數(shù)字位還是標簽
同時,在DigitalPage頁面退出編輯模式(返回觀察模式)時,也會調(diào)用一次回調(diào)函數(shù)函數(shù),并傳入的order為
Digital_Pos_Complete
的一個option , 所以在回調(diào)函數(shù)中判斷這個order,可以將對應(yīng)的操作放在編輯結(jié)束返回到觀察模式時執(zhí)行(例如,等所有值設(shè)置結(jié)束再讀取值)。 -
-
void OLED_DigitalPage_UpdateDigitalNumAnimation(DigitalPage * dp, uint8_t leftval, uint8_t midval, uint8_t rightval, DigitalDirect dir);
- 用于更新DigitalPage頁面中的數(shù)字,并觸發(fā)滾動的動畫。
- 需要注意的是,
dir
是DigitalDirect
枚舉類型的一個變量,可取的值有Digital_Direct_Increase
,Digital_Direct_Decrease
兩種,決定數(shù)字的滾動方向。
-
void OLED_DigitalPage_UpdateLabelAnimation(DigitalPage * dp, uint8_t label_index, DigitalDirect dir)
-
用于更新DigitalPage頁面中的標簽,并觸發(fā)滾動的動畫。
-
需要注意的是,只能將標簽更新為初始化中設(shè)置的
label_array
標簽數(shù)組中的一個便簽。label_index
為要更新的標簽在label_array
的下標(取值0~label_num_array -1
);label_index
可以超過label_num_array
,當超過時會自動選擇為0。
dir
與更新數(shù)字的函數(shù)一樣,是DigitalDirect
枚舉類型的一個變量,可取的值有Digital_Direct_Increase
,Digital_Direct_Decrease
兩種,決定的滾動方向。 -
DigitalPage頁面操作邏輯的說明
DigitalPage類(結(jié)構(gòu)體類型)中有一個比較重要的成員mode
(為枚舉類型 DigitalMode
) 。該枚舉類型的取值有如下幾個
typedef enum
{
Digital_Mode_Observe = 0x00,
//觀察模式?jīng)]有光標(剛進入DigitalPage頁面的模式;沒有下劃線光標)
Digital_Mode_Edit = 0x01,
//對編輯位置的編輯(可以通過up\down消息控制光標的移動;下劃線光標閃爍)
Digital_Mode_Singlebit = 0x02, //對單位數(shù)字的編輯(可以通過up\down消息控制單位數(shù)字/標簽的加減和切換;下劃線光標常亮)
} DigitalMode; //digital頁面的模式
DigitalPage頁面運行的狀態(tài)機如下圖所示:有興趣的可以看看??

UI的一些接口函數(shù)和參數(shù)
一些UI使用的接口函數(shù)和參數(shù)一起在這兒說明。
接口函數(shù)(有6個)
//用于向UI傳遞一個消息Msg(msg_click/msg_up/msg_down/msg_return)
void OLED_MsgQueSend(InputMsg msg);
//UI必要的一些參數(shù)和變量的初始化
void OLED_UiInit(void);
//UI運行任務(wù),需要放在主循環(huán)中循環(huán)調(diào)用,而且盡量不要阻塞
void OLED_UIProc(void);
//從一個頁面跳轉(zhuǎn)到另一個頁面,常用于回調(diào)函數(shù)中調(diào)用,并確定頁面的上下級關(guān)系(這樣,在terminate_page頁面收到return消息時,會返回self_page_id所代表的頁面)
//@param self_page_id 是當前頁面的id(回調(diào)函數(shù)中有這個參數(shù))
//@param terminate_page 要跳轉(zhuǎn)的那個頁面的地址(不需要理會是那種類型的頁面,直接將頁面地址作為參數(shù)傳入即可)
void OLED_UIJumpToPage(uint8_t self_page_id,PageAddr terminate_page);
//切換當前頁面的函數(shù),與Jump函數(shù)不同的時,這個函數(shù)不會綁定上下級頁面關(guān)系,
//terminate_page 頁面收到return 消息不會返回當前頁面(常用于臨時的畫面切換)
//@param terminate_page 要跳轉(zhuǎn)的那個頁面的地址(不需要理會是那種類型的頁面,直接將頁面地址作為參數(shù)傳入即可)
void OLED_UIChangeCurrentPage(PageAddr terminate_page);
/*獲取當前頁面的id*/
uint8_t OLED_UIGetCurrentPageID(void);
需要注意的只有:
-
void OLED_UIProc(void);
需要在主循環(huán)中循環(huán)調(diào)用,且最好沒有阻塞; -
OLED_UIJumpToPage
函數(shù)會確認頁面的上下級關(guān)系,OLED_UIChangeCurrentPage
函數(shù)只是切換頁面,沒有確認頁面的上下級關(guān)系; -
OLED_UIJumpToPage
函數(shù)和OLED_UIChangeCurrentPage
函數(shù) 的terminate_page
參數(shù)只需傳入頁面地址(指針)就行,不需要理會頁面是什么類型。
UI參數(shù)
WouoUIPage的參數(shù)基本上WouoUI原作保持一致,如下:(由于我沒有移植退出時的淡出動畫,因此參數(shù)也會比WouoUI要少一些)
ui_para.ani_param[TILE_ANI] = 120; // 磁貼動畫速度
ui_para.ani_param[LIST_ANI] = 120; // 列表動畫速度
ui_para.ani_param[WIN_ANI] = 120; // 彈窗動畫速度
ui_para.ani_param[TAG_ANI] = 60; // 標簽動畫速度
ui_para.ani_param[DIGI_ANI] = 100; // 數(shù)字動畫滾動速度(這些速度是越大運動越慢)
ui_para.ufd_param[TILE_UFD] = True; // 磁貼圖標從頭展開開關(guān)
ui_para.ufd_param[LIST_UFD] = True; // 菜單列表從頭展開開關(guān)
ui_para.loop_param[TILE_LOOP] = True; // 磁貼圖標循環(huán)模式開關(guān)
ui_para.loop_param[LIST_LOOP] = True; // 菜單列表循環(huán)模式開關(guān)
ui_para.valwin_broken = True; //彈窗背景虛化開關(guān)
ui_para.conwin_broken = True; //確認彈窗背景虛化開關(guān)
ui_para.digital_ripple = True; //digital頁面波紋遞增動畫開關(guān)
ui_para.raderpic_scan_mode = False; //鐳射文字只掃描亮處
ui_para.raderpic_scan_rate = 4; //鐳射文字掃描速度
ui_para.raderpic_move_rate = 50; //鐳射文字移動速度
WouoUIPage整體的代碼邏輯
這部分是針對想要二次開發(fā)WouoUIPage的人寫的(其實是怕我之后回來想做改進的時候看不懂自己的代碼??),方便理解整體的代碼邏輯,如果是單純使用的話,參考例子和上面的接口說明應(yīng)該就夠了。
關(guān)于圖形層
-
圖形層中有一個
window
類,這個類幾乎在每個圖形層的函數(shù)中都是作為第一個參數(shù)輸入的。這個window
只是用于控制繪制的邊界,繪圖函數(shù)繪制的點如果超過傳入的window
的大小,就不會繪制到緩沖區(qū)中。oled_ui.h
中提供了一個w_all
全局窗口變量,只是為了方便可能在除了上述頁面之外,使用者還有其他繪圖需要準備的,其邊界為整個128*64的屏幕,這個窗口也是整個ui繪制時主要使用的窗口。 -
圖形層中有一個更改畫點顏色的函數(shù):(其實是控制寫入的字節(jié)以什么位運算寫入緩沖區(qū)中)。
/** * @brief : void OLED_SetPointColor(uint8_t color) * @param : 設(shè)置畫筆顏色,color:1=亮,0=滅,2=反色 * @attention : None * @author : Sheep * @date : 23/10/04 */ void OLED_SetPointColor(uint8_t color) { switch (color) { case 0: oled_color = '&';break; case 1: oled_color = '|';break; case 2: oled_color = '^';break; default:break; } // oled_color = (color != 0 )?'|':'&'; }
關(guān)于UI層
-
PageAddr
頁面地址變量,其實是一個void*
類型,為了用于實現(xiàn)OLED_UIJumpToPage
函數(shù)和OLED_UIChangeCurrentPage
函數(shù)的 “偽多態(tài)”。(其實內(nèi)部所有AnimInit
、Show
、React
函數(shù)都使用這樣的"偽多態(tài)") 。在獲取頁面地址后,直接強轉(zhuǎn)為
Page
類,這是一個所有頁面類型都必須包含的結(jié)構(gòu)體成員(且必須是第一個,為了方便轉(zhuǎn)換類型)。Page
類中包含了所有頁面必須有的一些成員,如下://每個頁面都有的三種方法 typedef void (*PageAniInit)(PageAddr); //頁面的動畫初始化函數(shù) typedef void (*PageShow)(PageAddr); //頁面的展示函數(shù) typedef void (*PageReact)(PageAddr); //頁面的響應(yīng)函數(shù) typedef struct { PageType page_type; //頁面類型,以便在處理時調(diào)用不同函數(shù)繪制 uint8_t page_id; //頁面的序號,每個頁面唯一一個,用于指示在數(shù)組中的位置,方便跳轉(zhuǎn) uint8_t last_page_id; //上一個頁面的id,用于返回時使用 CallBackFunc cb; //頁面的回調(diào)函數(shù) PageAniInit ani_init; PageShow show; PageReact react; } Page; //最基本的頁面類型(所有頁面類型的基類和結(jié)構(gòu)體的**第一個成員**)
-
WouoUIPage的狀態(tài)機(相比WouoUI原版減少了一個”退出過渡動畫“,原因就是 Air001的RAM和Flash不太夠??)。文章來源:http://www.zghlxwxcb.cn/news/detail-834787.html
關(guān)于注釋
如果有小伙伴愿意查看源代碼的話,可能會看到有三種風格的函數(shù)注釋,這是因為我本身有兩種函數(shù)注釋風格,而且在后期寫代碼的過程中,使用了阿里的大模型幫忙生成注釋,因此注釋可能會有多種風格??。文章來源地址http://www.zghlxwxcb.cn/news/detail-834787.html
到了這里,關(guān)于WouoUI-PageVersion 一個用于快速構(gòu)建具有絲滑OLED_UI動畫的項目的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!