2014年6月27日 星期五

[Android]使用 BaseAdapter客製化 ListView


上一篇:[Android] Action Bar Tabs 和 ListView 簡易示範

範例下載:GitHub

  上一篇已經有提到如何簡單使用 ListView的功能,今天我們就來使用 BaseAdapter客製化 ListView (把每一個 ListView都用 Layout顯示)。


一、為了程式的可維護性及 Android的 MVC架構,使 Controller及 Model分開,我們將新增一個套件( package),並且在裡面建立 ListView Adpater及 項目要用的物件。

  對著 src按右鍵,並且選擇新建-->套件 我們在這邊取名為"com.example.utils",接著在此套件中新建兩個類別( class),分別取名為 NewItem及 ListViewAdpater,完成後如下圖:


  

然後先撰寫 NewItem物件的內容:

package com.example.utils;

public class NewItem {
 
 private String Memo;
 private String Time;
 
 public NewItem(String memo,String time) {
  this.Memo=memo;
  this.Time = time;
 }
 
 public String getMemo(){
  return Memo;
 }
 
 public String getTime(){
  return Time;
 }
 
 
}

二、創立顯示 Item的 Layout



這邊命名為fragment0_listitem.xml,內容如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <!-- first row that Country and publish date -->

    <TextView
        android:id="@+id/Time"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="right|center_vertical"
        android:maxLines="1"
        android:text="2014-03-10"
        android:textColor="#0f55bd"
        android:textSize="15dp" />

    <TextView
        android:id="@+id/Memo"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:ellipsize="end"
        android:maxLines="2"
        android:text="item 1"
        android:textColor="#000000"
        android:textSize="20dp" />

</LinearLayout>



三、實作 ListViewAdpater(繼承  BaseAdapter)的內容。 
 
  這邊簡單介紹一下 BaseAdapter(網路上有人翻作基礎連接器)。上一章有說到 Adpater是用來給像是 Spinner、ListView、GridView塞入資料用的,而這三個其實都有各自的 Adapter,但  BaseAdapter對這三個是可以通用的,這是為什麼呢?由 API可知, 這是因為 BaseAdapter實作了 ListAdapter和 SpinnerAdapter,而 GridView 的 Adpater本身也實作了 ListAdapter,因此 BaseAdapter對它們來說是三者通用的。



ListViewAdpater.java內容如下:

package com.example.utils;

import com.example.actionbartabstest.R;
import java.util.List;
import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

public class ListViewAdpater extends BaseAdapter {
 Context context;
 List items;

 public ListViewAdpater(Context context, List items) {
  this.context = context;
  this.items = items;
 }

 //hold views for costomized listview
 private class ViewHolder {
  TextView txtMemo;
  TextView txtTime;
 }

 @Override
 //How many items are in the data set represented by this Adapter.
 public int getCount() {
  return items.size();
 }

 @Override
 //Get the data item associated with the specified position in the data set.
 public Object getItem(int position) {
  return items.get(position);
 }

 @Override
 //Get the row id associated with the specified position in the list.
 public long getItemId(int position) {
  return position;
 }

 @Override
 //Get a View that displays the data at the specified position in the data set.
 public View getView(int position, View convertView, ViewGroup parent) {
  ViewHolder holder;
  LayoutInflater mInflater = (LayoutInflater) context
    .getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
  if (convertView == null) {
   convertView = mInflater.inflate(R.layout.fragment0_listitem, null);
   holder = new ViewHolder();
   holder.txtMemo = (TextView) convertView.findViewById(R.id.Memo);
   holder.txtTime = (TextView) convertView.findViewById(R.id.Time);
   
   convertView.setTag(holder);
  } else {
   holder = (ViewHolder) convertView.getTag();
  }

  NewItem items = (NewItem) getItem(position);
  
  holder.txtMemo.setText(items.getMemo());
  holder.txtTime.setText(items.getTime());
  
  return convertView;
 }

}

其函數作用內容可以參考API:BaseAdapterAdapter



四、將其加入 我們先前準備的 MainActivity中。

  在前一篇我們已經產生了一個 Fragment來塞入 ListView,在這邊我們要來取代原本的內容。請將 Fragment0的 onCreateView改寫如下:

