2015年5月31日 星期日

Android 開發 (九十九) What's New in M support-design-widget NavigationView

NavigationView的使用情境是在側欄

套上navigationview 讓你可以較容易的刻出material的樣板
你只需要在layout裡放

<android.support.design.widget.NavigationView    android:id="@+id/navigation"    android:layout_width="wrap_content"    android:layout_height="match_parent"    android:layout_gravity="start"    app:headerLayout="@layout/headerlayout"    app:menu="@menu/menu_main" />

headerlayout為上方的板塊,headerlayout 可以利用addHeaderView
增加header 剩餘下方的選項,如上方的settings 則是寫在menu裡
利用menu做設定,這種設計的作法,感覺google也是想告訴我們
側欄應該只放設定相關的東西,而不應該放太多有的沒的資訊吧.

Android 開發 (九十八) android studio 1.13 databinding part2

上一篇有提到,databinding的介紹,今天這篇要介紹的是,
假設model變更時,要如何讓view也跟著改變呢?

其實方法很簡單,android 有提供新的class BaseObservable
如下圖

    public class User extends BaseObservable {
        private String firstName;
        private String lastName;

        @Bindable
        public String getFirstName() {
            return firstName;
        }

        @Bindable
        public String getLastName() {
            return lastName;
        }

        public User(String firstName, String lastName) {
            this.firstName = firstName;
            this.lastName = lastName;
        }

        public void setFirstName(String firstName) {
            this.firstName = firstName;
            notifyPropertyChanged(BR.firstName);
        }

        public void setLastName(String lastName) {
            this.lastName = lastName;
            notifyPropertyChanged(BR.lastName);
        }
    }

我們只需要在set之後,call notifyPropertyChanged就行了

    TwowaydatabindingLayoutBinding binding;
    User user;
    private int i = 0;

    @Overrideprotected
    void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = DataBindingUtil.setContentView(this, R.layout.twowaydatabinding_layout);
        user = new User("Test", "User");
        binding.setUser(user);
        findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                user.setLastName("change " + i);
                Toast.makeText(view.getContext(), " " + user.getLastName(), Toast.LENGTH_SHORT).show();
                i++;
            }
        });
    }
如上面的code所示,我在按鈕click的時候去改變user的lastName
然後edittext的lastname就會跟著改變

其實這種方法很像是adapter的notifydatasetChanged
不過目前這種方法只能用在 data change 通知 ui 改變
但是 ui 改變 -> data change這條路似乎還沒有看到任何的解法

希望在 android M正式release 的時候可以有 two-way binding的寫法出現.

2015年5月30日 星期六

Android 開發 (九十七) android studio 1.13 databinding part1

databinding 之前在寫windows的時候就用過,由於非常好用,
所以一直期待android 也可以support,如今android studio 1.13 support了這個功能!!

現在就來介紹如何使用

首先必須先將android studio升級到1.13
接下來必須在專案的 build.gradle裡加入
classpath 'com.android.databinding:dataBinder:1.0-rc0'

接下來必須在app的build.gradle裡加入
apply plugin: 'com.android.databinding'

然後就可以在app裡使用databinding的功能了

<?xml version="1.0" encoding="utf-8"?><layout xmlns:android="http://schemas.android.com/apk/res/android">    <data>        <variable name="user" type="com.designsupportlibrary.normaldatabinding.NormalUser"/>    </data>    <LinearLayout        android:orientation="vertical"        android:layout_width="match_parent"        android:layout_height="match_parent">        <EditText android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:text="@{user.firstName}"/>        <EditText android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:text="@{user.lastName}"/>        <Button            android:id="@+id/btn"            android:layout_width="wrap_content"            android:layout_height="wrap_content" />    </LinearLayout></layout>

如上面的xml file data代表著要連動的model
這代表著我們有一個 user class

public class NormalUser  {
    private String firstName;    private String lastName;
    public String getFirstName() {
        return firstName;    }
    public String getLastName() {
        return lastName;    }

    public NormalUser(String firstName, String lastName) {
        this.firstName = firstName;        this.lastName = lastName;    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
}

接著我們只需要將normalUser 與 ui 做綁定的動作即可
    NormalMainBinding binding;
    NormalUser user;

    @Overrideprotected
    void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = DataBindingUtil.setContentView(this, R.layout.normal_main);
        user = new NormalUser("Test", "User");
        binding.setUser(user);
        findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(view.getContext(), user.getLastName(), Toast.LENGTH_SHORT).show();
            }
        });
    }

所以這邊代表的意思就是,
首先我們會create一個binding的物件,他與view做綁定,但是我們還沒有將data餵給他
接著我們init User ,然後使用setUser 將 view 與 資料綁定

這時候 上方的edittext 就會去取得 firstName的資料
而下方的edittext就會去取得 lastName的資料,

不過目前的綁定方法就只有set下去的瞬間而已,之後你再對user做任何的改變都不會有其他相對應的變化了,如果要有相對應的變化,那就必須針對User做額外的動作,
不過這個就得等到part2 的時候再說囉XD

2015年5月29日 星期五

Android 開發 (九十六) What's New in M support-design-widget TabLayout

先讓我們看一下圖



