2013年11月30日 星期六

使用 extends Activity , 建立 simple_list_item_2 (兩行顯示) 的 ListView

package com.example.gpsticker;

import java.util.ArrayList;
import java.util.HashMap;

import android.os.Bundle;
import android.app.Activity;
import android.app.ListActivity;
import android.view.Menu;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.Toast;
import android.widget.AdapterView.OnItemClickListener;

public class MainActivity extends Activity {
   
     ArrayList<HashMap<String,String>> list = new ArrayList<HashMap<String,String>>();
     private SimpleAdapter adapter;
     ListView listView01;
   
     private static final String[] mPlaces = new String[] {
     "台北市", "新北市", "台南市", "高雄市", "苗粟縣",
     "台北市", "新北市", "台南市", "高雄市", "苗粟縣",
     "台北市", "新北市", "台南市", "高雄市", "苗粟縣",
     "台北市", "新北市", "台南市", "高雄市", "苗粟縣",
     "台北市", "新北市", "台南市", "高雄市", "苗粟縣",
     "台北市", "新北市", "789", "cde", "abc"
     };
   
     private static final String[] mFoods = new String[] {
     "大餅包小餅", "蚵仔煎", "東山鴨頭", "臭豆腐", "潤餅",
     "豆花", "青蛙下蛋","豬血糕", "大腸包小腸", "鹹水雞",
     "烤香腸","車輪餅","珍珠奶茶","鹹酥雞","大熱狗",
     "炸雞排","山豬肉","花生冰","剉冰","水果冰",
     "包心粉圓","排骨酥","沙茶魷魚","章魚燒","度小月",
     "aaa","abc","bbb","bcd","123"
     };
   
     @Override
     public void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_main);
        
         listView01 = (ListView)findViewById(R.id.listView1);

         //把資料加入ArrayList中
         for(int i=0; i<mPlaces.length; i++){
             HashMap<String,String> item = new HashMap<String,String>();
             item.put( "food", mFoods[i]);
             item.put( "place",mPlaces[i] );
             list.add( item );
         }
       
         //新增SimpleAdapter
         adapter = new SimpleAdapter(
                     this,
                     list,
                     android.R.layout.simple_list_item_2,
                     new String[] { "food","place" },
                     new int[] { android.R.id.text1, android.R.id.text2 } );
       
         //ListActivity設定adapter
         listView01.setAdapter( adapter );
       
         //啟用按鍵過濾功能,這兩行資料都會進行過濾
         listView01.setTextFilterEnabled(true);
       
       
         // 为ListView设置列表项点击监听器
         listView01.setOnItemClickListener(new OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> parent, android.view.View view, int position, long id) {
            Toast.makeText(getApplicationContext(), "您点击的是:"+"第"+(position+1)+"项", Toast.LENGTH_SHORT).show();
            }
         });
   

     }
   
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }


}

結果會如下 , 分隔線左右會有留空 , ListView 週邊有留空 , 另有一個物件





如果改用 extends ListActivity ,
1.
// setContentView(R.layout.activity_main); // 這行關掉

2.
         //listView01.setAdapter( adapter );   
     setListAdapter( adapter );

3.
         //listView01.setTextFilterEnabled(true);
         getListView().setTextFilterEnabled(true);

4. (不知如何取得 Click , 整個先關掉)
//         listView01.setOnItemClickListener(new OnItemClickListener() {
//
//            @Override
//            public void onItemClick(AdapterView<?> parent, android.view.View view, int position, long id) {
//            Toast.makeText(getApplicationContext(), "您点击的是:"+"第"+(position+1)+"项", Toast.LENGTH_SHORT).show();
//            }
//         });

結果就會是滿版的 ,





2013年9月21日 星期六

對 String ( 內容為 xml 標籤結構 ) , 使用特定 Tag 標籤 , 截取 substring 標籤的值


    String MyStream = "
    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <TraExtendCar xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <Placemark>
            <SN>1</SN>
            <City>臺北市</City>
            <Area>南港區</Area>
            <Description>忠孝東路六段39號前(台電前)</Description>
            <Lat>25.04665</Lat>
            <Long>121.58366</Long>
            <Speed>50</Speed>
            <Extend>10</Extend>
            <Bearing>227</Bearing>
        </Placemark>
        <Placemark>
            <SN>2</SN>
            <City>臺北市</City>
            <Area>南港區</Area>
            <Description>忠孝東路六段188巷(東向西)</Description>
            <Lat>25.048832</Lat>
            <Long>121.587055</Long>
            <Speed>50</Speed>
            <Extend>10</Extend>
            <Bearing>255</Bearing>
        </Placemark>
            ";