public View onCreateView(LayoutInflater inflater, ViewGroup container,
    Bundle savedInstanceState) {
        List rowitem= new ArrayList();   
        View rootView = inflater.inflate(R.layout.fragment0, container, false);
   
        rowitem.add(new NewItem("item 1","2014/06/26"));
        ListViewAdpater adpater= new ListViewAdpater(getActivity(),rowitem);
        listView.setAdapter(adpater);
   
        return rootView;
}
}


五、Demo


~今天就講解到這裡~

2014年6月24日 星期二

[Android] Action Bar Tabs 和 ListView簡易示範


範例下載:GitHub

  相信大家對 Twitter和 Facebook這種 View應該都不陌生吧!拜諸多大神所賜,現在要寫出這種 View已經是非常容易的事情。今天我們就來簡單實作這種 View─ Action Bar Tabs,並且加入幾個 UI及示範 ListView。



一、首先要創立專案,這裡要特別注意的是在最低版本中需要選擇 API 11(Android 3.0)以上。



  接著就一直下一步,直到 Create Activity的地方選擇 Blank Activity,然後下一步。接著在 Blank Activity的 Navigation Type中選擇 Action Bar Tabs (with ViewPager)這個選項,然後「完成」。



接著我們就直接來 Demo一下剛產生的專案:


接著就可以試著左右滑動,看一下這三個 View,是不是很快呢?


二、接著我們稍微改一下這個專案,將 3個 Fragment改成兩個 Fragment,並且分別在兩個 View中加入不同的元素

改成兩個 Fragment其實也很簡單,只要更改 getCount函數中的回傳值就可以了。
@Override
public int getCount() {
    return 2;
}

  接著為了要方便管理兩個 Fragment,我們將直接修改 PlaceholderFragment這個函數以達到我們的需求:
public static class Fragment0 extends Fragment {

    private static final String ARG_SECTION_NUMBER = "section_number";

        public static Fragment0 newInstance(int sectionNumber) {
            Fragment0 fragment = new Fragment0();
            Bundle args = new Bundle();
            args.putInt(ARG_SECTION_NUMBER, sectionNumber);
            fragment.setArguments(args);
            return fragment;
        }

        public Fragment0() {
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
            View rootView = inflater.inflate(R.layout.fragment_main, container, false);
            TextView textView = (TextView) rootView.findViewById(R.id.section_label);
            textView.setText(Integer.toString(getArguments().getInt(
                ARG_SECTION_NUMBER)));
            return rootView;
        }
}

  然後依樣畫葫蘆,創造出另一個 Fragment1。也由於我們要分開控制兩個 Fragment,所以也要為它們各自產生 layout,我們可以選擇直接更改 fragment_main.xml成 fragment0.xml,並且複製一份成為 fragment1.xml:



  由於 layout改變了,所以我們必須回去修改 MainActivity的 getItem函數,讓它分別對照到兩個 layout:

@Override
public Fragment getItem(int position) {
    switch(position){
        case 0:
        return Fragment0.newInstance(0);
        case 1:
        return Fragment1.newInstance(1);
        default:
        return Fragment0.newInstance(0);   
    }
}

備註:getItem函數可以回傳拿到上面第幾個 Fragment的實體。

這時候我們在第二個 Fragment加入一個 EditText和一個 Button。

Demo一下改完後的狀況:



三、接下來我們要在第一個 Fragment加入 ListView,並且簡單示範一下。

關於ListView:
  ListView是在 Android中很常見的一種 UI,與 iOS的 Table View雷同, ListView 通常使用在需在同一畫面大量使用時,如:電話簿、檔案管理、條列資訊....,都很建議使用。而 ListView在使用上需要搭配 Adapter用以連接資料。

不多說,先在 fragment0.xml加入ListView:
<ListView
    android:id="@+id/listView1"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_alignParentLeft="true"
    android:layout_alignParentTop="true" >
</ListView>

