ActionBarCompat 【Swipe to change tab】

23 October 2013

上一篇ActionBarCompat 【Add Tab】講到了,你們可能會覺得很奇怪,
為什麼不管點tab1還是tab2,
怎麼內容都一樣?
因為我們的確沒有透過FragmentTransaction把Fragment加進來!
最後的結論是說,要透過ViewPager去把Fragment加進來!

所以這篇就是要教大家怎麼使用ViewPager,
使用ViewPager好處就是,使用者可以用swipe去換tab,


1. 首先請將你的class implement OnPageChangeListener 這個interface

public class MainActivity extends ActionBarActivity implements TabListener,OnPageChangeListener {
....
}


2. 增加對應的method

因為在第一步的時候,你就已經implement一個interface進來,
所以在第二步驟我們必須增加下面的method

@Override
public void onPageScrollStateChanged(int arg0) {}

@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {}

@Override
public void onPageSelected(int iPosition) {
getSupportActionBar().setSelectedNavigationItem(iPosition);
}


我們在上面的onPageSeleced中實作了一段code,
它的目的就是當你swipe到該page,就顯示該page應顯示的Fragment!


3. 加入2個Fragment

這步驟是新增兩個Fragment,
目的是為了要塞在tab裡面!
由於很簡單,就不貼example了!
反正就是兩個Fragment(先命名為FragmentTab1, FragmentTab2)



4. 加入FragmentPagerAdapter

FragmentPagerAdapter目的就是待會要餵給viewPager使用的,
這樣viewPager才知道捲動到哪頁的時候,要顯示哪個Fragment.
我們可以在getItem看到,
當iPosition為1的時候,意思就是卷到第一個tab了!
所以我們就在這new上面新增的FragmentTab1出來!

public class HomeViewPagerAdapter extends FragmentPagerAdapter{

public HomeViewPagerAdapter(FragmentManager fm) {
super(fm);
}

@Override
public Fragment getItem(int iPosition) {
switch (iPosition) {
case 0:
return new FragmentTab1();
case 1:
return new FragmentTab2();
}
return null;
}

@Override
public int getCount() {
return 2;
}
}





5. 在layout中加入viewpager

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">

<android.support.v4.view.ViewPager
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />


</LinearLayout>



6. 取得layout中的viewpager

在這步驟就是取得剛剛上步驟新增的viewpager,
然後對它作設定,
首先要先設定adapter,這裡就是餵給他我們上面的HomeViewPagerAdapter,
接著就是設定listener,這裡我們指定this,指定this的話就會去抓第二步驟implement的method!
當然你也可以自己new!
至於第三步與第四步是optional的!當然你也可以不要設定!
這兩步驟只是為了讓畫面好看一點,在tab1和tab2之間swipe的時候,中間會有一個style在!
但理論上,你們第三步與第四步都會錯,因為沒有圖也沒有設定dimension!
private ViewPager viewPager;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

viewPager = (ViewPager) findViewById(R.id.pager);

if (viewPager!=null){
viewPager.setAdapter(new HomeViewPagerAdapter(getSupportFragmentManager()));
viewPager.setOnPageChangeListener(this);
viewPager.setPageMarginDrawable(R.drawable.grey_border_inset_lr); // optional
viewPager.setPageMargin(getResources().getDimensionPixelSize(R.dimen.page_margin_width)); // optional
}
}




7. hook onTabSelected

理論上完成上面的步驟,
你應該就可以完成用swipe換tab了!
可是你可能會發現,當你直接點tab時,
tab並不會更換!
所以最後一步驟就是要實作這一塊!
還記得上一篇嗎?
我們有implement onTabSelected這個method!
在裡面加入下面的code吧!

@Override
public void onTabSelected(Tab tab, FragmentTransaction arg1) {
viewPager.setCurrentItem(tab.getPosition());
}



大功告成!
恩,下一篇會教大家怎麼去style自己的actionbar(if i have time..)












read more »


Arduino WiFi Shield

30 September 2013

多虧於公司intern的實驗室,
我才有榮幸玩到Arduino的wifi套件!
不然一塊三千多塊,實在是買不下去阿!

這篇主要教大家,
怎麼用這塊wifi shield去做到下列的事情

  1. scan network AP
  2. connect to a network AP
  3. send a request
  4. create a WebServer using exists connection