// 以上 String 的建立 , 不是正確的 , 只是個方便看到內容的範例
   
    String Tag = "Description";
    String StartTag = "<" + Tag + ">";
    String EndTag = "</" + Tag + ">";
    int iStart = 0;
    int iEnd = 0;
    String strOut = "";
    iStart = MyStream.indexOf(StartTag)+StartTag.length();
    iEnd = MyStream.indexOf(EndTag);
    strOut = MyStream.substring(iStart, iEnd);










截取出 , 與 Tag 相同的標簽裡頭的 值 , 值會透過 substring 存於 strOut 裡
因來源應該是 xml 之類的文字檔 ,
值 的預設形態會是 String ,



以上不是 Bug Free , 還需要做 檢查 是否 標籤成對 的存在 ,
產生錯誤的測試為 , 使用不存在的標籤去跑程式 , 如
    String Tag = "Desc %$@ ription";

會產生 java.lang.NullPointerException 的錯誤









打上斷點(Toggle Line Breakpoint) , 透過 Debug 執行(Run下面那一個) ,
觀察 (x) = Variables ,
可見到 String indexOf 如果沒有找到 標籤 , 會回傳 -1 的值 ,





一個簡單的方法 , 用 try catch 包起來 ,
    try
    {
        String Tag = "Desc %$@ ription";
        String StartTag = "<" + Tag + ">";
        String EndTag = "</" + Tag + ">";
        int iStart = 0;
        int iEnd = 0;
        String strOut = "";
        iStart = MyStream.indexOf(StartTag)+StartTag.length();
        iEnd = MyStream.indexOf(EndTag);
        strOut = MyStream.substring(iStart, iEnd);
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

程式可以繼續往下走 , 不會報錯而中斷



純文字檔(xml為例) , 放置於 assets , 使用 AssetManager 讀取 , 輸出到 TextView

        TextView info_message = (TextView)findViewById(R.id.info_message);
AssetManager assetManager = getAssets();
    InputStream inputStream = null;
 
    String MyStream;
    try {
        // 指定/assets/MyAssets.txt
        inputStream = assetManager.open("trappoint.xml");
   
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        byte[] bytes = new byte[4096];
   
        int len;
        while ((len = inputStream.read(bytes)) > 0){
         byteArrayOutputStream.write(bytes, 0, len);
        }
   
        MyStream = new String(byteArrayOutputStream.toByteArray(), "UTF8");
       
        } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        MyStream = e.toString();
    }
 
    info_message.setText(MyStream);


使用  AssetManager , 將放置於 assets(資源管理匣) 的 trappoint.xml(各種檔案)
在此以 純文字檔 xml 為例
讀取 , 顯示於 名為 R.id.info_message 的 TextView



TextView 輸出結果


2013年5月2日 星期四

UIBarButton init 使用 SystemItem 以及 WithTitle

UIBarButton

兩種 alloc & init 的方法


第一種 , 使用 SystemItem
     UIBarButtonItem *saveButton = [[UIBarButtonItem alloc]
                                    initWithBarButtonSystemItem:UIBarButtonSystemItemDone
                                   target:self
                                   action:@selector(deleteAction:)];
    saveButton.style = UIBarButtonItemStyleBordered;




第二種 , 使用自定義文字
    UIBarButtonItem *saveButton = [[UIBarButtonItem alloc] initWithTitle:@"Recent" style:UIBarButtonItemStyleBordered target:self action:@selector(deleteAction)];
    saveButton.tag = 1;

2013年5月1日 星期三

TableViewCell ( with Custom ViewCell ) with Stroyboard



第一步
開啟 Storyboard
把 Cell 顯示的元件 透過 Storyboard 都給 拉一拉 , 把 outlet 擺設做好

第二步
新增一個 Class ,


在此我取這個 Class 的名稱為 ByTimeViewCell , 要選 繼承自(Subclass of) UITableViewCell


好了 , 上面兩個圖之後 , 就會產生出  Class ( 有 .h 也有 .m )






第三步 ,
於 ByTimeViewCell.h / .m 添加  outlet 物件的 @property / @synthesize

//  ByTimeViewCell.h
@property (nonatomic, weak) IBOutlet UILabel *firstLabel;
@property (nonatomic, weak) IBOutlet UILabel *secondLabel;
@property (nonatomic, weak) IBOutlet UILabel *thirdLabel;