然後我們修改 Fragment1的 onCreateView:
public View onCreateView(LayoutInflater inflater, ViewGroup container,
    Bundle savedInstanceState) {
    View rootView = inflater.inflate(R.layout.fragment0, container, false);
    ListView listView=(ListView) rootView.findViewById(R.id.listView1);
    String[] testArryStrings = new String[]{"1", "2", "3", "4", "5"};
    ArrayAdapter aa= new ArrayAdapter(getActivity(),
        android.R.layout.simple_expandable_list_item_1,
        testArryStrings);
    listView.setAdapter(aa);
    return rootView;
}

關於ArrayAdapter:
  ArrayAdapter是 Android中的一個 Adapter,它可以連結字串陣列到單一個 Text View的 List物件當中。上方程式碼有幾個重點:

  • ArrayAdapte所接收之項目為 Array。
  • ArrayAdapte的方法裡面並沒有提供多欄位的顯示方式。
  • 第一個參數代表目標為 Fragment1的 Activity。
  • 在第二個參數中使用 "android.R.layout.simple_expandable_list_item_1",表示是用 Android 內建的配置。
  • 最後一個參數是欲顯示的項目(字串陣列)。


Demo一下:




~今天就講解到這裡~


Reference 

2014年6月23日 星期一

[jQuery] jQuery入門


  jQuery是一套 JavaScript的函示庫,其主要特色是有著強大的選擇器、跨瀏覽器、Ajax(非同步的 JavaScript 與 XML 技術)、事件等。也因為是 JavaScript的函示庫,所以若要學會使用 jQuery必須要有一點 JavaScript的基礎,在接下來的教學中會簡單介紹放置位置、import、selector、modify、action、ajax等項目。

一、寫在哪?
  由於它是一套 JavaScript的函示庫,所以放置的地點跟 JavaScript是一樣的,需要放在SCRIPT標籤內。

<script>…</script>

二、匯入(import)
  你可以透過官網下載其檔案並進行匯入,或者直接填入官網的檔案位置,其語法如下:

<script src="https://code.jquery.com/jquery-2.1.1.js"></script>

  但是一般為了避免因官方出問題或者你想離線時寫 jQuery,一般建議將它下載下來以方便使用。

官方連結:點我



三、錢字號(Dollar sign)的意義
$代表的就是 jQuery的意思,因此若你在寫作中把 $換成 jQuery也是相通的(Q要大寫)。以下這兩種寫方是一樣的:

$(document).ready(function(){...});
jQuery(document).ready(function()...});


四、甚麼時候開始執行?
  有三種開始情況:
  • body:在讀取完 body標籤後開始執行。
  • document:在讀取完所有文件(.css、.js、.html)後開始執行。一般情況下都是使用這種。
  • window:當所有畫面都載入完畢後開始執行。若你希望文字內容優先載入,圖片晚一點在載入可以使用這種。


寫法如下:

$(document).ready(function(){ });

接下來我們展示第一個範例:
<html>
<head>
<script src="https://code.jquery.com/jquery-2.1.1.js"></script>
<script type="text/javascript">
    var pageOnLoad = function pageOnLoad() {
  alert("Hello World")
 }
 $(document).ready(pageOnLoad);!
</script>
</head><body></body>
</html>

若成功了,會在讀入畫面後立即跳出一個彈跳視窗:

五、選擇器(selector)
  一般會用的有三種,我們也使用範例來了解:

$("body").html(); //選取 body標籤內的所有內容
$("#id_name").html(); //"#" 選取 id名稱為 id_name的所有內容
$(".class_name").html(); //"." 選取 class名稱為class_name的所有內容。

  為什麼'上述都要強調所有呢?因為選擇器所選到的,其實都是陣列型態。所以取到的物件都可以加上陣列索引,若沒加的話預設就是 0開始。

var jsObj = $(".class")[0];

範例如下:
<html>
<head>
<script src="https://code.jquery.com/jquery-2.1.1.js"></script>
<script type="text/javascript">
 var pageOnLoad = function pageOnLoad() {
  alert($("body").html());
  alert($(".title").html());
  alert($("#subtitle").html());
 }
 $(document).ready(pageOnLoad);
