嘗鮮使用Kotlin寫了一段時間Android。說大幅度的減少了Java代碼一點不誇張。用Java的時候動不動就new一個<code>OnClickListener()</code>匿名類,動不動就類型轉換的地方都可以省下很多。更不用說特殊的地方使用<code>data class</code>更是少些不知道多少代碼。
類型安全,不再需要那麼多的<code>findById()</code>之後的類型轉換。
null安全,Kotlin裡,如果一個變量用?表示為可空,并且使用?之後再調用的時候,即使變量為空也不會引發異常。
無需裝置解析XML,因為Anko本質是代碼實作的界面和布局,是以省去了這些麻煩。
代碼複用,可以通過繼承<code>AnkoComponent</code>的方式實作代碼複用。XML布局是每一個Activity,每一個View各自專屬一個,
代碼複用比較少。
來一個列子看一下。為了不太墨迹,一些不必要的xml聲明此處略去。
首先,安裝一個Kotlin的插件是必須的。有了這個插件才可以使用Kotlin,然後才可以使用Anko。安裝這個插件和Android Studio裡安裝别的插件市一樣的。隻需要使用Kotlin查找就可以找到,之後安裝即可。
在build.gradle裡添加下面的代碼:
然後sync一把。配置的問題解決。
首先建立一個ListView的item點選之後跳轉的activity。這裡叫做<code>TabDemo1</code>。
現在就建立這個listview,并在listview的item點選之後調轉到相應的activity去。
這個listview非常簡單,隻在一個豎直的布局中放置,并且寬度和高度都是填滿豎直
布局。
分别解釋:
豎直布局。本質是<code>LinearLayout</code>,并且<code>orientation</code>的值為<code>vertical</code>。但是
水準方向的就沒有vetialLayout這種可以直接使用的了,需要自己寫明orientation。
建立一個listview。
給這個listview添加adapter。這裡簡單實用<code>ArrayAdapter<String></code>。
添加<code>OnItemClickListener</code>。<code>object : AdapterView.OnItemClickListener</code>用來
建立實作某個接口的匿名類。
<code>startActivity<TabDemo1>()</code>,是Anko的文法糖。<code>startActivity(SourceActivity.this, DestActivity.class)</code>
可以直接簡化為<code>startActivity<DestActivity>()</code>。簡單了不少。
在<code>lparams</code>中設定layout params相關的内容。預設的都是wrap content。這個設定為
寬、高都為match parent。
熱身結束。我們來開始真正的開發階段。
下面要開發的是一個日記App。一共有三個tab,第一個是日記清單,第二個tab是寫日記,第三個tab可以設定一些字型大小等(這裡隻用來占位,不做實作)。
每一個tab都用一個<code>Fragment</code>來展示内容。這三個tab分别<code>HomeListFragment</code>, <code>DetailFragment</code>,<code>DiarySettingsFragment</code>。這個三個fragment都在一個叫做<code>TabDemo1</code>的托管Activity裡。
現在就從這個托管activity:<code>TabDemo1</code>開始。這裡我們不使用預設的<code>ActionBar</code>,而是用完全自定義的方式來寫一個我們自己的action bar。是以需要把界面設定為全屏模式。設定全屏的模式的方法有很多,我們用設定style的方式來實作。
之後把這個style應用在activity在AndroidManifest.xml配置中。
這個時候這個托管activity的界面布局就是一個完全的白闆了。這個白闆現在要分為上中下三部分。上部為我們自定義的action bar,最下面的是tab bar,剩下的部分就是每個tab的内容的fragment。
我們來看一下這個布局應該怎麼寫:
前文的例子用了一個<code>verticalLayout</code>, 這裡用的是<code>relativeLayout</code>的布局。
這裡是自定義action bar。使用換一個<code>linearLayout</code>。如前所述,要橫向布局linear layout
就需要單獨的指定orientation:<code>orientation =LinearLayout.HORIZONTAL</code>。這裡比較簡單,隻有一個顯示title的text view。
這裡需要注意<code>gravity = Gravity.CENTER_HORIZONTAL or Gravity.CENTER_VERTICAL</code>
可以直接寫成<code>gravity = Gravity.CENTER</code>。這裡是為了突出<code>or</code>的用法。Kotlin裡的<code>or</code>
就是java的<code>|</code>操作符的作用。
這部分的布局是tab bar。
這裡用的是<code>weightTextView</code>而不是<code>textView</code>。後面會詳細的講解這一部分。
給tab bar添加style。此style不是彼style。這個style,會周遊tab bar的linear layout内部的全部的view,然後根據<code>when</code>表達式比對對應的規則,之後給對應于規則的view設定相應的屬性。比如,這裡會用when語句檢視view是否為textView,如果是的話就給這個view設定padding、drawable padding、text size以及gravity屬性。tab bar的linear layout有三個text view,是以他們都會被設定這些屬性。
每一個tab的内容展示用fragment就是這裡了。準确的說是fragment的container。
這個container是一個framelayout。在action bar之下,在tab bar之上。在布局的時候有<code>below(ID_TOP_BAR), above(ID_BOTTOM_TAB_BAR)</code>。<code>ID_TOP_BAR</code>和<code>ID_BOTTOM_TAB_BAR</code>就分别是action bar和tab bar的id值。這些id值自由設定。
另外,在java寫的時候常用的<code>findViewById()</code>方法在Kotlin和Anko中可以改為的<code>find<FrameLayout>(ID_FRAMELAYOUT)</code>。不見得簡單,但是增加了類型安全。不用再強制類型轉換。也不用擔心相關的錯誤再發生。
上文第4點用到了<code>weightTextView</code>。這是一個自定義的view。在Anko布局中,可以根據自己的需要自定義各種各樣的view。但是,需要經過一個小小的處理之後才可以使用到Anko的布局中。這個小小的處理就叫做擴充。下面看看如何給Anko添加<code>weightTextView</code>擴充的。
首先自定義一個view:<code>WeightTextView</code>。
附加解釋:
方法<code>setSelected()</code>是被迫添加的。在使用Anko,相當于使用代碼開發Android布局的時候<code>selector</code>不起作用。隻好把點選後的高亮效果寫在自定義的text view裡。
下面看看如何擴充Anko,來使用我們上面的自定義view。
這裡簡單介紹一下。拿官網的例子說一下:
現在有這麼一個<code>HTML</code>類,那麼調用的時候可以這樣:
在這麼一個lambda表達式裡就可以直接這樣調用<code>HTML</code>類的方法了,中間的過程是怎麼樣的呢
其實灰常的簡單呢。在方法<code>html()</code>裡,參數是一個<code>HTML</code>類的擴充方法,并且此方法無參,傳回<code>Unit</code>(java的<code>void</code>)。
在方法執行的過程中,首先初始化了<code>HTML</code>。之後調用了這個作為參數傳入的擴充方法。在具體調用<code>html()</code>方法的時候,可以隻簡單寫一個lambda表達式作為傳入的<code>HTML</code>擴充方法。既然是一個類的擴充方法,那當然可以調用這個類内部的方法了。
為了幫助了解,這裡給出一個參數是方法的方法:
第一個是用lambda表達式作為傳入方法,第二個是已經定義好的一個方法作為傳入方法。
本文中的重點在于使用Anko做布局,具體的邏輯處理java寫和Kotlin寫沒有什麼差別。這裡隻簡單介紹一下。
為了保證相容,這裡使用Support v4來處理Fragment的顯示等操作。在activity的一開始就把需要的fragemnt都加載進來。
每一個tab項被點選的時候的處理:
在開始之前需要考慮一個很嚴重的事情:資料存在什麼地方。本來應該是SQLite或者存在雲上的。存在雲裳就可以實作同一個賬号登入在任何地方都可以同步到同樣的内容。這裡隻簡單模拟,存放在app的記憶體裡。存放在<code>Application</code>派生類<code>AnkoApplication</code>的
靜态屬性<code>diaryDataSource</code>裡。<code>diaryDataSource</code>是一個<code>ArrayList</code>一樣的清單。
<code>HomeListFragment</code>類作為第一個tab内容展示fragment,用來顯示全部的日記清單的布局就非常簡單了,和我們前面的例子沒有什麼太大的差别。就是在一個verticalLayout裡放一個list view。這個list view的data source隻需要一個清單。
在activity裡的布局可以直接寫<code>vertical{}</code>,但是在fragment裡不可以這樣。直接寫<code>vertical{}</code>就已經把這個layout添加到父view上了,這fragment裡是不行的。在fragment裡需要建立一個單獨的view,并傳回。用<code>with</code>語句來建立這樣一個單獨的view。
在vertial layout裡添加了一個textview。
上面一步建立的textview作為list view沒有資料的時候顯示的empty view來使用。
日記的内容包括,日記title,日記本身的内容還有日記的日期。
是以布局上就包括日記的title、内容輸入用的<code>EditText</code>以及為了說明用的text view,還有edit text裡的hint。最後還有一個選擇
日期的控件。
需要注意打星号的地方。按鈕在點選之後會彈出一個dialog fragment來顯示日期view。使用者可以在這個日期view裡選擇相應的日期。但是,如何從日期dialog fragment傳遞選擇的日期給<code>DetailFragment</code>呢?這裡就涉及到兩個fragment之間傳遞資料的問題。
選擇日期的dialog fragment是<code>DatePickerFragment</code>。
首先<code>DatePickerFragment</code>要繼承<code>DialogFragment</code>之後override方法<code>onCreateDialog(savedInstanceState: Bundle)</code>。在這個方法裡使用上面代碼建立一個包含日期選擇器的dialog。
在選擇日期的時候,會觸發<code>DatePicker</code>的<code>OnDateChangedListener</code>接口的<code>onDateChanged</code>方法。我們在這個方法裡記錄選擇好的日期資料,在dialog的positive按鈕點選之後把這個資料發送給<code>DetailFragment</code>。
那麼怎麼發送呢?使用target fargment方法。在detail fragment彈出dialog fragment的時候,把detail fragment設定為target fragment。
在标星下面的一行代碼中。<code>datePicker.setTargetFragment(this@DetailFragment,DetailFragment.REQUEST_DATE)</code>将<code>DetailFragment</code>設定為target fragment,并且指定<code>REQUEST_DATE</code>這code,為以後取出資料使用。
在positive按鈕點選之後執行方法<code>sendResult</code>回傳資料
調用<code>targetFragment</code>的<code>onActivityResult()</code>方法來回傳日期資料。
在<code>DetailFragment</code>中通過override方法<code>onActivityResult()</code>來接收資料。
日期資料傳輸這部分到這裡結束。
全文也可以在這裡畫上一個句點了。以上還有很多關于Anko沒有使用的地方。Anko也是可以實作代碼界面分離的。繼承<code>AnkoComponent</code>可以寫出獨立的布局檔案,并且可以用anko preview插件來預覽界面效果。就拿setting這個tab的fragment來舉例:
首先定義一個獨立的布局檔案:
把這個布局檔案用在<code>DiarySettingsFragment</code>上:
然後這個布局還可以用在我們剛剛建立的<code>TempActivity</code>上:
Activity上使用就簡單很多了,隻需要這麼一句<code>SettingsUI<TempActivity>().setContentView(this)</code>。
歡迎加群互相學習,共同進步。QQ群:iOS: 58099570 | Android: 572064792 | Nodejs:329118122 做人要厚道,轉載請注明出處!
本文轉自張昺華-sky部落格園部落格,原文連結:http://www.cnblogs.com/sunshine-anycall/p/5300305.html,如需轉載請自行聯系原作者