//  ByTimeViewCell.m
@synthesize firstLabel;
@synthesize secondLabel;
@synthesize thirdLabel;




第四步
去到 Storyboard , 指派 ByTimeViewCell Class 給 Cell 物件
如果 這個 Custom Class 下拉選單 , 沒有出現 剛剛新增的 .h .m Class ,
請看一下 .h .m Class 應該是還沒儲存

如下圖 尚未儲存




如下圖 ( 當下檔案 Command+S 儲存快速鍵 )已經儲存


如果 .h .m 已經儲存 , 但 Class 還是沒有顯示 ,
可嘗試 關閉其他的 xcode Project 專案 , 只剩下 待解決的這個 Project ,
然後整個 xcode 關掉 重開 , Project 重開

再不行 , 還有一招 , 等下再講



第五步
去到 Storyboard 把 outlet 指派 Object
滑鼠指標移到最右邊的 圈圈 , 圈圈 裡頭會多個 + 號 , 然後按著
拉到 預覽可視版型的 物件上頭 再將滑鼠左鍵放開





第六步
去到 TableViewController.m
編輯 引用 .h
 #import "ByTimeViewCell.h"



第七步
去到
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
客制 ViewCell


當上方的框框改寫成如下
ByTimeViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

下方的框框
就可以以 . 帶出我們剛剛所新增的 三個 Label 物件
    cell.firstLabel.text = (NSString*)[dictionary objectForKey:@"StayTime"];
    cell.secondLabel.text = [NSString stringWithFormat:@"%02i:%02i", components.hour, components.minute];
    cell.thirdLabel.text = strDist;


這個 Function 第一行 CellIdentifier , ByTimeTableCell 自己命名
static NSString *CellIdentifier = @"ByTimeTableCell";
但需要與 Storyboard 裡頭 相同

如果不相同 , 編譯不會有 Warring , 也不會有 Error ,
情況會是 滑動 Cell 時 , 都是重新再畫 Cell , 比較耗用效能 , 因為沒有重複使用

如果 Storyboard 空白 , 編譯時會有 Warring , 也不會有 Error
但 , 執行起來 , Cell 會空空的 , 帶不出資料





 好了 , 這樣就把 Custom ViewCell 講完了


[EOF]










以各種 string Format 組合後 , 回傳 NSString * , 好用 !~


這個真是好用的參數 , 很符合我的胃口 , 我應該會很常使用到吧 !~

NSString * stRR = [NSString stringWithFormat:@"%@.html", title];

cell.secondLabel.text = [NSString stringWithFormat:@"%02i:%02i", components.hour, components.minute];
 

使用經緯度座標的兩點 歸納得出 KM/M 長度


三角形 斜邊公式 畢氏定理
一邊平方+二邊平方 開庚號 得 斜邊長度

一邊15,二邊15, 得 斜邊長度 21.21xxx 如下
 15,15=>21.21320343559643

依此定理,以經緯度作為一邊與二邊,嘗試歸納出 使用經緯度座標的兩點 KM/M 長度

diff
25.0346, 121.5496
25.0340, 121.5717
-----------------
6,221
36+48841
36,48841 = 開庚號 => 221.0814329607984
221.0814329607984 x 參數 = 2,251.78 M

經緯度距離,轉換成公尺 乘上此參數 x = 10.18529674719125

//////////////
Test A

25.0448, 121.5468
25.0308, 121.5658
-----------------
140,190
(19600+36100) = 開庚號 => 236.0084744241189
236.0084744241189 x 參數 = 2403.81634686154755 M
Result 參數得證


////////
Test B

25.0282, 121.5397
25.0437, 121.5655
-----------------
155, 258
(24025,66564) = 開庚號 => 300.9800657850948
300.9800657850948 x 參數 = 3065.57128501033451 M


-------------------- 分隔線 ---------
幾天之後 補充更新

Okay , 以上是 自己運算的方法 , 結果發現了 一個簡單的 iOS 內建 Function


        // 計算 trashPoint 與 user location 的直線距離
        CLLocation *loc = [[CLLocation alloc] initWithLatitude:fLatitude longitude:fLongitude];
        CLLocation *loc2 = [[CLLocation alloc] initWithLatitude:locationManager.location.coordinate.latitude longitude:locationManager.location.coordinate.longitude];
        CLLocationDistance dist = [loc distanceFromLocation:loc2];






PS. 兩個方法的誤差為 加減 7% 之間




ViewController Trigger !~


// ViewController Trigger !~
    [self.navigationController pushViewController:vc animated:YES];