在TabLayout出來之前,如果要做出類似的功能,除了自己刻之外,我想大部份的人都會利用https://github.com/astuetz/PagerSlidingTabStrip這個library吧

這個TabLayout 讓我們可以使用官方的api 而不用再依照3-party lib,不用再擔心library不再維護的問題了XD

接下來介紹該如何實做

跟正常的viewpager and tab一樣必須定義這兩個layout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <android.support.design.widget.TabLayout
        android:id="@+id/tabs"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

接下來只需要initViewpager
ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);setupViewPager(viewPager);
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(viewPager);
tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);

然後再使用 setupWithViewPager 將viewpager set 進去就行了,
這邊有一個設定要特別注意, setTabMode 有分 MODE_FIX and MODE_SCROLLABLE
其中如果使用MODE_SCROLLABLE  tab的textview的寬度才會正常顯示,否則textview的寬度會只有一個字的寬度

如上圖所示

不過在使用這個api的時候有遇到一個問題,當我利用下面的程式碼
tabLayout.setTabTextColors(Color.BLUE,Color.parseColor("#FF2750"));
想要更換tab的顏色時,卻無法正確更換,
當然還有下面那條線的顏色,目前還找不到更換的方法,
我猜測只能由theme來更換了. 如果有試出來再跟大家分享囉

Android 開發 (九十五) What's New in M support-design-widget Snackbar

What's SnackBar ? 讓我們看一下下面的圖片

SnackBar我們可以理解為進階版的toast
例如說當用戶刪除了某項商品,我們其實無法用比較不擾人的方式
去提示用戶是否要刪除該商品

如果用dialog 非常擾人
如果用toast 非常無感...而且無法做任何undo的動作

SnackBar應該是比較折衷的方式,利用show出一小段提示,讓用戶有機會可以反悔

講了那麼多我們要來介紹來如何實做了
要使用SnackBar我們只需要
    findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
        @Override public void onClick (View view){
            SpannableString s = new SpannableString("you just remove this product");
            s.setSpan(new ForegroundColorSpan(Color.RED), 0, s.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
            Snackbar.make(view, s, Snackbar.LENGTH_SHORT).setAction("undo", new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Log.d("Ted", "do click");
                }
            }).setActionTextColor(Color.parseColor("#FF2750")).show();
        }
    });

如上使用 Snackbar.make(...).show()就可以了,比較跟toast不同的地方在於,
snackbar需要view,而且文字可以換色,並且擁有click event,

在這邊還有一件事情要特別提到,Snackbar並沒有提供設定左邊文字顏色的api,
不過我們可以利用SpannableString來換色,如上面的sample code

我想之後很多app都會使用到這樣的特效吧. 個人真的認為還蠻實用的!!

Android 開發 (九十四) What's New in M support-design-widget FloatingActionButton

what's FloatingActionButton? 讓我們來看看下面的圖



值得注意的是我的版本是4.4 ,但是有shadow,而且點擊的時候也有shadow,
接下來我們要介紹如何實作,FloatingActionButton的實作方式更簡單
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:android.support.design="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <android.support.design.widget.FloatingActionButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="end|bottom"
        android:src="@drawable/abc_ic_clear_mtrl_alpha"
        android.support.design:fabSize="mini" />

    <android.support.design.widget.FloatingActionButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="end|bottom"
        android:src="@drawable/abc_ic_clear_mtrl_alpha"
        android.support.design:fabSize="normal" />
</LinearLayout>

只需要將ui放到xml上就完成了XD
在這邊值得一提的是,floatingActionButton有一個property fabSize,
要在xml上使用則必須加上
xmlns:android.support.design="http://schemas.android.com/apk/res-auto"
才能正確使用,fabSize有分normal and mini如上圖,就是正常size和mini size

今天介紹floatingActionButton就到這邊,接下來還會有需多新的ui會介紹唷!!

Android 開發 (九十三) What's New in M support-design-widget TextInputLayout

google io 2015 推出了新的support lib.
其中包含了 'com.android.support:design:22.2.0'
這個lib多了許多實用的material ui ,最近會一一介紹

今天要介紹的是 TextInputLayout



如上圖當沒有focus而且沒有key字的時候,hint會顯示在edittext裡,
當focus時hint就會像是title一樣顯示在edittext上方,

我想上面的圖片很清楚的展示了他的效果

至於要如何實做?

首先必須在gradle裡加入
compile 'com.android.support:design:22.2.0'

接著在xml裡加入textinputlayout
<android.support.design.widget.TextInputLayout    android:id="@+id/inputlayout"    android:hint="name"    android:layout_width="wrap_content"    android:layout_height="wrap_content" >    <EditText        android:hint="name"        android:layout_width="wrap_content"        android:layout_height="wrap_content" /></android.support.design.widget.TextInputLayout>

記得要在裡面放一個EditText,然後目前的TextInputLayout有一些問題
除非在TextInputLayout 和 EditText 加上hint 還有在code裡面也加上hint
TextInputLayout inputLayout = (TextInputLayout)findViewById(R.id.inputlayout);inputLayout.setHint("name");

否則上面的效果不會出現(至少在我的模擬器上面是這樣子的 genymotion 4.4)
只需要簡單的步驟,我們就設定好了,是不是很簡單!!