</script>
</head>
<body>
 <h1 class="title">Title</h1>
 <h2 id="subtitle">subtitle</h2>
</body>
</html>



六、修飾(modify)

 $(".class").append('…');//在所匹配的元素內加入內容
 $(".class").before('…');//在所匹配的元素之後加入內容
 $(".class").after('…'); //在所匹配的元素之前加入內容


七、動作(action)

$(".class").click(); 
$(".class").onclick(function() {…}); //按一下並觸發function()內的事件
//下列兩種要 jQuery 1.7版後才能使用
$(".class").on("click", function() {…}); //按一下並觸發function()內的事件
$(".class").on("click", "sel", function() {…}) //按一下觸發function()內的事件,並且將sel(自訂的)事件繼承給它


八、Ajax (按我看wiki簡介)
  這邊要注意一下,由於一般可能會預設不同意不同網域載入(不是所有瀏覽器都有此問題,例如IE8則沒此限制),因此會產生 Access-Control-Allow-Origin' header 的問題,解決方法是在提供 Ajax 服務的 response 加上 header (Access-Control-Allow-Origin:*) 即可,但若只是想單純測試,Chrome瀏覽器可以使用 Allow-Control-Allow-Origin套件(按我進入下載安裝頁面)。安裝完後,Chrome瀏覽器右上方會出現CORS按鈕,綠色代表已啟動,紅色則反之。