2013年4月29日 星期一

自定義 DebugLog 包裝 NSLog , 透過 define DEBUG_MODE 切換

//#define DEBUG_MODE

#ifdef DEBUG_MODE
    #define DebugLog( s, ... ) NSLog( @"<%p %@:(%d)> %@", self, [[NSString stringWithUTF8String:__FILE__] lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] )
#else
    #define DebugLog( s, ... )
#endif

// 帶有 執行的.m 名稱 與行號 , 以及執行中的 self 記憶體位置

2013年4月28日 星期日

Apple Certification for 新的開發環境(MBA,MBP), 新的測試機(iPhone,iPad) & 新的App

Apple Certification for Dev Env, Device & App


環境狀況 ,

一台新的 開發  Xcode 環境 such as MacBook Pro , MacBook Air , etc.

一台新的 測試 App 環境 such as iPhone , iPad , etc. (待補充)

一個新的 App , such as any iOS App.


目標:在新的 開發環境上 , 透過 鑰匙圈存取 產生公用密鑰 & 專用密鑰

第一步 , 開啟 鑰匙圈存取.app




第二步 , 使用工具列選單





第三步 , 產生 此開發環境的 金鑰 , 儲存到 桌面上





第四步 , 開啟 App Dev Web Page ,

切換頁面到 iOS Certificates / Development


檢視 Certificates , 如上圖 , 可全部 Revoke 舊的 , 失效的 , 上一台 開發環境的 ,

新增 , 按右上角的 [ + ] , 就可以 Choice File from 桌面的 本文上段所產生的 金鑰 上傳 ,





第五步  , 依照網頁步驟 , 產生出 Certificates , 把 Certificates 下載 ,





第六步 , 下載的 ios_development.cer (剛剛在 App Dev 產生出來的) , 點兩下 , 新增到 開發環境的鑰匙圈存取 中 ,

應該呈現 附掛在 上面步驟產生的金鑰以下 , (此步驟之前,以下沒有附掛項目)





    以上的部分 , 新的開發環境 , MBA , MBP . 已經與 App Dev 交換過 金鑰 ,

    跳過的部分 , 測試環境 , iPhone , iPad , 以後再補充吧 , 暫略

    以下的部分 , 是 新建立一個 App , 也需要在 App Dev 上產生對應的 Code Sign ,




第七步 , 在這裡要想一下 , App ID , 如圖 ,

依照 [ + ] 按扭 之後的步驟 , 目標是 產出一個新的 iOS App IDs





第八步 ,  切換到 Provisioning Profiles , 目標是 產生出 App ID 的 Dev / Dist Certificate , 下載 for Xcode 使用

點 [ + ] , 依照步驟指示到完成 ,







第九步 , 產出要是 開發環境金鑰(Apr. 24 2014) , Active , 接著下載給 鑰匙圈存取 進行新增





第十步 , 點選兩下 剛下載的 ios_development.cer 在鑰匙圈存取 好像不會有什麼動靜 ,

第十一步 , 開啟 Xcode Organizer , Import , Refresh 按一按 ,

最終產出為 Valid profile ,





第十一步 , 按一按 Import , 使這個目錄也顯示為 Valid profile





第十二步 , 於 Xcode 專案 管理頁面 ,

選上對應的 Code Sign ,





  [ 完成 ]

iOS NSMutableArray 與 NSDictionary 產生, 新增, 變更, 列key值, 列舉, 排序


// NSMutableArray with NSDictionary
//    alloc init
//    alloc initWithObjectsAndKeys
//    產生 NSDictionary,且賦予 value,key(group的概念)

    NSMutableArray *MyArray = [[NSMutableArray alloc] init];
    NSDictionary *dictionary = [[NSDictionary alloc] initWithObjectsAndKeys:
                                @"G97013",@"SN",
                                @"WeiTing Chen", @"NAME",
                                @"1976/08/22", @"DATE",
                                @"文化大學", @"INFO",
                                nil];

//    將第一筆 NSDictionary 使用 addObject 掛到 (NSMutableArray*)MyArray
    [MyArray addObject:dictionary];
    NSLog(@" count = %i",MyArray.count);
   
//    產生第二筆 NSDictionary
    dictionary = [[NSDictionary alloc] initWithObjectsAndKeys:
                                @"G98015",@"SN",
                                @"Jessica Chen", @"NAME",
                                @"1978/04/09", @"DATE",
                                @"夫妻大學", @"INFO",
                                nil];