恩,在開始之前,請先準備好環境!
注意!在我寫文章的這個時候!
arduino已經出到了1.0.5版!
最一開始我是用1.0.1版開發,但1.0.1版是沒有wifi的lib,
所以我自己去github把wifi的lib抓下來,再放在我的lib裡面!
的確!大部份功能都可以work!
除了建立webserver以外!
但是不要天真的以為用1.0.5版就可以建立webserver,
根據撞牆了幾個小時,發現要downgrade至1.0.2版才能建立webserver...
其實1.0.5版也可以,只是要做一些操作!實在太麻煩!
總而言之,請使用1.0.2



1. 把wifi shield直接插在你的arduino板上!

官網其實有備註,如果你是用比較舊的板子(UNO R3),還要稍微接一下線!
請看這篇吧!



2. include necessary lib

#include <WiFi.h>


3. 開始寫code

3.1 掃描附近所有的ap

void setup(){
Serial.begin(9600);
}

void loop(){
fnScanNetwork();
}

void fnScanNetwork(){

int iNum = WiFi.scanNetworks();
Serial.print("=========number of available networks:");
Serial.print(iNum);
Serial.println("=========");

// print the each SSID and Signal
for (int i = 0; i<iNum; i++) {
Serial.print(WiFi.SSID(i)); // pring SSID
Serial.print("\tSignal: ");
Serial.print(WiFi.RSSI(i)); // print Signal
Serial.print(" dBm");
Serial.print("\tEncryption: ");
Serial.println(WiFi.encryptionType(i)); // print Encryption Type
}

}



上面比較需要注意的大概就是WiFi.RSSI(i),
這隻method就是回傳該AP訊號的強弱!
記得值越大訊號越強!

再來就是WiFi.encryptionType(i),
這是回傳該AP的加密形態是什麼?
內容如下:
* TKIP (WPA) = 2
* WEP = 5
* CCMP (WPA) = 4
* NONE = 7
* AUTO = 8


3.2 連線至某個ap

char szSsid[] = "kerkerker";          //  network SSID (name) 
char szPass[] = "safesync"; // network password

int iStatus = WL_IDLE_STATUS;

void setup(){
Serial.begin(9600);
fnConnectToAP();
}

void loop(){
}

void fnConnectToAP(){
while ( iStatus != WL_CONNECTED) {
Serial.println("Connecting to network...");
Serial.print("SSID: ");
Serial.println(ssid);
delay(1000);
iStatus = WiFi.begin(ssid, pass); // connect
}

Serial.print("Connected successfully. IP address:");
IPAddress myAddress = WiFi.localIP();
Serial.println(myAddress);
}


WiFi.begin這個method就是在進行連線!
如果成功的話會看到下面兩張圖!
首先你的wifi shield上的link那顆燈會變成綠色!


而你的Serial Monitor會長得像下面一樣!





3.3 傳送一個request至一個server

首先在setup裡面先連線至ap,
接著就送出一個request,
然後就在loop裡面進行讀資料的動作!
如果成功的話,你應該會在你的Serial Monitor看到一大堆回傳的資料才對!

// connect to ap
int iStatus = WL_IDLE_STATUS;
char szSsid[] = "kerkerker"; // network SSID (name)
char szPass[] = "safesync"; // network password


// send a request
char szServername[]="www.google.com"; // remote server we will connect to
WiFiClient client;

void setup(){
Serial.begin(9600);
fnConnectToAP();
fnSendRequest();
}

void loop(){
fnReadData();
}

void fnSendRequest(){
if (client.connect(szServername, 80)) {
Serial.println("connected");

// Send a HTTP request:
client.println("GET /search?q=arduino HTTP/1.1");
client.println("Host: www.google.com");
client.println();
}

}
void fnReadData(){
while (client.available()) {
char c = client.read();
Serial.print(c);
}

// if the server's disconnected, stop the client:
if (!client.connected()) {
Serial.println();
Serial.println("disconnecting from server.");
client.stop();

// do nothing forevermore:
while(true);
}
}




3.4 建立一個webserver供人連線

輸入下列的code以後,接著只要用browser輸入你的ip,
就會看到Hello World了!

// webserver
WiFiServer server(80);

void setup(){
Serial.begin(9600);
fnConnectToAP();
// fnSendRequest();
fnStartServer();
}

void loop(){
fnWaitingRequest();
// fnReadData();
}


void fnStartServer(){
delay(1000);
server.begin();
}