使用 webservice取得資料,其範例如下:
$.ajax({
    type: "POST", //使用POST方式
    url: "填入webservice網址",
    dataType: 'text', 
    data: {input:"若需要輸入甚麼,可以寫在這裡"},
    success: function(data){ //成功取得資料時
        alert(data);
        var result = jQuery.parseJSON(data); //取回資料後轉換成 JSON格式
    },
    error: function() { //發生錯誤時
        alert(“無法連線至伺服器");
    }
});

上述寫法沒有順序性,並且可依照需求填寫。


OK,今天就簡單介紹到這裡吧~

2014年6月20日 星期五

[Android]監聽事件之順序關係

   在 Android 中,onClick、onLongClick 的觸發是和 ACTION_DOWN 及 ACTION_UP 相關的,在時序上,如果我們在一個 View 中同時覆寫了onClick、onLongClick 及 onTouchEvent 的話,onTouchEvent 是最先捕捉到 ACTION_DOWN 和 ACTION_UP 事件的,其次才可能觸發 onClick 或者onLongClick。

※下面的 Log 是在 onLongClick() 方法 return false 的情況下,一次觸碰操作的基本時序:
06-19 11:05:15.023: DEBUG/TestActivity(277): onTouch ACTION_DOWN
06-19 11:05:15.533: DEBUG/TestActivity(277): onLongClick
06-19 11:05:16.603: DEBUG/TestActivity(277): onTouch ACTION_UP
06-19 11:05:16.663: DEBUG/TestActivity(277): onClick
可以看到,在 ACTION_UP 後仍然觸發了 onClick() 方法。

[JAVA]extends VS implements

  由於 JAVA 不像 C 可以多重繼承,但是我們可以利用 interface 來實現。綜合以上所述, 可列出以下幾點特徵:

  • 具有 abstract method 的 class 必須宣告為 abstract class。
  • 繼承 abstract class 的子類別必須 override 所有父類別的 abstract method, 否則子類別也必須宣告為 abstract class。
  • 實作 Interface A 的 Class 必須實作 A 裡的所有 method, 否則必須宣告自己為 abstract class。
  • 不能直接 new abstract class, 只能 new 其非 abstract class 的子類別。


PS:extends必須在implements前面

不懂嗎? 呂布只有一個親爸爸(繼承),但他有好多個乾爸爸(實作)~~~~

[Objective-C]初學入門,以 Fraction為例


相關資訊:
Xcode版本:5.1.1
範例下載:GitHub

         歡迎加入 Objective-C的世界,此教學筆記將以實作分數為例簡單介紹這個語言。首先你必須先安裝好 Xcode,並且對 C語言有著基本的認識。接著,我們就開始一步步建置這個專案:

一、首先打開 Xcode,並從左上角的 File-->New-->Project新增一個專案。



二、由於我們並不是要寫 iOS的 App,所以從左下角的 OS X的類別選擇 Application,接著在右邊選擇 Command Line Tool (用命令提示字元來執行),然後 Next。


三、接著依照提示填上相關的專案名稱, Type選擇 Foundation。



四、Next之後你就可以選擇專案的儲存位置,以及下方問你有無需要作 Source Control, Source Control基本上是用來做版本控制的功能,由於我這邊並不需要,所以無需打勾。


五、Create後,就已經看到 Xcode幫我們產生的主程式以及相關的目錄。



六、按左上角的 Play按鈕,就可以在左下角見到預設產生的"Hello World"囉!這行訊息是使用 NSLog印出的,NSLog是 Objective-C用來在命令列印出訊息的函數,其中是以 NSString作為參數,若你想用 C語言的 printf也是可以的,但 NSLog預設提的格式訊息(如時間)是非常方便的,因此這邊均會使用 NSLog來印出訊息。



七、接著就要來實作 Fraction,直接對左邊的 testFraction目錄在觸控板上雙指按下(或點右鍵),選擇 New File。


八、選擇 OS X的 Cocoa --> Objective-C Class,然後 Next。



九、Class名稱我們這邊取名為 Fraction,Subclass of選擇 NSObject。NSObject是 Objective-C 的抽象根類別,幾乎所有的物件都繼承自它, NSObject可以幫你的物件初始化,並且真正實作它。



十、接下來你就可以看到它幫我們產生的兩個檔案 .h跟 .m檔。
  • .h 為標頭檔,所有要在外部使用的屬性及方法都要在這裡做宣告。
  • .m 為 Objective-C 的主檔,所有的屬性設定及方法都寫在這裡。





十一、接著我們直接看要寫的程式碼吧!

  • Fraction.h 在這裡我們要宣告外在類別可宣告外在可用的屬性(變數)與方法,若沒在此宣告,外在是無法順利呼叫的。

#import <foundation oundation.h="">

@interface Fraction : NSObject
//自行宣告屬性
@property (nonatomic)int numerator, denominator;
//宣告為property的主要功能是方便我們取用或設定物件裡的資料成員,會自動生成get, set方法
//nonatomic-->允許被不同執行緒同時存取,相對於atomic,速度較快,但較不安全
@property (nonatomic) NSString *str;

//手動實作 get、set方法
-(void) setTo:(int)n over:(int)d;
-(void) print;
-(Fraction*) add:(Fraction*) f;
-(Fraction*) Subtract:(Fraction*) f;
-(Fraction*) Multiply:(Fraction*) f;
-(Fraction*) Divide:(Fraction*) f;
-(Fraction*) Reduction:(Fraction*) f;
@end


  • Fraction.m

#import "Fraction.h"

@implementation Fraction
-(NSString*)description 
{
    //回傳一個NSString結果的分數
    return [NSString stringWithFormat:@"%d/%d",self.numerator,self.denominator];
}

-(NSString*) str
{
   //避免產生空物件
    if(!_str)
    {
        _str=[NSString new ];
    }
    return _str;
}

//覆寫Denominator的set方法,避免Denominator為0
-(void)setDenominator:(int)denominator 
{
    if(denominator) _denominator=denominator;
}

//設定分數之分子分母
-(void) setTo:(int)n over:(int)d 
{
    //兩種寫法均可行
    [self setNumerator:n];
    self.denominator=d;
}

-(void) print
{
    NSLog(@"%i / %i",self.numerator,self.denominator);
}

-(Fraction*) add:(Fraction*) f
{
    Fraction *sum=[Fraction new];
    sum.denominator = self.denominator * f.denominator;
    sum.numerator = self.numerator * f.denominator + self.denominator * f.numerator;
    sum=[sum Reduction:sum];
    return sum;
}

-(Fraction*) Subtract:(Fraction*) f
{
    Fraction *sub=[Fraction new];
    sub.denominator = self.denominator * f.denominator;
    sub.numerator = self.numerator * f.denominator - self.denominator * f.numerator;
    sub=[sub Reduction:sub];
    return sub;
}

-(Fraction*) Multiply:(Fraction*) f
{
    Fraction *mul=[Fraction new];
    mul.denominator = self.denominator * f.denominator;
    mul.numerator = self.numerator * f.numerator;
    mul=[mul Reduction:mul];
    return mul;
}

-(Fraction*) Divide:(Fraction*) f
{
    Fraction *div=[Fraction new];
    div.denominator = self.denominator * f.numerator;
    div.numerator = self.numerator * f.denominator;
    div=[div Reduction:div];
    return div;
}

-(Fraction*) Reduction:(Fraction*) f
{
    for (int i=2; i<f.denominator; i++) {
        while ((f.numerator%i==0) && (f.denominator%i==0)) {
            f.numerator = f.numerator / i;
            f.denominator = f.denominator / i;
        }
    }
    return f;
}



  • main.m 程式進入點,從這裡對 Fraction類別進行測試

#import <Foundation/Foundation.h>
//外部的 import是使用 ” 符號
#import "Fraction.h"

int main(int argc, const char * argv[])
{

    @autoreleasepool {
        Fraction *myFrac1;
        //myFrac1 = [Fraction alloc];
        //myFrac1 = [myFrac1 init];
        myFrac1 = [[Fraction alloc] init];
        [myFrac1 setTo:2 over:3];
        [myFrac1 print];
        
        Fraction *myFrac2 = [Fraction new];
        [myFrac2 setTo:1 over:3];
        //覆寫set的方法 使得此變數不得為0
        [myFrac2 setDenominator:0];
        [myFrac2 print];
        Fraction *myFrac3;
        myFrac3 = [myFrac1 add:myFrac2];//加
        [myFrac3 print];
        myFrac3 = [myFrac1 Subtract:myFrac2];//減
        [myFrac3 print];
        myFrac3 = [myFrac1 Multiply:myFrac2];//乘
        [myFrac3 print];
        myFrac3 = [myFrac1 Divide:myFrac2];//除
        [myFrac3 print];
        
    }
    return 0;

}

十二、Demo

2014年6月19日 星期四

[Android]監聽 長按 事件

  先前介紹的OnClick()不須傳回任何值,但onLongClick() 必須一個布林值,表示是否引發「長按」事件,還是也要在之後手指放開時引發「按一下」事件。這是因為「長按」一定是包含在「按一下」的過程中,因此必須依靠傳回值,來告訴系統只要引發「長按」就好。

  一個用戶的操作會被傳遞到不同的前端物件的不同監聽方法處理,任何一個接收並處理了該次事件的方法如果在處理完後返回了 true,那麼該次 event 就算被完全處理了,其他的 View 或者監聽方法就不會再有機會處理該 event 了。


接續上一篇的內容:按一下 的事件處理範例

※下面得範例將要在長按按鈕後,將計數值歸0: MainActivity.java
package tw.mangolai.counter2;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
//匯入監聽器介面
import android.view.View.OnClickListener; 
//匯入監聽器介面
import android.view.View.OnLongClickListener; 
import android.widget.Button;
import android.widget.TextView;

//實作 OnLongClickListener介面
public class MainActivity extends Activity implements OnClickListener, OnLongClickListener { 
    TextView txv;  //用來參照 textView1 元件的變數
    Button btn;   //用來參照 button1 元件的變數
    int counter = 0; //用來儲存計數的值, 初值為 0

    @Override
    //實作監聽器介面中定義的 onClick方法
    public void onClick(View v) { // 實作監聽器介面中定義的 onClick方法
        // 將計數值加 1, 然後轉成字串顯示出來
        txv.setText(String.valueOf(++counter)+"顆鑽石"); 
    }

    @Override
    //實作長按 (OnLongClickListener 介面)的方法
    public boolean onLongClick(View v) { 
        counter = 0;
        txv.setText("0"+"顆鑽石");
        return true;
    }
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //找出要參照的物件
        txv = (TextView) findViewById(R.id.textView1); 
        //找出要參照的物件
        btn = (Button) findViewById(R.id.button1); 
        //登錄監聽物件, this表示活動物件本身
        btn.setOnClickListener(this); 
        //將活動物件登錄為按鈕的長按監聽器 
        btn.setOnLongClickListener(this); 
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }
}