//    將第二筆 NSDictionary 使用 addObject 掛到 (NSMutableArray*)MyArray
    [MyArray addObject:dictionary];
    NSLog(@" count = %i",MyArray.count);   
   

//    產生第三筆 NSDictionary
    dictionary = [[NSDictionary alloc] initWithObjectsAndKeys:
                  @"85017",@"SN",
                  @"John", @"NAME",
                  @"1980/11/23", @"DATE",
                  @"info at objectgraph.com", @"INFO",
                  nil];
//    將第三筆 NSDictionary 使用 atIndexedSubscript 指定順序為 MyArray.count 掛到 (NSMutableArray*)MyArray
//    因 MyArray.count 尚未使用,此效果同等於 addObject(新增)
    [MyArray setObject:dictionary atIndexedSubscript:MyArray.count];
    NSLog(@" count = %i",MyArray.count);
       
//    透過 NSEnumerator 列舉在第三筆(當前筆,與前兩筆都是不同記憶體位置) NSDictionary 的 Key 名稱
//    key 的形態使用 id 即可(待瞭解)
    NSEnumerator *enumerator = [dictionary keyEnumerator];
    id key;
   
    while ((key = [enumerator nextObject])) {
        NSLog (@"Next key is: %@", key); 
    }

//    使用 for in 列舉第三筆 NSDictionary 的 value & key
    for (NSDictionary *dict in MyArray)
    {
        for (id key in dict) {
            NSLog(@"key: %@   value:%@", key, [dict objectForKey:key]);
        }
    }
    NSLog(@" ------------ ");
   

//    產生第四筆 NSDictionary
    dictionary = [[NSDictionary alloc] initWithObjectsAndKeys:
                  @"A85017",@"SN",
                  @"AJohn", @"NAME",
                  @"A1980/11/23", @"DATE",
                  @"Ainfo at objectgraph.com", @"INFO",
                  nil];
//    將第四筆 NSDictionary 使用 atIndexedSubscript 指定順序為 MyArray.count-2 掛到 (NSMutableArray*)MyArray
//    因 MyArray.count-2 已有被使用,此效果同等於 更新資料,實際為改變記憶體指向的位置
    [MyArray setObject:dictionary atIndexedSubscript:MyArray.count-2];
    NSLog(@" count = %i",MyArray.count);
   
//    列舉 MyArray 全貌,可與上此列舉比對內容變動
    for (NSDictionary *dict in MyArray)
    {
        for (id key in dict) {
            NSLog(@"key: %@   value:%@", key, [dict objectForKey:key]);
        }
    }
   
    NSLog(@" ------------ ");
  
//    再準備一筆資料
    dictionary = [[NSDictionary alloc] initWithObjectsAndKeys:
                  @"_85017",@"SN",
                  @"_John", @"NAME",
                  @"_1980/11/23", @"DATE",
                  @"_info at objectgraph.com", @"INFO",
                  nil];
//    新增掛於 MyArray 最後一筆
    [MyArray addObject:dictionary];
    NSLog(@" count = %i",MyArray.count);
   
//    列舉 MyArray 全貌
    for (NSDictionary *dict in MyArray)
    {
        for (id key in dict) {
            NSLog(@"key: %@   value:%@", key, [dict objectForKey:key]);
        }
    }
   
    NSLog(@" ------------ ");
  
//    透過 NSSortDescriptor , 表示出要以 NAME 這個 key 欄位排序
//    將 MyArray 透過排序條件,結果輸出到 sortedMyArray
    NSSortDescriptor *nameDescriptor = [[NSSortDescriptor alloc] initWithKey:@"NAME" ascending:YES selector:@selector(compare:)] ;
    NSArray *descriptors = [NSArray arrayWithObject:nameDescriptor];
    NSArray *sortedMyArray = [MyArray sortedArrayUsingDescriptors:descriptors];
    for (NSDictionary *dict in sortedMyArray)
    {
        for (id key in dict) {
            NSLog(@"key: %@   value:%@", key, [dict objectForKey:key]);
        }
    }
    NSLog(@" ------------ ");

iOS NSMutableArray 建立,新增一筆,列舉

// NSMutableArray
//    alloc    init
//    addObject
//    for each

    NSMutableArray *myArray = [[NSMutableArray alloc] init];
    [myArray addObject:@"First line"];
    [myArray addObject:@"Second line"];
    [myArray addObject:@"Third line"];
    [myArray addObject:@"Fourth line"];
    [myArray addObject:@"Fifth line"];
   
    for (NSString *line in myArray) {
        NSLog(@"line: %@", line);
    }