void fnWaitingRequest(){
WiFiClient client = server.available();

if (client) {
Serial.println("new client comming");

boolean bCurrentLineIsBlank = true;
while (client.connected()) {
if (client.available()) {
char c = client.read();
Serial.write(c);
// if you've gotten to the end of the line and the line is blank, the http request has ended,
// so you can send a reply
if (c == '\n' && bCurrentLineIsBlank) {
// send a standard http response header
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close"); // the connection will be closed after completion of the response
client.println();
client.println("<!DOCTYPE HTML>");
client.println("<html>");
client.print("Hello World ");

client.println("</html>");
break;
}
if (c == '\n') {
// you're starting a new line
bCurrentLineIsBlank = true;
} else if (c != '\r') {
// you've gotten a character on the current line
bCurrentLineIsBlank = false;
}
}
}
// give the web browser time to receive the data
delay(1);

// close the connection:
client.stop();
Serial.println("client disonnected");
}

}



source code: https://github.com/Ken-Yang/ArduinoWiFiShield

基本上蠻簡單的,
code也很好理解!
只是有些tricky的地方,
像是1.0.5版需要update firmware!
官網上也有很多豐富的example!
有空可以去看看!


如果有空,下一篇會教大家怎麼結合wifi+遙控車!















read more »


ActionBarCompat 【Add Tab】

28 September 2013

上一篇ActionBarCompat 【Basic】教導大家怎麼使用Google提供的ActionBarCompat lib以後,
這篇要延續上篇實作的actionbar,來加入tabs!

最早在android要使用tab的layout,
必須使用tabhost這個object!
但現在被deprecated了!
後來推薦使用Fragment去控制tabwidget ui object.
但這篇是要教大家怎麼直接用actionbar加入tabs,
相較前面的兩種方法,用actionbar比較簡單!


1. 首先請將你的class implement TabListener 這個interface

public class MainActivity extends ActionBarActivity implements TabListener {
....
}


2. 加入應有的method

因為你前一步驟implement了一個interface,
那麼在你的Class之中,也應該要有該interface底下的method,
所以你的class一開始應該會紅紅的一條,代表error,
那麼你只要將滑鼠移至該class名稱上,eclipse就會有選項幫你直接加入該有的method,
或者你也可以自己直接加入,如下

@Override
public void onTabReselected(Tab arg0, FragmentTransaction arg1) {
// TODO Auto-generated method stub

}

@Override
public void onTabSelected(Tab arg0, FragmentTransaction arg1) {
// TODO Auto-generated method stub

}

@Override
public void onTabUnselected(Tab arg0, FragmentTransaction arg1) {
// TODO Auto-generated method stub

}


3. 加入tab

這邊是利用ActionBar去加入tab,
所以我們再加入之前應該先取得actiobar這個object,

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

final ActionBar actionbar = getSupportActionBar();

}

接著設定navigation mode,
這裡分成三種

  1. ActionBar.NAVIGATION_MODE_LIST     (actionbar左上角會有spinner)
  2. ActionBar.NAVIGATION_MODE_TABS    (就是tabs)
  3. ActionBar.NAVIGATION_MODE_STANDARD    (什麼都不會有,只剩actionbar)

所以理論上我們要設成第二種!

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

final ActionBar actionbar = getSupportActionBar();

actionbar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

}

最後一步就是加入tab了!

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

final ActionBar actionbar = getSupportActionBar();

actionbar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

// add tab
actionbar.addTab(actionbar.newTab().setText(R.string.tab1).setTabListener(this));
actionbar.addTab(actionbar.newTab().setText(R.string.tab2).setTabListener(this));

}



接著大家就可以deploy上去看看了!
應該就可以看到2個tab出現!
如下圖



這時候大家可能會覺得很奇怪,
不管點tab1還是tab2,
怎麼內容都一樣?

原因是因為你要在先前implement的method(onTabSelected)中,
透過FragmentTransaction把Fragment加進來!
好!這時候大家可能也會好奇一件事,我的Class明明是 extends ActionBarActivity,
怎麼可能在這個class之中把Fragment加進來?不是應該要透過FragmentActivity嗎?
恩,其實如果你們在往下層看,會發現ActionBarActivity這個class也是extends FragmentActivity!
所以自然而然可以在ActionBarActivity中把一個Fragment加進來!

但是!!!!在這裡我不會教你用這種方式!!!
為什麼?
其實在Google Standard之中,希望我們有tabs時,理應上要支援swipe to change tab!
那麼要怎麼做到呢?
就是靠ViewPager!
下一篇ActionBarCompat 【Swipe to change tab】中,會教大家怎麼用ViewPager去把Fragment加進來以及可以swipe!



















read more »