[Android]按一下 的事件處理範例


 ※下面的範例是每按一下按鈕,就讓計數器加1:
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" >
    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/textView1"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="42dp"
        android:text="我就再回去看"
        android:textSize="60dp" />
    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="40dp"
        android:text="0顆鑽石"
        android:textSize="60dp" />
</RelativeLayout>

MainActivity.java
package tw.mangolai.counter;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
// 匯入監聽器介面
import android.view.View.OnClickListener; 
import android.widget.Button;
import android.widget.TextView;
// 實作 OnClickListener 介面
public class MainActivity extends Activity implements OnClickListener { 
    // 用來參照 textView1 元件的變數
    TextView txv;  
    // 用來參照 button1 元件的變數
    Button btn;   
    // 用來儲存計數的值, 初值為 0
    int counter = 0; 

    @Override
    // 實作監聽器介面中定義的 onClick 方法
    public void onClick(View v) { 
        // 將計數值加 1, 然後轉成字串顯示出來
        txv.setText(String.valueOf(++counter)+"顆鑽石"); 
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // 找出要參照的物件
        txv = (TextView) findViewById(R.id.textView1); 
        // 找出要參照的物件
        btn = (Button) findViewById(R.id.button1); 
        // 登錄監聽物件, this 表示活動物件本身
        btn.setOnClickListener(this); 
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }
}

