认识迅雷界面引擎
UI開發(fā)的新時(shí)代----認(rèn)識迅雷界面引擎
?
第一部分:交互開發(fā)技術(shù)概述 軟件產(chǎn)品的交互開發(fā)一直以來都不是一件令人愉悅的事情。首先,由于每個(gè)人編寫的第一個(gè)圖形應(yīng)用程序就已經(jīng)使用了一些交互開發(fā)技術(shù),而且由于IDE工具的強(qiáng)大,容易總結(jié)出交互開發(fā)就是“拖拖控件,改改屬性,寫寫響應(yīng)”的經(jīng)驗(yàn),所以很容易被認(rèn)為是沒什么技術(shù)含量的工作。但實(shí)際上,這是一個(gè)特別不容易的工作:因?yàn)樽鳛檐浖a(chǎn)品的臉面,上至公司老板,下至任意一個(gè)普通用戶,大家都可以對你的工作成果拼頭論足,并提出修改意見,而這些修改意見反應(yīng)到產(chǎn)品的方案修改上,總是會讓修改成本與項(xiàng)目的修改復(fù)雜度不呈線性關(guān)系。很多剛剛從事這一行的項(xiàng)目經(jīng)理總是不能理解,為什么按一個(gè)方案修改交互,需要1天,而另一個(gè)看起來似乎差不多的方案,卻要改上一個(gè)月? 從另一個(gè)角度也可以發(fā)現(xiàn)這里的技術(shù)門檻不易:其它領(lǐng)域的設(shè)計(jì)模式,經(jīng)驗(yàn)總結(jié)文章已經(jīng)汗牛充棟,各種各樣的新思路和在這些思路上建立起來的各種開源庫,每過幾年基本就要洗上一輪,但在交互開發(fā)上,除了各個(gè)廠商提供的平臺開發(fā)方法,幾乎沒有被公認(rèn)和被廣泛使用的界面開發(fā)庫,更不要提相關(guān)方法論和模式的升華,總結(jié)與創(chuàng)新了。 但是,軟件產(chǎn)品的交互體驗(yàn),特別是互聯(lián)網(wǎng)產(chǎn)品的交互體驗(yàn),如今越來越多的受到人們的重視。從過去能實(shí)現(xiàn)功能完成交互,到后來提供一致的操作習(xí)慣,流暢的實(shí)現(xiàn)整個(gè)交互流程,如今還渴望交互體驗(yàn)?zāi)芑谟脩舻氖褂眯睦碓O(shè)計(jì),更加美觀,并提高產(chǎn)品的整體品味。如今全球市值最高的Apple公司,正是靠著其ipod,iphone,ipad系列產(chǎn)品的優(yōu)秀交互體驗(yàn)和近乎完美的工業(yè)設(shè)計(jì),征服了廣大用戶。 迅雷作為中國非常流行的一款Windows平臺下的客戶端產(chǎn)品,對于改進(jìn)產(chǎn)品的交互體驗(yàn)有著強(qiáng)烈的愿望。迅雷5.8完成了工具軟件的關(guān)鍵功能提升,隨后的版本進(jìn)化,希望能進(jìn)一步改進(jìn)產(chǎn)品的交互體驗(yàn): 更美觀也更現(xiàn)代。迅雷5.9(迅雷6)是基于傳統(tǒng)Windows界面開發(fā)技術(shù)改進(jìn)交互體驗(yàn)的結(jié)果,這個(gè)結(jié)果雖然還不錯(cuò),但帶來了另一個(gè)問題:開發(fā)成本的提高。迅雷作為一款由多個(gè)部門合作開發(fā)的(包括合作開發(fā)交互)客戶端產(chǎn)品,傳統(tǒng)的開發(fā)技術(shù)不能很好的組合各個(gè)部門開發(fā)的模塊,開發(fā)成本與穩(wěn)定性都有問題。公司迫切的需要一個(gè)能解決這些問題的下一代界面引擎,并在多個(gè)方面使用各種方式開始了勇敢的嘗試。 第二部分?過去我們?nèi)绾伍_發(fā)按鈕 現(xiàn)在我將通過一個(gè)經(jīng)典的windows下”自畫按鈕”的工程實(shí)例,和大家一起觀察UI開發(fā)的過程。”自畫按鈕”是一個(gè)非常常見的產(chǎn)品需求,相信不少讀者都有過相似的經(jīng)歷(下列故事純屬虛構(gòu),如有雷同,真是巧合). 那年正是Windows XP最流行的時(shí)候,我們的產(chǎn)品也跟進(jìn)時(shí)代的發(fā)展,將界面風(fēng)格升級到了XP Style,同時(shí)我們的產(chǎn)品還兼容Windows2000,設(shè)計(jì)和產(chǎn)品都希望我們的軟件在兩個(gè)系統(tǒng)下都能有一致的外觀表現(xiàn)。于是,我就需要開發(fā)一個(gè)能在兩個(gè)平臺下都長得一樣的按鈕。這個(gè)活并不困難,我們先看看需求: 看了需求之后,作為一個(gè)合格的Windows開發(fā)工程師,很快就完成了。實(shí)現(xiàn)代碼大致如下: CButton::OnPaint() { DrawBkg(m_state,0,0,width,height); DrawText(m_state,m_btnText,width/2-textWidth/2,height/2-textHeight/2); if?(isFocus) { DrawFocusRect(2,2,width-2,height-2); } } CButton::OnLButtonDown(){ ChangeState(BTN_STATE_DOWN); } CButton::OnLButtonUp(){ ChangeState(BTN_STATE_NORMAL); FireEventOnClick(); } 分析實(shí)現(xiàn)代碼,大家可以看到基本思路是這樣的 1.???????確定按鈕有幾個(gè)狀態(tài),然后根據(jù)這些狀態(tài)下按鈕的外觀,確定如何實(shí)現(xiàn)OnPaint函數(shù)。 2.???????處理WM_LBUTTONDOWN,WM_MOUSEMOVE等輸入消息,在這些消息里改按鈕的狀態(tài) 3.???????在WM_LBUTTONUP,WM_KEYUP等消息里,Fire一個(gè)按鈕自己定義的OnClick事件 很好,我們的軟件用上了新按鈕,問題解決了,產(chǎn)品經(jīng)理和設(shè)計(jì)師都很滿意。咱也結(jié)束了一天的工作,安心回家睡個(gè)好覺。 又過了幾天,公司的產(chǎn)品總監(jiān)在產(chǎn)品會上提到,我們要統(tǒng)一所有產(chǎn)品的交互邏輯,特別是某些按鈕,根據(jù)現(xiàn)在的交互規(guī)范,應(yīng)該加上醒目的圖標(biāo)。會后設(shè)計(jì)師打開PHOTOSHOP,很快就把按新規(guī)范調(diào)整的按鈕發(fā)給了我。如下圖 這次我沒有立刻開始實(shí)現(xiàn),因?yàn)楣镜牧硪划a(chǎn)品也用到了我實(shí)現(xiàn)的這個(gè)按鈕,我要保證原有的按鈕能繼續(xù)正常工作,我打算和那邊的研發(fā)商量一下怎么改。這里我有兩個(gè)方案。 方案一: 1.定義 CIconButton,繼承CButton 2.CIconButton添加方法SetIcon 3.在CIconButton::OnPaint里添加如下代碼 OnPaint() {DrawBkg(m_state); DrawIcon(m_state);
DrawText(m_state); } 4.使用新的CIconButton完成需求 方案二、 1.在CButton里添加兩個(gè)擴(kuò)展點(diǎn)回調(diào) OnPaint() {
if(OnDrawBkgCallback()) DrawBkg(m_state); if(OnDrawItemCallback()) DrawText(m_state); } 并提供設(shè)置回調(diào)的接口 SetOnDrawBkgCallback() SetOnDrawItemCallback() 2.產(chǎn)品通過SetOnDrawItemCallBack完成需求 void OnBtnDrawItemCallback() { DrawIcon(); return true; } m_button.SetOnDrawItemCallback(OnBtnDrawItemCallback); 在方案的選擇上,大家有了一些爭議:方案一看起來比較直接,而且實(shí)現(xiàn)起來也比較快,最重要的是使用我的控件庫的產(chǎn)品開發(fā)工程師特別希望這么改;而方案二實(shí)現(xiàn)需要更多的代碼,并且產(chǎn)品開發(fā)工程師需要學(xué)習(xí)和編寫更多的代碼才能完成這個(gè)需求,不過這個(gè)方案的未來我更看好。最后我們選定了一個(gè)方案(在這里選哪一個(gè)都能完成需求),加班寫好代碼,提交測試,發(fā)布新的界面控件庫,制作新的安裝包,一陣忙碌,這個(gè)小小的需求升級總算是結(jié)束了。 又過了幾天,公司大老板通過郵件告訴大家,公司產(chǎn)品的大客戶比較喜歡Windows Rabbion風(fēng)格。于是產(chǎn)品經(jīng)理再次調(diào)整設(shè)計(jì),要求一些按鈕要改成如下樣式: 很明顯,這次圖標(biāo)跑到按鈕文本上面去了,這就是最新的時(shí)代潮流。雖然很不情愿,但這不就是生活么?隔壁卡位的設(shè)計(jì)師,半個(gè)小時(shí)搞定了所有需要調(diào)整的地方的效果圖,按時(shí)下班回家了,而我們工程師還必須加班! 這次的工作量就和上次修改的方案有關(guān)了: 如果我們上一步使用了方案一,這次我們?nèi)兆記]那么好過了。我們需要?jiǎng)?chuàng)建一個(gè)新的CIconButton2繼承自CIconButton,再加一個(gè)新接口SetIcon2,可以在設(shè)置圖標(biāo)的同時(shí)調(diào)整圖標(biāo)在文本的什么位置(這次還耍了個(gè)小聰明,這個(gè)接口可以支持圖標(biāo)在文本的上下左右4個(gè)方位) 。 而使用方案二的優(yōu)越性則在這里得到了體現(xiàn):作為按鈕的開發(fā)者,并不需要修改一行代碼,你只要繼續(xù)指導(dǎo)一下需要實(shí)現(xiàn)這個(gè)需求的產(chǎn)品開發(fā)工程,調(diào)整一下OnBtnDrawItemCallback的實(shí)現(xiàn)即可。 實(shí)際上,在迅雷,我們有過一次在方案一這條路上走到頭的經(jīng)歷,迅雷的代碼里有一個(gè)叫 CXLButton的怪物,提供了近200個(gè)接口,有快2萬行代碼。當(dāng)編寫這個(gè)類的哥們走人以后,接手這個(gè)Class的新人發(fā)現(xiàn)這個(gè)按鈕的用途(在最后一個(gè)版本的需求里)只是用來實(shí)現(xiàn)一個(gè)圖標(biāo)在文字上面的工具欄按鈕,”這垃圾代碼是誰寫的!”,他逢人就要這么嘲笑一下,然后花了一個(gè)下午的時(shí)間寫了一個(gè)新類 CXLButton2,清晰明了的實(shí)現(xiàn)了這個(gè)需求。但我們都知道,這是另一個(gè)輪回的開始。而且,有資格使用方案一還意味著控件開發(fā)工程師愿意幫助產(chǎn)品開發(fā)工程師修改接口與實(shí)現(xiàn),如果這兩組工程師不在一個(gè)公司,更大的成本會花在人與人的溝通上甚至無法進(jìn)行。 Microsoft提供的標(biāo)準(zhǔn)控件,通過類似方案2的方法提供可擴(kuò)展性。方案二在過去,都被普遍認(rèn)為是一個(gè)出色的解決可復(fù)用性問題的模式(我很少在招聘的時(shí)候能看到有人能在開發(fā)控件的時(shí)候通過這種方式提供可擴(kuò)展性),但其缺點(diǎn)之一就是讓控件的使用有點(diǎn)復(fù)雜,學(xué)習(xí)成本很高。比如我至今都沒有通過MSDN 完全搞清楚過微軟TreeView提供的這種擴(kuò)展事件的細(xì)節(jié),還好有一份泄漏的Windows源代碼,讓我對這些回調(diào)之間的關(guān)系能有清楚的認(rèn)識。而且這個(gè)方案會讓產(chǎn)品開發(fā)工程師學(xué)習(xí)很多高度依賴控件庫內(nèi)部實(shí)現(xiàn)的知識,如果產(chǎn)品更換的底層界面庫,那么大量的這種經(jīng)驗(yàn)就沒有意義了。 而且,方案二真的能以不變應(yīng)萬變,支持所有的需求變化么?大家可以自行思考。 通過這個(gè)可擴(kuò)展的按鈕控件的開發(fā)實(shí)例,我們總結(jié)了三個(gè)交互開發(fā)的經(jīng)驗(yàn): 一、?交互是最易改變的需求 二、?開發(fā)一個(gè)可復(fù)用的交互控件的主要工作有
1)根據(jù)最初的需求決定方法,事件
2)根據(jù)最初的需求決定如何實(shí)現(xiàn)OnPaint,如何將原始的OS輸入事件轉(zhuǎn)成邏輯事件
3)在OnPaint里織入擴(kuò)展點(diǎn)。 三、交互開發(fā)涉及的技術(shù)點(diǎn)很多,實(shí)現(xiàn)時(shí)注意細(xì)節(jié),注規(guī)避常見問題,當(dāng)繪制特別復(fù)雜的時(shí)候還要仔細(xì)優(yōu)化性能。 第三部分?新的思路 從頭觀察上面的例子,我發(fā)現(xiàn): 不管怎么修改交互需求,隔壁卡位的設(shè)計(jì)師總是很少加班,他們的工作量似乎能很好的和交互需求的修改量成正比,而且沒有什么局限。相反,我們的工作總是存在一些天花板,一旦需求改變越過了開發(fā)時(shí)預(yù)設(shè)的一些前提條件,需求修改的響應(yīng)時(shí)間會大幅增加。 不管是通過那種方法,有限的接口和有限的擴(kuò)展點(diǎn),理論上滿足不了近乎無限的需求變化。而我們觀察所謂的通過事件擴(kuò)展控件的方案,其核心是希望OnPaint能夠根據(jù)各種參數(shù),調(diào)整工作流程。而OnPaint里實(shí)現(xiàn)的功能,說到底就是 “在指定位置使用適當(dāng)?shù)暮瘮?shù)繪制文本或貼圖”。要想讓一段代碼的流程具有很強(qiáng)的可變性,是非常困難的。從某種意義上說,OnPaint函數(shù)就是萬惡之源。 明白了問題的根源,那么如何解決問題就有了方向:我們要在交互開發(fā)的過程中干掉OnPaint。實(shí)際上在這之前已經(jīng)有技術(shù)實(shí)現(xiàn)了這一點(diǎn):HTML本身并沒有提供繪制函數(shù),而實(shí)際上,前端交互開發(fā)是目前所有交互開發(fā)技術(shù)里流程分工合理,并且需求修改響應(yīng)速度保持線形增長,容易學(xué)習(xí),有完善工具鏈條的技術(shù)。我們可以在傳統(tǒng)app開發(fā)里使用HTML技術(shù)么? 很多人回答YES,并做出了開創(chuàng)性的嘗試。不過經(jīng)過了一些思考之后我們并沒有選擇HTML(原因我們以后會在另外的文章里詳細(xì)的介紹)。經(jīng)過了一些借鑒和總結(jié),我圍繞這個(gè)問題提出了一個(gè)新的概念:可以通過定義原子UI對象(UIObject)之間的父子關(guān)系和位置關(guān)系組成對象樹(UIObjTree)來描述界面,UIObject的類型是相當(dāng)有限的。而按邏輯構(gòu)建的UIObjTree的實(shí)際上組織了OnPaint里“按什么樣的順序在什么地方畫什么”的問題。 這個(gè)概念有點(diǎn)抽象?還是你已經(jīng)完全明白了?都沒關(guān)系,還是剛剛例子里的按鈕,按這種方法分析以后,我們會得到一個(gè)怎樣的UIObjTree呢? 非常直觀的對象樹,只有兩個(gè)UIObject。接下來的需求修改就變成了修改這個(gè)數(shù)據(jù)結(jié)構(gòu)。而樹結(jié)構(gòu)的修改接口提供起來是非常簡單缺完備的:添加節(jié)點(diǎn),刪除節(jié)點(diǎn),查找節(jié)點(diǎn),修改節(jié)點(diǎn)屬性。我們看看在這個(gè)結(jié)構(gòu)上如何響應(yīng)上面的需求 你會發(fā)現(xiàn)抽象UI得到的UIOjbTree會與設(shè)計(jì)師提供的PSD圖結(jié)構(gòu)非常相似,這就非常符合真正的開發(fā)情況:開發(fā)得到的需求并不直接來自產(chǎn)品經(jīng)理,而是來自設(shè)計(jì)師。如果技術(shù)能夠?qū)⒃O(shè)計(jì)師的成果直接轉(zhuǎn)化成App可以使用的數(shù)據(jù)結(jié)構(gòu),那么這樣的技術(shù)無疑在實(shí)現(xiàn)能力和開發(fā)效率上,能與設(shè)計(jì)師相同。(這個(gè)理論迅雷通過迅雷7 ,XMP多個(gè)產(chǎn)品的大規(guī)模實(shí)踐,已經(jīng)得到了有效的證明)所以BOLT界面引擎的創(chuàng)新,根本上是提出了一種新的抽象交互的思路。 這里建議您可以考慮將一些常見的控件,或則您現(xiàn)在正在開發(fā)的軟件的交互解構(gòu)成UIObjTree,試一試吧。 圍繞這個(gè)概念來構(gòu)建整個(gè)界面引擎,我們還獲得了一系列進(jìn)一步的好處: 基于同樣的模式分析交互,能輸出近乎一致的結(jié)果。 可以將界面布局從邏輯代碼中獨(dú)立出來。 對界面的抽象是平臺無關(guān)的。(雖然我們沒有把跨平臺作為BOLT界面引擎的關(guān)鍵目標(biāo)) 讓對象的屬性在一段時(shí)間里按規(guī)律變化,就能實(shí)現(xiàn)動畫。開發(fā)各種特效也有了一致的思路 基于對象樹枝葉嫁接的復(fù)用和界面模塊劃分,易于理解。并提供了統(tǒng)一的可訪問性 (所謂的可訪問性,是指你可以在控件的開發(fā)者不提供實(shí)現(xiàn)的基礎(chǔ)之上,只通過UIObjTree的樹操作借口,就能訪問并修改其表現(xiàn)) 交互開發(fā)技術(shù)的變遷 整理上面的思路,我們得到交互開發(fā)技術(shù),或則就是界面庫的分代標(biāo)準(zhǔn): 第一代 :SDK開發(fā),使用系統(tǒng)默認(rèn)控件 第二代 :基于窗口子類化的自繪控件皮膚庫。繪制通常基于GDI。控件類型和系統(tǒng)一致。 第三代 :提供一套完整的體系(窗口,繪制等),所有的控件都基于這個(gè)體系開發(fā)。本身提供很多功能更強(qiáng)的控件,并有統(tǒng)一的方法開發(fā)/使用新控件。這一代庫主要是解決實(shí)現(xiàn)能力問題。由于Windows的系統(tǒng)限制,二代庫有很多功能局限。(比如按鈕發(fā)光這個(gè)需求需要按鈕的實(shí)現(xiàn)代碼可以繪制到按鈕子窗口以外的) 第四代 :布局文件+腳本語言的開發(fā)模式,依靠”組合”抽象界面并圍繞這個(gè)概念搭建 。不提供控件但提供易學(xué)易用的控件開發(fā)模式。不提供內(nèi)置特效但能讓使用者輕易開發(fā)自己的界面特效。 這個(gè)分代標(biāo)準(zhǔn)基本上是參考windows上的界面庫發(fā)展而制定的,第二代和第三代庫本身其實(shí)沒有什么本質(zhì)上的區(qū)別,主要是Windows由于兼容原因,提供的UI相關(guān)API和窗口混和器過于古典(子窗口與父窗口之間只有遮蓋關(guān)系,沒有辦法混合,很多GDI函數(shù)都無視Alpha通道),使得開發(fā)一套完整的界面庫反而還需要自己實(shí)現(xiàn)窗口管理和圖形庫這些有一定技術(shù)門檻的基礎(chǔ)設(shè)施。新的OS本身提供的UI框架本身就解決了這些問題,所以這些新的OS上的庫就直接是3代庫了。 需要指出的是,有一些技術(shù)框架也提供基于組合的方法構(gòu)建界面的方法.比如現(xiàn)在相當(dāng)流行的iOS上的cocoa框架,很多時(shí)候可以只通過組合各種View的方法來創(chuàng)建新的控件。但這個(gè)框架我依舊認(rèn)為他是三代庫,因?yàn)榭蚣苓€是依舊以繪制為核心構(gòu)建,比如你可以組合多個(gè)不同屬性的按鈕構(gòu)成一個(gè)新控件,但你無法獲得按鈕上文字的SubView,沒有獲得統(tǒng)一的可訪問性。 第四部分 Bolt界面引擎概念介紹 關(guān)鍵概念 ????????使用XML文件來定義UIObjTree,用Lua腳本來實(shí)現(xiàn)界面邏輯 ????????UIObject的類型包括ImageObject,TextObject,還有一些精心設(shè)計(jì)的原子類型?《引擎內(nèi)置的元對象介紹》 ????????圍繞核心概念建立了一系列輔助設(shè)施 基本工作原理 BOLT界面引擎這里提供了兩個(gè)重要的核心概念HostWnd ,Render。Render可以把一顆構(gòu)建完成的UIObjTree渲染成一張位圖。而HostWnd是界面引擎核心與操作系統(tǒng)之間的橋梁,能把這張位圖通過系統(tǒng)提供的API畫到屏幕上,并能轉(zhuǎn)化操作系統(tǒng)的鍵盤/鼠標(biāo)等事件成為引擎的定義得標(biāo)準(zhǔn)輸入事件(Action)。 這張圖里還提到了我們的UI資源管理模塊和XML布局文件讀取與管理模塊。 Render的基本工作原理 DirtyRect(臟矩形)是驅(qū)動Render工作的核心。關(guān)于臟矩形,在很多2D游戲開發(fā)的文章里都有詳細(xì)介紹。當(dāng)一顆UIObjTree上的產(chǎn)生了臟矩形,其對應(yīng)的Render在下次渲染時(shí)就會開始有動作,否則就什么也不干。Render會選取與臟矩形相交的所有UIObject,然后按這些UIObject的z-order排序(從小到大)排序 ,再按這個(gè)順序依次調(diào)用這些UIObject的Draw方法。由于所有的UIObject都是由引擎實(shí)現(xiàn)的,所以這個(gè)Draw方法也是一個(gè)不可見的內(nèi)部函數(shù),Draw的實(shí)現(xiàn)會調(diào)用一些我們精心優(yōu)化過的圖形圖像繪制函數(shù),這一切就構(gòu)成了Bolt界面引擎的高速渲染引擎。 注:虛線表示的矩形是臟矩形,那么Render只會渲染與這個(gè)區(qū)域相交的UIObject。 BOLT界面引擎里控件的概念 基于UIObject和UIObjTree,開發(fā)控件就是設(shè)計(jì)一個(gè)可復(fù)用的“對象樹片斷”,而使用控件就是由界面引擎完成這個(gè)對象樹片斷如何嫁接到對象樹上。 這里通過一個(gè)簡單的例子演示一下這個(gè)過程 這樣的一個(gè)MessageBox。抽象成UIObjTree 我們可以定義Button的對象樹片斷是: 合并以后 而且很明顯,引入控件的概念,能把一顆復(fù)雜的UIObjTree分解成多個(gè)片斷交給團(tuán)隊(duì)開發(fā),而最后合成的UIObjTree依舊保持了各個(gè)節(jié)點(diǎn)的可訪問性。 第五部分?未來展望 Bolt界面引擎的核心概念,是完全創(chuàng)新與獨(dú)立的,并不依賴任何操作系統(tǒng)。所以BOLT界面引擎的發(fā)展方向之一是把界面引擎移植到各種各樣的平臺,目前最成熟穩(wěn)定的平臺是Windows,有工業(yè)級產(chǎn)品的質(zhì)量。我們在Andiord平臺和MacOS平臺都有初步移植的版本,但我們還需要花費(fèi)很多精力在合適的機(jī)會完成讓這些平臺的界面引擎更完美 我們在移植到Andiord平臺時(shí)發(fā)現(xiàn),界面引擎要想在這些手持設(shè)備上流程運(yùn)行,原有的基于CPU指令集優(yōu)化的高速渲染器是不好的。一是CPU性能達(dá)不到,不夠流暢,二是太耗電,這里迫切需要使用設(shè)備提供的硬件加速功能。得益于界面引擎不希望用戶編寫繪制代碼的核心概念,我們只需要重新調(diào)整高速渲染器就可以實(shí)現(xiàn)硬件加速。目前我們正在嘗試各種各樣的支持硬件加速的框架方案:既能高效使用硬件的能力 ,又能兼顧C(jī)PU算法的靈活性。 我們目前的主要精力都放在引擎本身的完善上,但實(shí)際上,如同HTML與Dreamweaver一樣,界面引擎在設(shè)計(jì)之初就可以讓布局部分由使用專業(yè)工具的專業(yè)人員完成,而不是負(fù)責(zé)編寫邏輯代碼的工程師。我們對我們的布局XML格式的簡單優(yōu)雅和可擴(kuò)展性都有充分的信心,我們衷心的希望各位同行在理解認(rèn)可了我們的概念后支持我們的標(biāo)準(zhǔn),這樣大家就能開發(fā)各種輔助工具,互相通用,共同改進(jìn)BOLT界面引擎的工具鏈支持。 轉(zhuǎn)自http://xldoc.xl7.xunlei.com/0000000018/00000000180001000020.html
轉(zhuǎn)載于:https://www.cnblogs.com/Bonker/p/3286773.html
總結(jié)
- 上一篇: Httpclient发送json请求
- 下一篇: 找数组里没出现的数