[Android]事件處理


事件處理的機制

   當使用者對手機進行各種操作時,即會產生對應的事件(Event),例如按下按鈕時,會產生對應的 OnClick事件。
   若要處理任何事件,必須準備一個能處理事件的監聽物件(或稱監聽器,Listener),然後將之登錄到來源物件中,那麼當來源物件有事件發生時,就會自動呼叫相對應的監聽事件來進行處理。

 不懂嗎? 為了抓小偷,所以我們在家中裝了監視器,若沒有監視器監看,那就 沒~有~畫~面~



JAVA 的介面(Interface)


   在 Android中,是以 JAVA的介面(Interface)來規範事件處理的方法,簡單說就是凡是要成為某類事件的監聽物件時,就要需要提供符合其介面規定格式的方法。例:按一下(OnClick)的事件,對應規範就是OnClickListener界面,該介面必須要規定了監聽物件提供的 onClick() 方法的規格,我們必須要專寫 onClick() 的方法才能處理「按一下」的事件。

注意:這裡稱的面(Interface)跟使用者介面(User Interface)是不同的唷~~~


※下面的範例將介紹實作介面以及監聽器使用方法:

//這就是實作 監聽器Listener 唷~~~~~~
class MyOnClickListener implements OnClickListener{ 
    //這裡撰寫監聽物件的處理方法,就是按下按鈕後要做啥~
    public void onClick(View v){ 
        switch(v.getId()){
        //按鈕1 要做啥~
        case R.id.btn1: 
            textView1.setText("textview1");
            break;
        //按鈕2 要做啥~
        case R.id.btn2: 
            textView2.setText("textview2");
            break;
        }
    }
}
private MyOnClickListener myOnClickListener = new MyOnClickListener();

//登錄就是下面這兩行啦~~~~~
//this代表 目前的物件,也就是勿前執行的方法所屬的物件 
button1.setOnClickListener(this); 
//這裡寫myOnClickListener馬耶通~~~
button2.setOnClickListener(myOnClickListener); 
/*
為何這樣寫?
因為在同一個類別內無法實作同一個方法兩次唷~~~~~~
物件都可以用陣列的方式來達到大量控制唷~~~~~~
*/

實作 (Implement) 介面其實只是一種宣告而已,真正要做得是:

  1. 撰寫符合該介面的規格 (方法名稱、參數、傳回值)的方法(method) 
  2. 向來源物件登錄自己成為該事件的監聽物件


 不懂嗎? 人類想要看的見,上帝必須要實作"眼睛"。上帝忘記實作時,你就會看不見五顆鑽石!!!!!