MediaPlayer 不支援多個音樂同時播放
SoundPool 音樂容量只允許10M
private MediaPlayer player;
1.從內部儲存空間播放
player.setDataSource("/mnt/sdcard/slashwater.aif");
無法播放aif
// player.setDataSource("/mnt/sdcard/morzart.mid");
player.prepare();
player.start();
2.從網路播放
3.從res/raw播放
寫程式就像學音樂一樣,只看樂譜不動手永遠無法演奏出美妙旋律。只演奏一遍也不可能立刻成為音樂家。 這部落格紀錄我的學習筆記,各位看倌若找不到需要的資料請見諒~~~ This blog records my study about Computer Science.
總網頁瀏覽量
2013年4月22日 星期一
Android一些理論筆記
Activity:
1.每個activity是一個螢幕
關於activity生命週期查閱lifecycle
2.activity有兩種宣告方式:
第一種透過XML設定檔宣告:
activity設定檔位於res/layout底下
一個xml相當於一個view容器
第二種自訂一個繼承View的類別
之後再MainActivity實體化並setContentView
MySelfeView mcv = new MySelfeView(this);
setContentView(mcv);//設定目前螢幕
Service元件
1.Service 沒有提供與用戶進行互動的展示層,Service是執行在後台的元件
Service通常由Activity或其他的Context物件來啟動
Service通常在Activity生命週期結束仍會運行
每個Service應該在AndroidMainifest.xm.進行宣告
2.
Service啟動方式有兩種:
第一透過startService(Intent)啟動。
透過startService(Intent)呼叫的service生命週期:跟Activity差不多
onCreate() onStart() onDestroy()
第二透過bindService方法啟動,然後Service會跟呼叫Service的物件(Context,就是Activity)綁住
當被綁定的Context被銷毀時 Service也會連帶停止執行
生命週期大致如下順序
onCreate() onBind() onUnbind() /onDestory()
Broadcast Receiver元件:
負責接收廣播訊息並對訊息做出反應的元件應用:當電池電量過低、或信號過低時 系統發廣播進行通知
Content Provider元件
Service
Service:
播歌、下載檔案、電池快耗盡通知、mail來電通知
Service通常會啟動另外一個thread處理較花時間的程序
Intent it = new Intent(this,MyService.class);
it.putExtra("Name", "Morzart");
startService(it);
2.新增class繼承extends Service
extends Service
3.
務必記得去Mainifest.xml
註冊Service不然是不會執行Service的
4.
override onStartCommand(Intent intent)。
//接收啟動Service的Activity Inent物件
//如果沒有特別事情,可以省略
public int onStartCommand(Intent intent, int flags, int startId) {
String name = intent.getStringExtra("Name");
Log.i("YYP",name);
//Toast.makeText(this, name, Toast.LENGTH_SHORT).show();
return super.onStartCommand(intent, flags, startId);
}
宣告
private Timer timer;
在onCreate(){
timer= new Timer();
ttimer.scheduel(new MyNotice(),10000);
}
//我們會發現當啟動Service之後會先onCreate 接著再執行onStartCommand
//接著宣告thread處理service要做的事情
//本例子是在state bar顯示通知
//使用者按下通知時候會跳到另一個頁面
private class MyNotice extends TimerTask{
public void run(){
NotificationManager mgr= (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
//notificationManager負責整個系統通知控制
//NotificationManager屬於系統管理類別因此要從getSystemService取得notification服務
@SuppressWarnings("deprecation")
Notification notice = new Notification(R.drawable.ic_launcher,"重要通知",System.currentTimeMillis());
//notification 物件此物件名稱是"重要通知"
//(顯示在state Bar的icon,顯示再狀態bar的文字,顯示的時戳)
//System.currentTimeMillis()取得現在時間
notice.flags=Notification.FLAG_AUTO_CANCEL;
//按一下service後notification會Service列表消失
// notice.flags=Notification.FLAG_FOREGROUND_SERVICE;
//Service為常駐狀態,常駐在service列表
// notice.flags=Notification.FLAG_ONLY_ALERT_ONCE;
//Service為常駐狀態,常駐在service列表
//flag表用來標記notification是何種類型任務
Intent it = new Intent(this,Page2.class);
//按下Service通知 進入page2
PendingIntent pit = PendingIntent.getActivity(this, 1, it, 0);
// PendingItent pit = PendingIntent.getActivities(context, requestCode, intents, flags);
//pending:即將發生的。
//顧名思義是宣告暫時存放的intent
//PendingIntent pit = PendingIntent.getBroadcast(this,1, it, 0);
//PendingIntent pit = PendingIntent.getService(this,1, it, 0);
notice.setLatestEventInfo(this, "重要訊息", "好好學習天天向上", pit);
//deprecated
//notice.setLatestEventInfo(context, contentTitle, contentText, contentIntent)
//當使用者點下該notification之後會去執行pit的intent
mgr.notify(1, notice);
//指定要顯示的notification物件以及識別ID
}
}
最後要停止Service,要宣告intent物件
再呼叫stopService()
private void toStop(){
Intent it = new Intent(this,MyService.class);
stopService(it);
//執行到這,會呼叫Serivce的onDestroy()
//雖然stop了 但是service仍會在service列表裡
}
二、廣播訊息、接收廣播訊息
在Service的.java檔
實作發送廣播訊息,以TimerTask實作之
timer.schedule(new MyTask(), 0,500);
private class MyTask extends TimerTask{
@Override
public void run() {
//Toast.makeText(this, "service start", Toast.LENGTH_SHORT).show();
//要Handler
int temp=(int)(Math.random()*49+1);
Intent it = new Intent("MyAction");
//Intent(String Action) 給intent貼標籤"MyAction"
it.putExtra("value", temp);//想要傳遞的東西放進去
sendBroadcast(it);//廣播出去由BroadcastReceiver接收
}
}
在MainActivity裡面:
實作接收訊息
宣告
private class MyReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context arg0, Intent intent) {
int value = intent.getIntExtra("value", -1);
//int value = intent.getIntExtra("", defaultValue)
tv.setText(""+value);
}
}
宣告:
private MyReceiver receiver;
receiver = new MyReceiver();
IntentFilter filter = new IntentFilter("MyAction");
//只接收"MyAction"的intent廣播
//IntentFilter filter = new IntentFilter("MyAction2");
//如果這裡改為"MyAction2"會收不到MyAction的intent廣播
registerReceiver(receiver,filter);
播歌、下載檔案、電池快耗盡通知、mail來電通知
Service通常會啟動另外一個thread處理較花時間的程序
一、Notification,通知服務的功能實作(有部分method是deprecation)
1.在MianActivity宣告intent並startServiceIntent it = new Intent(this,MyService.class);
it.putExtra("Name", "Morzart");
startService(it);
2.新增class繼承extends Service
extends Service
3.
務必記得去Mainifest.xml
註冊Service不然是不會執行Service的
4.
override onStartCommand(Intent intent)。
//接收啟動Service的Activity Inent物件
//如果沒有特別事情,可以省略
public int onStartCommand(Intent intent, int flags, int startId) {
String name = intent.getStringExtra("Name");
Log.i("YYP",name);
//Toast.makeText(this, name, Toast.LENGTH_SHORT).show();
return super.onStartCommand(intent, flags, startId);
}
宣告
private Timer timer;
在onCreate(){
timer= new Timer();
ttimer.scheduel(new MyNotice(),10000);
}
//我們會發現當啟動Service之後會先onCreate 接著再執行onStartCommand
//接著宣告thread處理service要做的事情
//本例子是在state bar顯示通知
//使用者按下通知時候會跳到另一個頁面
private class MyNotice extends TimerTask{
public void run(){
NotificationManager mgr= (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
//notificationManager負責整個系統通知控制
//NotificationManager屬於系統管理類別因此要從getSystemService取得notification服務
@SuppressWarnings("deprecation")
Notification notice = new Notification(R.drawable.ic_launcher,"重要通知",System.currentTimeMillis());
//notification 物件此物件名稱是"重要通知"
//(顯示在state Bar的icon,顯示再狀態bar的文字,顯示的時戳)
//System.currentTimeMillis()取得現在時間
notice.flags=Notification.FLAG_AUTO_CANCEL;
//按一下service後notification會Service列表消失
// notice.flags=Notification.FLAG_FOREGROUND_SERVICE;
//Service為常駐狀態,常駐在service列表
// notice.flags=Notification.FLAG_ONLY_ALERT_ONCE;
//Service為常駐狀態,常駐在service列表
//flag表用來標記notification是何種類型任務
Intent it = new Intent(this,Page2.class);
//按下Service通知 進入page2
PendingIntent pit = PendingIntent.getActivity(this, 1, it, 0);
// PendingItent pit = PendingIntent.getActivities(context, requestCode, intents, flags);
//pending:即將發生的。
//顧名思義是宣告暫時存放的intent
//PendingIntent pit = PendingIntent.getBroadcast(this,1, it, 0);
//PendingIntent pit = PendingIntent.getService(this,1, it, 0);
notice.setLatestEventInfo(this, "重要訊息", "好好學習天天向上", pit);
//deprecated
//notice.setLatestEventInfo(context, contentTitle, contentText, contentIntent)
//當使用者點下該notification之後會去執行pit的intent
mgr.notify(1, notice);
//指定要顯示的notification物件以及識別ID
}
}
最後要停止Service,要宣告intent物件
再呼叫stopService()
private void toStop(){
Intent it = new Intent(this,MyService.class);
stopService(it);
//執行到這,會呼叫Serivce的onDestroy()
//雖然stop了 但是service仍會在service列表裡
}
二、廣播訊息、接收廣播訊息
在Service的.java檔
實作發送廣播訊息,以TimerTask實作之
timer.schedule(new MyTask(), 0,500);
private class MyTask extends TimerTask{
@Override
public void run() {
//Toast.makeText(this, "service start", Toast.LENGTH_SHORT).show();
//要Handler
int temp=(int)(Math.random()*49+1);
Intent it = new Intent("MyAction");
//Intent(String Action) 給intent貼標籤"MyAction"
it.putExtra("value", temp);//想要傳遞的東西放進去
sendBroadcast(it);//廣播出去由BroadcastReceiver接收
}
}
在MainActivity裡面:
實作接收訊息
宣告
private class MyReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context arg0, Intent intent) {
int value = intent.getIntExtra("value", -1);
//int value = intent.getIntExtra("", defaultValue)
tv.setText(""+value);
}
}
宣告:
private MyReceiver receiver;
receiver = new MyReceiver();
IntentFilter filter = new IntentFilter("MyAction");
//只接收"MyAction"的intent廣播
//IntentFilter filter = new IntentFilter("MyAction2");
//如果這裡改為"MyAction2"會收不到MyAction的intent廣播
registerReceiver(receiver,filter);
2013年4月20日 星期六
簽名、手記製作
程式的目的:
將手機螢幕當作便條紙可以在上面畫圖。
圖構成的邏輯:
畫圖由多條線構成一張圖
而兩個以上的點構成一條線
實作:
1.宣告LinkedList 裡面存放多條線(多個HashMap物件)
2.宣告HashMap代表一個線條,HashMap存放線條的顏色、粗細,以及構成線條的座標
3.HashMap裡面其中一欄位存放LinkedList存放多個座標,每一個座標以HashMap姿態放進LinkedList中
(一條線由多個座標連起來所構成)
因此實作LinkedList為容器存放多個座標,
接著利用GestureDetector以及onTouchEvent onDraw onDown來實作將HashMap放進LinkedList
或者取出的動作啦
ScrollView:ScrollView也是layout一種,只限定vertical的方向。當scrollview裡面的元件超過螢幕顯示範圍,可以滾動方式取得元件。不可以放在LinearLayout之內。
自訂View:新增.java類別,類別必須繼承(extends View)。
且必須有建構式,本例子的建構式接收Context,AttributeSet
所謂Context就是指向parent對象的指標(或參考),受到parent控制
通常Context指向Activity
Context可以理解成程式(物件)所在的環境(狀態)
Context裡面存放Activity各式各樣的資訊
首先,準備好painel view
public class MainPanel extends View
在建構式宣告畫筆Paint
以及手勢偵測物件,告知gesturedetector所在context以及listener
在建構式外面宣告傾聽者類別繼承手勢傾聽者
new GestureDetector(context,MyListenter)
private void MyListener extends SimpleOnGestureListener{}
GestureListener要override OnDown 以及onScroll method
MainPanel(View) 要override onTouchEvent 以及onDraw method
範例程式:
public class MainPanel extends View {
private Paint p;// 畫筆
private GestureDetector gd;
private Context context;
private HashMap<String, Object> line;//
private LinkedList<HashMap<String, Object>> lines, redos;
private int size;// 筆畫粗細
private boolean isInit;
private boolean isDrawing;
public MainPanel(Context c, AttributeSet attrs) {
super(c, attrs);
context = c;// 從mainActivity來的?
//Log.i("context",context.toString());
//context指的是MainActivity@416a87d0
size = 10;
p = new Paint();
p.setColor(Color.MAGENTA);
p.setStrokeWidth(size);
gd = new GestureDetector(context, new MyListener());
// 手勢偵測物件,偵測碰觸螢幕的事件
setBackgroundColor(Color.TRANSPARENT);// View的顏色與parent一樣
}
private class MyListener extends SimpleOnGestureListener {
@Override
public boolean onDown(MotionEvent e) {
//onTouchEvent return gd.onTouchEvent(event)且action_down 會觸發這裡
//Log.i("Sing","onDown");
//onDown表示線條起點
float x = e.getX(), y = e.getY();
//手指碰到的座標
line.put("color", p.getColor());
line.put("size", (int)p.getStrokeWidth());
LinkedList<HashMap<String,Float>> lxy = new LinkedList();
HashMap<String,Float> xy = new HashMap();
xy.put("x", x);
xy.put("y", y);
lxy.add(xy);//HashMap放進Linklist
//將起始座標放入lxy[0]
line.put("line", lxy);//起始座標
// return super.onDown(e);
return true;
//retrun true會持續觸發touchevent 以及onScroll
}
// @Override
// public boolean onScroll(MotionEvent e1, MotionEvent e2,
// float distanceX, float distanceY) {
// Log.i("Sing","onScroll");
//
// return super.onScroll(e1, e2, distanceX, distanceY);
// }
}//GuestureDetector
//初始化
private void init(){
lines = new LinkedList<HashMap<String,Object>>();
redos= new LinkedList<HashMap<String,Object>>();
isDrawing = false;
isInit =true;
}
@Override
protected void onDraw(Canvas canvas) {
Log.i("Sing","onDraw");
super.onDraw(canvas);
if(!isInit) init();
//初始化,因為onDraw相當於View的main,
//但是有時會自動執行多次 所以就用init()初始化
//第一次進入這裡不會在View上畫出東西
//第一次進入畫面不會跑進foreachloop
for(HashMap<String,Object> line : lines){
// p.setColor(Color.BLACK);
// p.setStrokeWidth(3);
//所以這邊可以用條件判斷,當line裡面lxy的index符合某條件時
//更改線條顏色
p.setColor((Integer)line.get("color"));
//Log.i("Conan"," "+(Integer)line.get("color"));
p.setStrokeWidth((Integer)line.get("size"));
// Log.i("Conan"," "+(Integer)line.get("size"));
LinkedList<HashMap<String,Float>> lxy = (LinkedList)line.get("line");
//第一次treace程式碼:line存放兩個座標了
for(int i=1; i<lxy.size();i++){
HashMap<String,Float> xy0 = lxy.get(i-1);
//取得linkedlist 裡面物件 ,節點1
HashMap<String,Float> xy1 = lxy.get(i);
//節點2
canvas.drawLine(xy0.get("x"), xy0.get("y"), xy1.get("x"), xy1.get("y"), p);
// 畫線
}
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// Log.i("Sing","onTouchEvent");
if(!isDrawing){
//之前尚未開始畫圖,進入這裡進行初始化
//第二次treace:新增第二條線
line = new HashMap();
lines.add(line);//line是一條線,lines放多條線的LinkedList
//第二次trace到這,在lines[1]加上line HashMap物件
//還沒設定線條顏色與粗細
// Log.i("YYP", "" + lines.size());
//lines放n條線
isDrawing = true;
return gd.onTouchEvent(event);//第一次onTouchEvent後跳去onDown
}
else if(isDrawing && event.getAction()==MotionEvent.ACTION_UP)
{//正在畫圖 手指離開螢幕
isDrawing = false ;
return false;
}
else
{//isDrawing = true event.getAction()==MotionEvent.Action_Move
//正在畫圖
LinkedList<HashMap<String,Float>> lxy = (LinkedList)line.get("line");
//這裡的line跟onDwon的line是同一個
//第二次trace到這邊:line裡面已經有兩個座標,
HashMap<String,Float> xy = new HashMap();
xy.put("x", event.getX());//線的終點
xy.put("y", event.getY());
//第二次trace到這邊:增加第三座標
lxy.add(xy);
//第一次trace將座標放入lxy[1]
//第二次trace到這 ,座標放入lxy[2]
postInvalidate();//呼叫ondraw
return gd.onTouchEvent(event);
}
// String str=event.toString();
// Log.i("Sing",str);
// int action = event.getAction();
// cordinateX = (int) event.getX();
// cordinateY = (int) event.getY();
// switch (action) {
// // 按下那一刻的動作
// case MotionEvent.ACTION_DOWN:
// Log.v("Sing", "ACTION_DOWN");
// break;
// // 移動的動作
// case MotionEvent.ACTION_MOVE:
// Log.v("Sing", "ACTION_MOVE");
// break;
// // 抬起的動作
// case MotionEvent.ACTION_UP:
// Log.v("Sing", "ACTION_UP");
//// postInvalidate();//好像開啟另一條thread呼叫onDraw吧?
// break;
// }
// return super.onTouchEvent(event);
// return true;
}
}
以上完成之後,手指在螢幕上畫圖表示
將線條座標一一塞入LinkedList裡面。
開新檔案就是將LinkedList裡面的物件(線條、座標)清空
最快的方法重新new一個LinkedList物件,讓line指向新的物件
這樣就達到開新檔案了。
在MainPanel裡面宣告
void doInit(){
isInit=false;
postInvalidate;
//執行上面的onDraw
}
在MainActivity
宣告view變數
private MainPanel mp;
mp= (MainPanel)findViewById(R.id.mp);
//若沒寫這行會出現nullPointException
將mp.doInit();寫在btnOnClick事件裡。
void undo() {
//復原表示將LinkedList的元素逐一刪掉
if (!lines.isEmpty()) {
//lines.removeLast();
//
// lines裡面將線條移除
redos.add(lines.removeLast());
//刪掉的元素放進redo
postInvalidate();
}
}
void redo(){
if((redos!=null)&&(redos.size()>0)){
lines.add(redos.removeLast());
//將redo的東西重新放入lines
postInvalidate();
}
}
引用別人寫好的函式庫
1.
首先下載
android color picker
整個project程式碼
2. import android-color-picker
3.import之後在android-color-picker專案點右鍵,選properties
之後選擇"android" 之後將"is Libray"打勾 之後點apply並關閉視窗
4.回到原本project
在原本project點右鍵跟上面一樣選properties 選android
之後點add
將android-color-picker加入
這樣一來可以將自己/別人寫的code當作函式庫引用了
private void colorPicker(){
相關步驟以及整個code下載來源如下:
https://code.google.com/p/android-color-picker/
首先去mainifest.xml設定權限
android.permission.WRITE_EXTERNAL_STORAGE
允許程式可以將資料儲存到手機上面去
接著利用MainPanel extends View物件的setDrawingCacheEnabled(true)
mp.setDrawingCacheEnabled(true);
讓onDraw的資訊可以快取在記憶體
private void save(){}
FileOutputStream fout;
try{
fout = new FileOutputStream("/mnt/sdcard/name.png");
//指定輸出到內部儲存空間
Bitmap bmp = mp.getDrawingCache();
//Bitmap物件 接收快取記憶體裡的資料
bmp.compress(Compress.PNG,100,fout);
//輸出格式 輸出品質 輸出目的
fout.flush();
fout.close();
Toast.makeText(this, "saveOK", Toast.LENGTH_SHORT).show();
}catch(Exception e){
Log.i("Exception",e.toString());
}
SeekBar實作
private SeekBar seekbar;
seekbar = (SeekBar)findViewById(R.id.seekbar);
seekbar.setProgress(mp.getSize());
//設定seekbar初始值
seekbar.setMax(10);
//設定seekbar最大值
seekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener(){
@Override
public void onProgressChanged(SeekBar arg0, int progress, boolean fromUser) {
//progress:seekbar的值
mp.setSize(progress);
}
@Override
public void onStartTrackingTouch(SeekBar arg0) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}});
int getSize(){
return (int)p.getStrokeWidth();
}
void setSize(int size){
p.setStrokeWidth(size);
}
Application Node新增Activity
在Activity底下新增
intent filter將其他activity的intent filter刪掉
這樣可以依照自己意思指定起始畫面了
PS:
private Resource res;
res = getResources();//從Context取得Resource物件
//Resource物件可以在.java檔案取得該專案的xml資源設定值
Toast.makeText(this, res.getString(R.string.btn_save), Toast.LENGTH_SHORT).show();
//re.getString(R.string.btn_save); 印出string.xml中所對應的字串
去看values/string.xml有這樣標籤
<string name="btn_save">Save</string>
將手機螢幕當作便條紙可以在上面畫圖。
一、畫圖實作
圖構成的邏輯:
畫圖由多條線構成一張圖
而兩個以上的點構成一條線
實作:
1.宣告LinkedList 裡面存放多條線(多個HashMap物件)
2.宣告HashMap代表一個線條,HashMap存放線條的顏色、粗細,以及構成線條的座標
3.HashMap裡面其中一欄位存放LinkedList存放多個座標,每一個座標以HashMap姿態放進LinkedList中
(一條線由多個座標連起來所構成)
因此實作LinkedList為容器存放多個座標,
接著利用GestureDetector以及onTouchEvent onDraw onDown來實作將HashMap放進LinkedList
或者取出的動作啦
ScrollView:ScrollView也是layout一種,只限定vertical的方向。當scrollview裡面的元件超過螢幕顯示範圍,可以滾動方式取得元件。不可以放在LinearLayout之內。
自訂View:新增.java類別,類別必須繼承(extends View)。
且必須有建構式,本例子的建構式接收Context,AttributeSet
所謂Context就是指向parent對象的指標(或參考),受到parent控制
通常Context指向Activity
Context可以理解成程式(物件)所在的環境(狀態)
Context裡面存放Activity各式各樣的資訊
首先,準備好painel view
public class MainPanel extends View
在建構式宣告畫筆Paint
以及手勢偵測物件,告知gesturedetector所在context以及listener
在建構式外面宣告傾聽者類別繼承手勢傾聽者
new GestureDetector(context,MyListenter)
private void MyListener extends SimpleOnGestureListener{}
GestureListener要override OnDown 以及onScroll method
MainPanel(View) 要override onTouchEvent 以及onDraw method
範例程式:
public class MainPanel extends View {
private Paint p;// 畫筆
private GestureDetector gd;
private Context context;
private HashMap<String, Object> line;//
private LinkedList<HashMap<String, Object>> lines, redos;
private int size;// 筆畫粗細
private boolean isInit;
private boolean isDrawing;
public MainPanel(Context c, AttributeSet attrs) {
super(c, attrs);
context = c;// 從mainActivity來的?
//Log.i("context",context.toString());
//context指的是MainActivity@416a87d0
size = 10;
p = new Paint();
p.setColor(Color.MAGENTA);
p.setStrokeWidth(size);
gd = new GestureDetector(context, new MyListener());
// 手勢偵測物件,偵測碰觸螢幕的事件
setBackgroundColor(Color.TRANSPARENT);// View的顏色與parent一樣
}
private class MyListener extends SimpleOnGestureListener {
@Override
public boolean onDown(MotionEvent e) {
//onTouchEvent return gd.onTouchEvent(event)且action_down 會觸發這裡
//Log.i("Sing","onDown");
//onDown表示線條起點
float x = e.getX(), y = e.getY();
//手指碰到的座標
line.put("color", p.getColor());
line.put("size", (int)p.getStrokeWidth());
LinkedList<HashMap<String,Float>> lxy = new LinkedList();
HashMap<String,Float> xy = new HashMap();
xy.put("x", x);
xy.put("y", y);
lxy.add(xy);//HashMap放進Linklist
//將起始座標放入lxy[0]
line.put("line", lxy);//起始座標
// return super.onDown(e);
return true;
//retrun true會持續觸發touchevent 以及onScroll
}
// @Override
// public boolean onScroll(MotionEvent e1, MotionEvent e2,
// float distanceX, float distanceY) {
// Log.i("Sing","onScroll");
//
// return super.onScroll(e1, e2, distanceX, distanceY);
// }
}//GuestureDetector
//初始化
private void init(){
lines = new LinkedList<HashMap<String,Object>>();
redos= new LinkedList<HashMap<String,Object>>();
isDrawing = false;
isInit =true;
}
@Override
protected void onDraw(Canvas canvas) {
Log.i("Sing","onDraw");
super.onDraw(canvas);
if(!isInit) init();
//初始化,因為onDraw相當於View的main,
//但是有時會自動執行多次 所以就用init()初始化
//第一次進入這裡不會在View上畫出東西
//第一次進入畫面不會跑進foreachloop
for(HashMap<String,Object> line : lines){
// p.setColor(Color.BLACK);
// p.setStrokeWidth(3);
//所以這邊可以用條件判斷,當line裡面lxy的index符合某條件時
//更改線條顏色
p.setColor((Integer)line.get("color"));
//Log.i("Conan"," "+(Integer)line.get("color"));
p.setStrokeWidth((Integer)line.get("size"));
// Log.i("Conan"," "+(Integer)line.get("size"));
LinkedList<HashMap<String,Float>> lxy = (LinkedList)line.get("line");
//第一次treace程式碼:line存放兩個座標了
for(int i=1; i<lxy.size();i++){
HashMap<String,Float> xy0 = lxy.get(i-1);
//取得linkedlist 裡面物件 ,節點1
HashMap<String,Float> xy1 = lxy.get(i);
//節點2
canvas.drawLine(xy0.get("x"), xy0.get("y"), xy1.get("x"), xy1.get("y"), p);
// 畫線
}
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// Log.i("Sing","onTouchEvent");
if(!isDrawing){
//之前尚未開始畫圖,進入這裡進行初始化
//第二次treace:新增第二條線
line = new HashMap();
lines.add(line);//line是一條線,lines放多條線的LinkedList
//第二次trace到這,在lines[1]加上line HashMap物件
//還沒設定線條顏色與粗細
// Log.i("YYP", "" + lines.size());
//lines放n條線
isDrawing = true;
return gd.onTouchEvent(event);//第一次onTouchEvent後跳去onDown
}
else if(isDrawing && event.getAction()==MotionEvent.ACTION_UP)
{//正在畫圖 手指離開螢幕
isDrawing = false ;
return false;
}
else
{//isDrawing = true event.getAction()==MotionEvent.Action_Move
//正在畫圖
LinkedList<HashMap<String,Float>> lxy = (LinkedList)line.get("line");
//這裡的line跟onDwon的line是同一個
//第二次trace到這邊:line裡面已經有兩個座標,
HashMap<String,Float> xy = new HashMap();
xy.put("x", event.getX());//線的終點
xy.put("y", event.getY());
//第二次trace到這邊:增加第三座標
lxy.add(xy);
//第一次trace將座標放入lxy[1]
//第二次trace到這 ,座標放入lxy[2]
postInvalidate();//呼叫ondraw
return gd.onTouchEvent(event);
}
// String str=event.toString();
// Log.i("Sing",str);
// int action = event.getAction();
// cordinateX = (int) event.getX();
// cordinateY = (int) event.getY();
// switch (action) {
// // 按下那一刻的動作
// case MotionEvent.ACTION_DOWN:
// Log.v("Sing", "ACTION_DOWN");
// break;
// // 移動的動作
// case MotionEvent.ACTION_MOVE:
// Log.v("Sing", "ACTION_MOVE");
// break;
// // 抬起的動作
// case MotionEvent.ACTION_UP:
// Log.v("Sing", "ACTION_UP");
//// postInvalidate();//好像開啟另一條thread呼叫onDraw吧?
// break;
// }
// return super.onTouchEvent(event);
// return true;
}
}
二、開新檔案的功能:
以上完成之後,手指在螢幕上畫圖表示
將線條座標一一塞入LinkedList裡面。
開新檔案就是將LinkedList裡面的物件(線條、座標)清空
最快的方法重新new一個LinkedList物件,讓line指向新的物件
這樣就達到開新檔案了。
在MainPanel裡面宣告
void doInit(){
isInit=false;
postInvalidate;
//執行上面的onDraw
}
在MainActivity
宣告view變數
private MainPanel mp;
mp= (MainPanel)findViewById(R.id.mp);
//若沒寫這行會出現nullPointException
將mp.doInit();寫在btnOnClick事件裡。
三、復原、重做
以一個線條為單位復原重作。void undo() {
//復原表示將LinkedList的元素逐一刪掉
if (!lines.isEmpty()) {
//lines.removeLast();
//
// lines裡面將線條移除
redos.add(lines.removeLast());
//刪掉的元素放進redo
postInvalidate();
}
}
void redo(){
if((redos!=null)&&(redos.size()>0)){
lines.add(redos.removeLast());
//將redo的東西重新放入lines
postInvalidate();
}
}
四、自訂線條顏色(color picker實作)
取用別人寫好的code當作自己的函式庫libray引用別人寫好的函式庫
1.
首先下載
android color picker
整個project程式碼
2. import android-color-picker
3.import之後在android-color-picker專案點右鍵,選properties
之後選擇"android" 之後將"is Libray"打勾 之後點apply並關閉視窗
4.回到原本project
在原本project點右鍵跟上面一樣選properties 選android
之後點add
將android-color-picker加入
這樣一來可以將自己/別人寫的code當作函式庫引用了
private void colorPicker(){
// initialColor is the initially-selected color to be shown in the rectangle on the left of the arrow.
// for example, 0xff000000 is black, 0xff0000ff is blue. Please be aware of the initial 0xff which is the alpha. AmbilWarnaDialog dialog = new AmbilWarnaDialog(this,mp.getColor, new OnAmbilWarnaListener() { @Override public void onOk(AmbilWarnaDialog dialog, int color) { // color is the color selected by the user.
mp.setColor(color);
} @Override public void onCancel(AmbilWarnaDialog dialog) { // cancel was selected by the user } });}
相關步驟以及整個code下載來源如下:
https://code.google.com/p/android-color-picker/
五、儲存檔案
首先去mainifest.xml設定權限
android.permission.WRITE_EXTERNAL_STORAGE
允許程式可以將資料儲存到手機上面去
接著利用MainPanel extends View物件的setDrawingCacheEnabled(true)
mp.setDrawingCacheEnabled(true);
讓onDraw的資訊可以快取在記憶體
不寫這行,下面程式會出現NotFoundException之類的字眼
Bitmap物件在記憶體中抓取不到資料
private void save(){}
FileOutputStream fout;
try{
fout = new FileOutputStream("/mnt/sdcard/name.png");
//指定輸出到內部儲存空間
Bitmap bmp = mp.getDrawingCache();
//Bitmap物件 接收快取記憶體裡的資料
bmp.compress(Compress.PNG,100,fout);
//輸出格式 輸出品質 輸出目的
fout.flush();
fout.close();
Toast.makeText(this, "saveOK", Toast.LENGTH_SHORT).show();
}catch(Exception e){
Log.i("Exception",e.toString());
}
六、自訂線條大小
SeekBar實作
private SeekBar seekbar;
seekbar = (SeekBar)findViewById(R.id.seekbar);
seekbar.setProgress(mp.getSize());
//設定seekbar初始值
seekbar.setMax(10);
//設定seekbar最大值
seekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener(){
@Override
public void onProgressChanged(SeekBar arg0, int progress, boolean fromUser) {
//progress:seekbar的值
mp.setSize(progress);
}
@Override
public void onStartTrackingTouch(SeekBar arg0) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}});
int getSize(){
return (int)p.getStrokeWidth();
}
void setSize(int size){
p.setStrokeWidth(size);
}
七、自訂歡迎畫面
Application Node新增Activity
在Activity底下新增
intent filter將其他activity的intent filter刪掉
這樣可以依照自己意思指定起始畫面了
PS:
private Resource res;
res = getResources();//從Context取得Resource物件
//Resource物件可以在.java檔案取得該專案的xml資源設定值
Toast.makeText(this, res.getString(R.string.btn_save), Toast.LENGTH_SHORT).show();
//re.getString(R.string.btn_save); 印出string.xml中所對應的字串
去看values/string.xml有這樣標籤
<string name="btn_save">Save</string>
2013年4月18日 星期四
手機、平板電腦座標系統
將裝置橫放我們會發現有些裝置橫向(左右方向)的座標軸是x軸,有些是y軸
通常手機橫放的左右方向是y軸
共通點是Y軸方向是照相機鏡頭的方向
Private Display display;
display= getWindowManager().getDefaultDisplay()
display.getRotation();
當getRotation()為1時候表示使用手機
若為零表示使用平板電腦
通常手機橫放的左右方向是y軸
共通點是Y軸方向是照相機鏡頭的方向
Private Display display;
display= getWindowManager().getDefaultDisplay()
display.getRotation();
當getRotation()為1時候表示使用手機
若為零表示使用平板電腦
2013年4月15日 星期一
android自訂View觸控事件筆記
一、原始狀況:
自訂繼承View的類別。
override onTouchEvent與onDraw
執行程式會先跑onDraw
碰觸螢幕會觸發onTouchEvent事件
(onTouchEvent 回傳super.onTouchEvent(event)
二、
將onTouchEvent的retrun super.onTouchEvent(event);
改為return true
執行程式碰觸View會一直觸發onTouchEvent事件
onTouchEvent事件分成三種動作(action)
可以藉由event.getAction();
得知目前使用者的onTouchEvent事件的action
分別為Action_Down、Action_Move、Action_Up
第一個例子onTouchEvent只會偵測到Action_Down
如果onTouchEvent改為return true
則可以偵測到Action_Down、Action_Move、Action_UP
三、加上GuestureDetector手勢偵查物件
宣告GuestureDetector物件並宣告SimpleOnGestureListener子類別,
override onDown 與Scroll 與Fling
private GestureDetector gd;
gd = new GestureDetector(context,MyListener());
//context是指activity要看view放在哪個activity,MyListener是傾聽者
private class MyListener extends SimpleOnGestureListener{
//宣告傾聽者 繼承自SimpleOnGestureListener
@Override
public boolean onDown(MotionEvent e) {
Log.i("Sing","onDown");
return super.onDown(e);
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
Log.i("Sing","onScroll");
return super.onScroll(e1, e2, distanceX, distanceY);
}
}
1.
將onTouchEvent傳回值
改成gd.onTouchEvent(event)
//GestureDetector偵測有沒有發生onTouchEvent事件
執行程式會執行onDraw
按下螢幕會執行onTouchEvent
緊接著執行onDown。
因為GestureDetector偵測到onTouchEvent觸發onDown
2.承上
將onDown的return super.onDown(e);改為return true;
再執行程式
按下螢幕(不滑動)會發現
程式會先onTouchEvent之後onDwon接著就是連續執行onToucheEvent
而沒有執行onDown
由此可知道
當onTouchEvent 的 action 為down時候
會觸發Listener 的ondown
如果手指在螢幕上滑動一段距離
會交錯著先觸發onTouchEvent之後觸發onScroll
onDraw → onTouchEvent→ onDown → onTouchEvent→ onScroll →onTouchEvent→ onScroll
3.若沒加上postInvalidate()是不會再呼叫onDraw的
自訂繼承View的類別。
override onTouchEvent與onDraw
執行程式會先跑onDraw
碰觸螢幕會觸發onTouchEvent事件
(onTouchEvent 回傳super.onTouchEvent(event)
二、
將onTouchEvent的retrun super.onTouchEvent(event);
改為return true
執行程式碰觸View會一直觸發onTouchEvent事件
onTouchEvent事件分成三種動作(action)
可以藉由event.getAction();
得知目前使用者的onTouchEvent事件的action
分別為Action_Down、Action_Move、Action_Up
第一個例子onTouchEvent只會偵測到Action_Down
如果onTouchEvent改為return true
則可以偵測到Action_Down、Action_Move、Action_UP
三、加上GuestureDetector手勢偵查物件
宣告GuestureDetector物件並宣告SimpleOnGestureListener子類別,
override onDown 與Scroll 與Fling
private GestureDetector gd;
gd = new GestureDetector(context,MyListener());
//context是指activity要看view放在哪個activity,MyListener是傾聽者
private class MyListener extends SimpleOnGestureListener{
//宣告傾聽者 繼承自SimpleOnGestureListener
@Override
public boolean onDown(MotionEvent e) {
Log.i("Sing","onDown");
return super.onDown(e);
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
Log.i("Sing","onScroll");
return super.onScroll(e1, e2, distanceX, distanceY);
}
}
1.
將onTouchEvent傳回值
改成gd.onTouchEvent(event)
//GestureDetector偵測有沒有發生onTouchEvent事件
執行程式會執行onDraw
按下螢幕會執行onTouchEvent
緊接著執行onDown。
因為GestureDetector偵測到onTouchEvent觸發onDown
2.承上
將onDown的return super.onDown(e);改為return true;
再執行程式
按下螢幕(不滑動)會發現
程式會先onTouchEvent之後onDwon接著就是連續執行onToucheEvent
而沒有執行onDown
由此可知道
當onTouchEvent 的 action 為down時候
會觸發Listener 的ondown
如果手指在螢幕上滑動一段距離
會交錯著先觸發onTouchEvent之後觸發onScroll
onDraw → onTouchEvent→ onDown → onTouchEvent→ onScroll →onTouchEvent→ onScroll
3.若沒加上postInvalidate()是不會再呼叫onDraw的
2013年4月14日 星期日
SensorManager
SensorManager是手機平板電腦特有的功能
本文先說明加速度感測器:
加速度感測器顯示手機受到加速度的方向
分成X Y Z三個方向
將手機平躺著那麼X 與Y加速度趨近於零
Z加速度為9.8m/s^2
如果將手機直立Y加速度為9.8m/s^2
將手機橫立X軸加速度為9..8m/s^2
只是單純旋轉手機,不出力那麼所受的合力為9.8m/s^2
public class MainActivity extends Activity {
private SensorManager mgr;
private TextView info;
private Sensor sensor;
private MyListener listener;
private int nowz = -500, nowx, initx;
private float maxx;
private boolean isPull;
private int iscast = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
info = (TextView) findViewById(R.id.info);
mgr = (SensorManager) getSystemService(SENSOR_SERVICE);
List<Sensor> list = mgr.getSensorList(Sensor.TYPE_ALL);
// for (Sensor sensor: list){
// info.append(sensor.getName() + ":" +
// sensor.getMaximumRange() + ":" +
// sensor.getResolution() + "\n"
// );
// }
//
sensor = mgr.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
//
// sensor = mgr.getDefaultSensor(Sensor.TYPE_ORIENTATION);
// sensor = mgr.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION);
// sensor = mgr.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
// sensor = mgr.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR);
listener = new MyListener();
}
@Override
protected void onResume() {
super.onResume();
mgr.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_NORMAL);
}
@Override
protected void onPause() {
super.onPause();
mgr.unregisterListener(listener);
}
private class MyListener implements SensorEventListener {
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// TODO Auto-generated method stub
}
@Override
public void onSensorChanged(SensorEvent event) {
float[] data = event.values;
float x = data[0] * 10, z = data[2] * 100;
// info.setText(data[0]+"\n"+data[2]);
if (z < nowz) {
if (iscast == 0) {
Log.i("log", "以拉釣竿");
nowz = 990;
iscast = 1;
}
}
if (z > nowz) {
if (iscast == 1) {
if (x < 0) {
maxx = (Math.abs(1-x/10))*5;
Log.i("log", "z"+z + " x"+x);
info.setText("" + maxx);
iscast = 3;
}
}
maxx = 0;
initx = -20;
nowz = -500;
}
// if (z < nowz) {
// nowz = (int) z * 10;
// initx = (int) x;
// isPull = true;
// } else {
// isPull = false;
// if (x < initx) {
// int dx = (int) (Math.abs(x - initx));
// if (dx > maxx) {
// maxx = dx;
// info.setText("Power:" + maxx);
// }
// } else {
// nowz = 999;
// maxx = 0;
// }
// }
}}}
SensorManager.getOrientation();
本文先說明加速度感測器:
加速度感測器顯示手機受到加速度的方向
分成X Y Z三個方向
將手機平躺著那麼X 與Y加速度趨近於零
Z加速度為9.8m/s^2
如果將手機直立Y加速度為9.8m/s^2
將手機橫立X軸加速度為9..8m/s^2
只是單純旋轉手機,不出力那麼所受的合力為9.8m/s^2
public class MainActivity extends Activity {
private SensorManager mgr;
private TextView info;
private Sensor sensor;
private MyListener listener;
private int nowz = -500, nowx, initx;
private float maxx;
private boolean isPull;
private int iscast = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
info = (TextView) findViewById(R.id.info);
mgr = (SensorManager) getSystemService(SENSOR_SERVICE);
List<Sensor> list = mgr.getSensorList(Sensor.TYPE_ALL);
// for (Sensor sensor: list){
// info.append(sensor.getName() + ":" +
// sensor.getMaximumRange() + ":" +
// sensor.getResolution() + "\n"
// );
// }
//
sensor = mgr.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
//
// sensor = mgr.getDefaultSensor(Sensor.TYPE_ORIENTATION);
// sensor = mgr.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION);
// sensor = mgr.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
// sensor = mgr.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR);
listener = new MyListener();
}
@Override
protected void onResume() {
super.onResume();
mgr.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_NORMAL);
}
@Override
protected void onPause() {
super.onPause();
mgr.unregisterListener(listener);
}
private class MyListener implements SensorEventListener {
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// TODO Auto-generated method stub
}
@Override
public void onSensorChanged(SensorEvent event) {
float[] data = event.values;
float x = data[0] * 10, z = data[2] * 100;
// info.setText(data[0]+"\n"+data[2]);
if (z < nowz) {
if (iscast == 0) {
Log.i("log", "以拉釣竿");
nowz = 990;
iscast = 1;
}
}
if (z > nowz) {
if (iscast == 1) {
if (x < 0) {
maxx = (Math.abs(1-x/10))*5;
Log.i("log", "z"+z + " x"+x);
info.setText("" + maxx);
iscast = 3;
}
}
maxx = 0;
initx = -20;
nowz = -500;
}
// if (z < nowz) {
// nowz = (int) z * 10;
// initx = (int) x;
// isPull = true;
// } else {
// isPull = false;
// if (x < initx) {
// int dx = (int) (Math.abs(x - initx));
// if (dx > maxx) {
// maxx = dx;
// info.setText("Power:" + maxx);
// }
// } else {
// nowz = 999;
// maxx = 0;
// }
// }
}}}
SensorManager.getOrientation();
Dialog(AlertDialog,ProgressDialog,自訂dialog,自訂Toast,View)
本文是AlertDialgo的實作
基本上當作SOP處理
記得實作AlertDialog基本架構
AlertDialog是一個類別,裡面包住Builder類別
AlertDialog是Dialog子類別。
本例子
全都用Button來觸動showDialog method
首先在Activity宣告AlertDialog的物件。
private AlertDialog alert;
一、true與false對話框:
private void showDialog1(){
AlertDialog.Builder builder = new AlertDialog.Builder(this);
//宣告AlertDialog裡的Builder物件
////this 是指Activity也就是對話框顯示所在的Activity,this為context型態
builder.setTitle("這是對話框標題");
builder.setMessage("這是對話框內容。是否刪除資料?");
builder.setCancelable(false);
//設定鎖住返回鍵,false表示禁止按下返回鍵,只能按"確定"與"取消"
//alertDidalog的"確認"按鈕,傳遞參數,按鈕的內容以及註冊傾聽者。實作傾聽者匿名內部類別。
builder.setPositiveButton("是", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(MainActivity.this,"資料已刪除",Toast.LENGTH_SHORT).show();
//由於Toast包在內部類別裡面所以this前面要加上MainActivity
//記得要加上show()
}
});
//alertDidalog的"取消"按鈕,其餘同上
builder.setNegativeButton("否", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(MainActivity.this, "取消刪除", Toast.LENGTH_SHORT).show();
}
});
//最後務必記得要create() 跟show()
alert=builder.create();//create傳回Builder型態
alert.show();//.show() 傳回Dialog型態
}
private void showDialog2(){
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("選擇一個喜歡的項目吧");
builder.setCancelable(true);
builder.setItems(items,new DialogInterface.OnClickListener() {
//傳入字串陣列items
@Override
public void onClick(DialogInterface dialog, int which) {
//which表示使用者所點選的項目
Toast.makeText(MainActivity.this, "你選擇了"+items[which], Toast.LENGTH_SHORT).show();
}
});
alert=builder.create();
alert.show();
}
基本上當作SOP處理
記得實作AlertDialog基本架構
AlertDialog是一個類別,裡面包住Builder類別
AlertDialog是Dialog子類別。
本例子
全都用Button來觸動showDialog method
首先在Activity宣告AlertDialog的物件。
private AlertDialog alert;
一、true與false對話框:
private void showDialog1(){
AlertDialog.Builder builder = new AlertDialog.Builder(this);
//宣告AlertDialog裡的Builder物件
////this 是指Activity也就是對話框顯示所在的Activity,this為context型態
builder.setMessage("這是對話框內容。是否刪除資料?");
builder.setCancelable(false);
//設定鎖住返回鍵,false表示禁止按下返回鍵,只能按"確定"與"取消"
//alertDidalog的"確認"按鈕,傳遞參數,按鈕的內容以及註冊傾聽者。實作傾聽者匿名內部類別。
builder.setPositiveButton("是", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(MainActivity.this,"資料已刪除",Toast.LENGTH_SHORT).show();
//由於Toast包在內部類別裡面所以this前面要加上MainActivity
//記得要加上show()
}
});
//alertDidalog的"取消"按鈕,其餘同上
builder.setNegativeButton("否", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(MainActivity.this, "取消刪除", Toast.LENGTH_SHORT).show();
}
});
//最後務必記得要create() 跟show()
alert=builder.create();//create傳回Builder型態
alert.show();//.show() 傳回Dialog型態
}
二、列表式(list)對話框:按下button顯示多個項目,點其中一個項目,告知使用者所選的項目。
核心method :setItems(CharSequence[],DialogInterface.OnClickListener);
String items={"香蕉","芭樂","手榴彈","書"};
String items={"香蕉","芭樂","手榴彈","書"};
private void showDialog2(){
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("選擇一個喜歡的項目吧");
builder.setCancelable(true);
builder.setItems(items,new DialogInterface.OnClickListener() {
//傳入字串陣列items
@Override
public void onClick(DialogInterface dialog, int which) {
//which表示使用者所點選的項目
Toast.makeText(MainActivity.this, "你選擇了"+items[which], Toast.LENGTH_SHORT).show();
}
});
alert=builder.create();
alert.show();
}
三、自訂對話框:利用xml自訂對話框,與Dialog物件結合。Dialog是AlertDialog父類別。
private Dialog dialog;
private void showDialog3(){
dialog = new Dialog(this);
//對話框物件,this是context物件,表示對話框所在activity
dialog.setContentView(R.layout.newreg);//配接對話框
dialog.setTitle("註冊新帳號");
Button ok , cancel;
// ok=(Button)findViewById(R.id.ok);
//必須指定是哪個Activity、Dialog在findViewById,否則會出現NullPointerException,找不到對應物件。
ok = (Button)dialog.findViewById(R.id.ok);
//使用dialog下的findviewbyid
cancel = (Button)dialog.findViewById(R.id.cancel);
username = (EditText)dialog.findViewById(R.id.username);
passwd = (EditText)dialog.findViewById(R.id.passwd);
ok.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
String uname = username.getText().toString();
String password=passwd.getText().toString();
Toast.makeText(MainActivity.this, uname+":"+password, Toast.LENGTH_SHORT).show();
dialog.dismiss();//解散(關閉)對話框
}});
cancel.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "cancel", Toast.LENGTH_SHORT)
.show();
dialog.dismiss();
}});
dialog.show();//別忘了要show()
}
private Dialog dialog;
private void showDialog3(){
dialog = new Dialog(this);
//對話框物件,this是context物件,表示對話框所在activity
dialog.setContentView(R.layout.newreg);//配接對話框
dialog.setTitle("註冊新帳號");
Button ok , cancel;
// ok=(Button)findViewById(R.id.ok);
//必須指定是哪個Activity、Dialog在findViewById,否則會出現NullPointerException,找不到對應物件。
ok = (Button)dialog.findViewById(R.id.ok);
//使用dialog下的findviewbyid
cancel = (Button)dialog.findViewById(R.id.cancel);
username = (EditText)dialog.findViewById(R.id.username);
passwd = (EditText)dialog.findViewById(R.id.passwd);
ok.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
String uname = username.getText().toString();
String password=passwd.getText().toString();
Toast.makeText(MainActivity.this, uname+":"+password, Toast.LENGTH_SHORT).show();
dialog.dismiss();//解散(關閉)對話框
}});
cancel.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "cancel", Toast.LENGTH_SHORT)
.show();
dialog.dismiss();
}});
dialog.show();//別忘了要show()
}
四、ProgressDialog:
實作下載檔案時常會出現的對話框
宣告ProgressDialog物件
利用執行緒計算count、Handler處理長條bar的運作
private ProgressDialog progress;
private MyHandler handler = new MyHandler();
//private Handler handler;
//打錯,造成NullPointerException
private void showDialog4(){
progress = new ProgressDialog(this);
progress.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
//progress.setProgressStyle(ProgressDialog.STYLE_SPINNER);
//Spinner表示畫圓圈,Horizontal表示長條bar
progress.setCancelable(false);
progress.setMessage("Loading.....");
progress.setMax(123);//長條bar最大長度
new MyThread().start();
progress.show();
}
private class MyThread extends Thread{
@Override
public void run() {
for(int i=0;i<=123;i++){
//改成i+=2 長條bar只會跑到122就停止
handler.sendEmptyMessage(i);
//忘了打這行造成,progressDialog只開啟視窗卻沒有跑
//progress.setProgress(i);
//其實可以直接在thread處理也有同樣效果,但忘了為何在Handler處理會比較好
try {
Thread.sleep(60);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
progress.dismiss();
}
}
private class MyHandler extends Handler{
@Override
public void handleMessage(Message msg)
{
progress.setProgress(msg.what);//傳入參數設定長條bar的值
if(msg.what==progress.getMax()){
progress.dismiss();
}
}
}
五、自訂View並將View鑲嵌進Toast,變成自訂Toast
利用context提供的method getLayoutInflater建立自訂view
LayoutIflater inflater= getLayoutInflater()
private void showMyToast(int status , String info){
LayoutInflater inflater = getLayoutInflater();
//Activity的method
//將自己設計的layout轉成View
View layout = inflater.inflate(R.layout.mytoast, (ViewGroup)findViewById(R.id.root));
//R.id.root是xml中layout的id
//將xml檔mytoast裡面的ViewGroup(Layout及其元件)轉成View
//setContentView(layoutID)會直接將layout貼上畫面
ImageView img = (ImageView)layout.findViewById(R.id.img);
TextView msg= (TextView)layout.findViewById(R.id.msg);
//注意Img跟msg是屬於變數layout裡面的
//所以是layout之中findview,不是MainActivity findview
switch(status){
case 1:
img.setImageResource(R.drawable.warning);
break;
case 2:
img.setImageResource(R.drawable.warning);
break;
default:
img.setImageResource(R.drawable.warning);
break;
}
msg.setText(info);
//TextView mag秀出文字
Toast toast = new Toast(this);
toast.setView(layout);//將自訂view放入toast
toast.setGravity(Gravity.CENTER_VERTICAL, 0, 100);
//(,xoffset,yoffset)
//設置toast的位置
toast.setDuration(Toast.LENGTH_SHORT);
toast.show();
}
六、另一種自訂View
另一種自訂View是將java鑲嵌到layout檔案
在java檔案中寫class繼承view
在layout寫
<com.example.signature.MainPanel
/>
實作下載檔案時常會出現的對話框
宣告ProgressDialog物件
利用執行緒計算count、Handler處理長條bar的運作
private ProgressDialog progress;
private MyHandler handler = new MyHandler();
//private Handler handler;
//打錯,造成NullPointerException
//記得要new MyHandler();否則也會造成NullPointerException
private void showDialog4(){
progress = new ProgressDialog(this);
progress.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
//progress.setProgressStyle(ProgressDialog.STYLE_SPINNER);
//Spinner表示畫圓圈,Horizontal表示長條bar
progress.setCancelable(false);
progress.setMessage("Loading.....");
progress.setMax(123);//長條bar最大長度
new MyThread().start();
progress.show();
}
private class MyThread extends Thread{
@Override
public void run() {
for(int i=0;i<=123;i++){
//改成i+=2 長條bar只會跑到122就停止
handler.sendEmptyMessage(i);
//忘了打這行造成,progressDialog只開啟視窗卻沒有跑
//progress.setProgress(i);
//其實可以直接在thread處理也有同樣效果,但忘了為何在Handler處理會比較好
try {
Thread.sleep(60);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
progress.dismiss();
}
}
private class MyHandler extends Handler{
@Override
public void handleMessage(Message msg)
{
progress.setProgress(msg.what);//傳入參數設定長條bar的值
if(msg.what==progress.getMax()){
progress.dismiss();
}
}
}
五、自訂View並將View鑲嵌進Toast,變成自訂Toast
利用context提供的method getLayoutInflater建立自訂view
LayoutIflater inflater= getLayoutInflater()
private void showMyToast(int status , String info){
LayoutInflater inflater = getLayoutInflater();
//Activity的method
//將自己設計的layout轉成View
View layout = inflater.inflate(R.layout.mytoast, (ViewGroup)findViewById(R.id.root));
//R.id.root是xml中layout的id
//將xml檔mytoast裡面的ViewGroup(Layout及其元件)轉成View
//setContentView(layoutID)會直接將layout貼上畫面
ImageView img = (ImageView)layout.findViewById(R.id.img);
TextView msg= (TextView)layout.findViewById(R.id.msg);
//注意Img跟msg是屬於變數layout裡面的
//所以是layout之中findview,不是MainActivity findview
switch(status){
case 1:
img.setImageResource(R.drawable.warning);
break;
case 2:
img.setImageResource(R.drawable.warning);
break;
default:
img.setImageResource(R.drawable.warning);
break;
}
msg.setText(info);
//TextView mag秀出文字
Toast toast = new Toast(this);
toast.setView(layout);//將自訂view放入toast
toast.setGravity(Gravity.CENTER_VERTICAL, 0, 100);
//(,xoffset,yoffset)
//設置toast的位置
toast.setDuration(Toast.LENGTH_SHORT);
toast.show();
}
六、另一種自訂View
另一種自訂View是將java鑲嵌到layout檔案
在java檔案中寫class繼承view
在layout寫
<com.example.signature.MainPanel
/>
2013年4月11日 星期四
android 資料儲存data storage
SharedPreference:
儲存基本型態的資料
如果應用程式使用的資料量不大
那麼可以考慮用SharedPreference
應用:
遊戲的紀錄
聲音開與關
等程式相關狀態
用SharedPreference創立的資料只限於該應用程式使用
當然可以在getSharedPreferences設定公開檔案給其他應用程式使用
SharedPreferences sp = getSharedPreferences("YYP.dat",MODE_PRIVATE);
以XML格式將資料存放到/data/data/com.example.fishingmapmaker/shared_prefs/之下
如果在實體手機操作那麼
/data必須是root權限才可以讀取
public class MainActivity extends Activity {
private Button click1, click2, click3;
private TextView tv, tv2, tv3;
private EditText iodata1, iodata3;
private SharedPreferences sp;
//宣告sharedpreference物件
private SharedPreferences.Editor editor;
//宣告sharedpreference編輯器
private String username;
private int stage;
private boolean sound;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sp = getSharedPreferences("YYPdata", MODE_PRIVATE);
//getSharedPreferences是context裡面的method
//建立sharedpreference儲存資料的檔案 並宣告存取權限為只限於本程式閱讀
editor= sp.edit();
//調出sharedpreference編輯器
click1 = (Button)findViewById(R.id.click1);
tv = (TextView)findViewById(R.id.tv);
click2 = (Button)findViewById(R.id.click2);
tv2 = (TextView)findViewById(R.id.tv2);
iodata1 = (EditText)findViewById(R.id.iodata1);
click3 = (Button)findViewById(R.id.click3);
tv3 = (TextView)findViewById(R.id.tv3);
iodata3 = (EditText)findViewById(R.id.iodata3);
click1.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View arg0) {
savePreference();
}
});
readPreference();
click2.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
saveInnerData();
}
});
readInnerData();
click3.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
saveSDData();
}
});
readSDData();
}
private void savePreference(){
editor.putBoolean("sound", false);//每個資料型態都有對應的method
editor.putString("username", "Brad");//存進檔案
editor.putInt("stage", 118);
editor.commit();//務必要寫這行,才會將資料存進檔案
readPreference();
}
private void readPreference(){
username = sp.getString("username", "nobody");//讀取sharedpreference的儲存內容
stage=sp.getInt("stage", 0);
sound=sp.getBoolean("sound", true);
tv.setText("UserName: " + username + "\n" +
"Sound: " + (sound?"On":"Off") + "\n" +
"Stage: " + stage);
}
private void saveInnerData(){
String data = iodata1.getText().toString();//EditView的輸入文字記得要在末端加上toString(),因為getText()是View型態
try{
FileOutputStream fout
FileOutputStream fout = openFileOutput("YYP.dat",MODE_PRIVATE);
FileOutputStream fout= new FileOutputStream("YYP.dat");//錯誤寫法 filenotfound
//在純翠java 會預設純到專案跟目錄
fout.write(data.getBytes());//因為檔案皆為字串所以要將字串型別轉成byte型式
fout.flush();
fout.close();
Toast.makeText(this, "save OK", Toast.LENGTH_SHORT).show();
readInnerData();
}catch(IOException e){
Toast.makeText(this,"IO Exception", Toast.LENGTH_SHORT).show();
}
}
private void readInnerData(){
try{
// FileInputStream fin = new FileInputStream("YYP.dat");//出現fileNotFoundException
FileInputStream fin = openFileInput("YYP.dat");
BufferedReader reader = new BufferedReader(new InputStreamReader(fin));
String line;
while((line=reader.readLine())!=null){
tv.append(line+"\n");
}
fin.close();
}catch(IOException e){
Toast.makeText(this,"save ok",Toast.LENGTH_SHORT ).show();
}
}
//讀取寫入SDcard
private void saveSDData(){
String data = iodata3.getText().toString();
try{
FileWriter writer = new FileWriter("/mnt/sdcard/brad.dat");
writer.write(data);
writer.flush();
writer.close();
}catch(IOException e){
e.printStackTrace();
}
}
private void readSDData(){
try{
BufferedReader reader = new BufferedReader(new FileReader("/mnt/sdcard/brad.dat"));
String line;
while((line=reader.readLine())!=null){
tv3.append(line+"\n");
}
reader.close();
}catch(Exception e){
}
}
}
InnerStorage:
inner storage儲存在/data/data/com.example/files/之下
SDcardStorage
將資料儲存在SDcard
儲存基本型態的資料
如果應用程式使用的資料量不大
那麼可以考慮用SharedPreference
應用:
遊戲的紀錄
聲音開與關
等程式相關狀態
用SharedPreference創立的資料只限於該應用程式使用
當然可以在getSharedPreferences設定公開檔案給其他應用程式使用
SharedPreferences sp = getSharedPreferences("YYP.dat",MODE_PRIVATE);
以XML格式將資料存放到/data/data/com.example.fishingmapmaker/shared_prefs/之下
如果在實體手機操作那麼
/data必須是root權限才可以讀取
public class MainActivity extends Activity {
private Button click1, click2, click3;
private TextView tv, tv2, tv3;
private EditText iodata1, iodata3;
private SharedPreferences sp;
//宣告sharedpreference物件
private SharedPreferences.Editor editor;
//宣告sharedpreference編輯器
private String username;
private int stage;
private boolean sound;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sp = getSharedPreferences("YYPdata", MODE_PRIVATE);
//getSharedPreferences是context裡面的method
//建立sharedpreference儲存資料的檔案 並宣告存取權限為只限於本程式閱讀
editor= sp.edit();
//調出sharedpreference編輯器
click1 = (Button)findViewById(R.id.click1);
tv = (TextView)findViewById(R.id.tv);
click2 = (Button)findViewById(R.id.click2);
tv2 = (TextView)findViewById(R.id.tv2);
iodata1 = (EditText)findViewById(R.id.iodata1);
click3 = (Button)findViewById(R.id.click3);
tv3 = (TextView)findViewById(R.id.tv3);
iodata3 = (EditText)findViewById(R.id.iodata3);
click1.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View arg0) {
savePreference();
}
});
readPreference();
click2.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
saveInnerData();
}
});
readInnerData();
click3.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
saveSDData();
}
});
readSDData();
}
private void savePreference(){
editor.putBoolean("sound", false);//每個資料型態都有對應的method
editor.putString("username", "Brad");//存進檔案
editor.putInt("stage", 118);
editor.commit();//務必要寫這行,才會將資料存進檔案
readPreference();
}
private void readPreference(){
username = sp.getString("username", "nobody");//讀取sharedpreference的儲存內容
stage=sp.getInt("stage", 0);
sound=sp.getBoolean("sound", true);
tv.setText("UserName: " + username + "\n" +
"Sound: " + (sound?"On":"Off") + "\n" +
"Stage: " + stage);
}
private void saveInnerData(){
String data = iodata1.getText().toString();//EditView的輸入文字記得要在末端加上toString(),因為getText()是View型態
try{
FileOutputStream fout
FileOutputStream fout = openFileOutput("YYP.dat",MODE_PRIVATE);
FileOutputStream fout= new FileOutputStream("YYP.dat");//錯誤寫法 filenotfound
//在純翠java 會預設純到專案跟目錄
fout.write(data.getBytes());//因為檔案皆為字串所以要將字串型別轉成byte型式
fout.flush();
fout.close();
Toast.makeText(this, "save OK", Toast.LENGTH_SHORT).show();
readInnerData();
}catch(IOException e){
Toast.makeText(this,"IO Exception", Toast.LENGTH_SHORT).show();
}
}
private void readInnerData(){
try{
// FileInputStream fin = new FileInputStream("YYP.dat");//出現fileNotFoundException
FileInputStream fin = openFileInput("YYP.dat");
BufferedReader reader = new BufferedReader(new InputStreamReader(fin));
String line;
while((line=reader.readLine())!=null){
tv.append(line+"\n");
}
fin.close();
}catch(IOException e){
Toast.makeText(this,"save ok",Toast.LENGTH_SHORT ).show();
}
}
//讀取寫入SDcard
private void saveSDData(){
String data = iodata3.getText().toString();
try{
FileWriter writer = new FileWriter("/mnt/sdcard/brad.dat");
writer.write(data);
writer.flush();
writer.close();
}catch(IOException e){
e.printStackTrace();
}
}
private void readSDData(){
try{
BufferedReader reader = new BufferedReader(new FileReader("/mnt/sdcard/brad.dat"));
String line;
while((line=reader.readLine())!=null){
tv3.append(line+"\n");
}
reader.close();
}catch(Exception e){
}
}
}
InnerStorage:
inner storage儲存在/data/data/com.example/files/之下
SDcardStorage
將資料儲存在SDcard
2013年4月10日 星期三
android Tiemrtask
除了extends Thread 、implement Runnable之外
也可以用timertask物件啟動執行緒
並且可以採用Button按下去會執行多個執行緒
在一般java swing可以直接在thread 的run()中直接操控UI
但是在android不行
必須裡用handler傳遞message操控UI
private Timer timer;
pirvate MyHandler handler;
timer.schedule(timertask,什麼時候執行,執行時間長度);
private void Click3(){
timer = new Timer();
// timer.schedule(task, when, period)
timer.schedule(new MyTask(),0,1000);
//第零秒後執行my task物件,持續執行一千秒,每秒執行一次
}
private class MyTask extends TimerTask{
int i;
@Override
public void run() {
Log.i("YYP","i = "+i++);
// tv.setText("i = "+i++);
//在android裡面thread不可以直接操控UI否則會出現
//04-10 23:31:45.967: W/dalvikvm(399): threadid=7: thread exiting with uncaught exception (group=0x4001d800) 04-10 23:31:46.009: E/AndroidRuntime(399): FATAL EXCEPTION: Timer-0 //04-10 23:31:46.009: E/AndroidRuntime(399): android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
//要操控UI必須用handler物件傳遞Message
handler.sendEmptyMessage(i++);
//handler.sendEmtyMessage(what);
}
}
//handler必須宣告,UI所在的activity之中。
private class MyHandler extends Handler{
//reciev Message
@Override
public void handleMessage(Message msg) {
tv.setText("i="+msg.what);
}
}
//activity結束時,取消timer物件執行緒
//否則activity結束後timer物件仍會持續執行
public void finish(){
timer.cancel();
timer=null;
super.finish();
}
也可以用timertask物件啟動執行緒
並且可以採用Button按下去會執行多個執行緒
在一般java swing可以直接在thread 的run()中直接操控UI
但是在android不行
必須裡用handler傳遞message操控UI
private Timer timer;
pirvate MyHandler handler;
timer.schedule(timertask,什麼時候執行,執行時間長度);
private void Click3(){
timer = new Timer();
// timer.schedule(task, when, period)
timer.schedule(new MyTask(),0,1000);
//第零秒後執行my task物件,持續執行一千秒,每秒執行一次
}
private class MyTask extends TimerTask{
int i;
@Override
public void run() {
Log.i("YYP","i = "+i++);
// tv.setText("i = "+i++);
//在android裡面thread不可以直接操控UI否則會出現
//04-10 23:31:45.967: W/dalvikvm(399): threadid=7: thread exiting with uncaught exception (group=0x4001d800) 04-10 23:31:46.009: E/AndroidRuntime(399): FATAL EXCEPTION: Timer-0 //04-10 23:31:46.009: E/AndroidRuntime(399): android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
//要操控UI必須用handler物件傳遞Message
handler.sendEmptyMessage(i++);
//handler.sendEmtyMessage(what);
}
}
//handler必須宣告,UI所在的activity之中。
private class MyHandler extends Handler{
//reciev Message
@Override
public void handleMessage(Message msg) {
tv.setText("i="+msg.what);
}
}
//activity結束時,取消timer物件執行緒
//否則activity結束後timer物件仍會持續執行
public void finish(){
timer.cancel();
timer=null;
super.finish();
}
2013年3月23日 星期六
ListView
Adapter:
連接後端資料與前端View的配接器

SimpleAdapter:可以自由擴充listItem格式
ArrayAdapter:listitem只能顯示一行
ListView讓手機頁面秀出垂直條列式項目。
約有三種方式:
一、
1.
首先在xml貼上<ListView>標籤,
<ListView
android:id="@+id/lv"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
></ListView>
預覽頁面會是下面這樣:
2.定義Item長相:
Item也是layout一種,一般新增一個xml來做Item版面配置。
假如我們希望Item長相如下:
有Icon,有title以及說明內容。
那麼新增一個item.xml,用來描繪Item的長相
上圖用兩個LinearLayout以及一個ImageView以及兩個TextView實作。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<ImageView
android:id="@+id/item_img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:src="@drawable/TVClose" //圖片所屬資料夾以及檔名
/>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="4"
android:orientation="vertical"
>
<TextView
android:id="@+id/item_title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="TVclose"
android:textSize="24dip"
android:textStyle="bold"
/>
<TextView
android:id="@+id/item_content"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="電視收播圖像"
android:textSize="12dip"
/>
</LinearLayout>
</LinearLayout>
在drawable放圖片檔案:
另外要在res資料夾裏頭,新增資料夾drawable,裡面放想要呈現在listview的圖片,放在res的檔案android會自動配置參考地址(int 型態)。在java要取用時可以打R.drawable.圖片檔名。
在.java宣告
private ListView lv;
lv=(ListView)findViewbyId(R.id.lv)
常見作法用ArrayList以及HashMap配合和泛型實作ListView
ArrayList表示ListView容器本身,HashMap表示一個Item。
ArrayList可以裝多個HashMap。
HashMap可以裝Item的資訊、圖檔
ArrayList<HashMap<String,Object>> list = new ArrayList<HashMap<String,Object>>();
//宣告ArrayList,這個ArrayList可以裝下多個HashMap
//以HashMap實作ListView的Item
//String:是key、index,也可以屬性來比喻他,方便開發者更好寫程式。Object是資料,可以用值來比喻。
HashMap<String,Object> data1 = new HashMap<String,Object>();
data1.put("item_img",R.drawable.freezer );//存放圖檔
data1.put("item_title", "Freezer");//Item圖檔在listview的名字
data1.put("item_content", "佛利沙,過去在宇宙為人人聞之色變的惡魔");
//Item說明
list.add(data1);//將Item塞入listview(將HashMap塞入Arraylist物件)
HashMap<String,Object> data4 = new HashMap<String,Object>();
data4.put("item_img", R.drawable.tvclose);
data4.put("item_title", "TVclose");
data4.put("item_content", "電視收播,以前電視台休息收播會出現影像");
list.add(data4);
//上面已經宣告listview設定,尚未告訴android
//main_activity.java的item與item.xml怎樣連接
//也沒告訴.java的listview與xml的listview連接
//底下實作之
String[] from = {"item_img","item_title","item_content"};
//HashMap的key,為了底下SimpleAdapter使用
int[] to = {R.id.item_img,R.id.item_title,R.id.item_content};
//Item.xml的標籤id
//注意int陣列中元素所代表的物件要正確對應到String的每個字串所代表的物件,例如R.id.item_title在item.xml代表TextView物件,而String[] from的"item_title"在activity.java裡面代表HashMap的字串,所以順序擺放要
正確,否則無法正確顯示listview
如果將順序改成如下,那麼顯示的listView如圖:
//int[] to = {R.id.item_content,R.id.item_title,R.id.item_img};
SimpleAdapter adapter = new SimpleAdapter(this, list,R.layout.item, from, to);
//資料與lItem的配接器,參數缺一不可,android才會幫我們接上對應的
//SimpleAdapter(哪個.java的item(context),哪個xml的item,HashMap的key,Item.xml版面配置單一選項編號)
lv.setAdapter(adapter);
//設置listview的配接器,item要秀在哪個listview
二、
1.
xml放一個<ListView />
<ListView
android:id="@android:id/list"
@android:id/list意思是調用android系統內建的id(資源)
//而且list只能給ListView用,如果用android:id其他的項目則會發生錯誤
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:drawSelectorOnTop="false"
/>
2.
extends ListActivity
3.
制定listview內容
String[] items = {"Aibo","Brad","Clock","David","Enjoy"};
setListAdapter(new ArrayAdapter(this,android.R.layout.XXXX,items));
//ArrayAdapter(context,listview格式,listview(裡面的textView)內容)
//setListAdapter
String[] items ={"Sherry", "Dorara", "Black", "Int", "Five"};
Button button1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//list項目
//setListAdapter(new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,items));
//ArrayAdapter(context , 格式TextViewResourceId(android有內建xml檔案?各式各樣格式, ,項目內容String[] items);
//普通格式
//setListAdapter(new ArrayAdapter<String>(this,android.R.layout.simple_list_item_single_choice,items));
//radiocheck模式
//setListAdapter(new ArrayAdapter<String>(this,android.R.layout.simple_list_item_checked,items));
//打勾圖示
setListAdapter(new ArrayAdapter<String>(this,android.R.layout.simple_list_item_activated_1,items));
//項目反白
//getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
//getListView()從Activity取得ListView物件
//複選模式
//如果不打上這行,預設為Choice_mode_none
//選擇項目
getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
//單選模式
button1=(Button)findViewById(R.id.button1);
}
//callback method
public void onListItemClick(ListView parent,View v, int position, long id){
button1.setText(items[position]);
}
三、整個activity視為ListView
1.準備一個XML描述ListView單一項目
<!-- <Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
/> -->
//若加上這個,每一項目都有button
//setOnItemClickListener失效
<TextView
android:id="@+id/item_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:layout_marginBottom="6dp"
android:textSize="24sp"
android:textStyle="bold|italic"
/>
2.新增一個Activity extends ListActivity
3.
宣告陣列存放ListView的項目內容
//例如Listview每一項目有TextView則宣告字串陣列
String[] item = {"one","two","three"};
//如果ListView項目有圖片就宣告 int陣列
int[] photos={R.drawable.photo1,R..drawable.photo2,R.drawable.photo3};
4.
宣告ArrayList為ListView容器
HashMap代表ListView的每一筆紀錄
一筆紀錄有多個屬性(欄位)
(一筆紀錄有textview以及image)
ArrayList<HashMap<String,String>> data = new ArrayList();
5.
String[] from = {"item_title"};
//item的key名稱,
//目的讓adapter做配接用
int[] to ={R.id.item_title};
//對應到描述listview單一項目的Xml檔案,裡面的元件(wedgit)的ID。
//對應textview的id
//如果xml有TextView以及ImageView元件,元件id分別是R.id.item_title,R.id.pictur
//則宣告int[] to = {R.id.item_title,R.id.picture}
6.將內容塞入HashMap
for(String item:items){
HashMap<String,String> dd = new HashMap();
dd.put(from[0], item);
//將每一筆紀錄第from[0]欄位存放資料內容
data.add(dd);
}
7.將資料與ListView配接
adapter = new SimpleAdapter(this,data,R.layout.activity_main,from,to);
8.View物件使用配接器
lv=getListView();
//將整個Activity視為listview
//原本lv= (ListView)findViewById(R.id.lv);
lv.setAdapter(adapter);
private ListView lv;
private SimpleAdapter adapter;
private String[] items = {
"LinearLayout", "RelativeLayout",
"TableLayout", "ListView",
"Gallery"
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(R.layout.activity_main);
String[] from = {"item_title"};
//item的key
int[] to ={R.id.item_title};
//對應到listItem每項目裡面的元件。 對應textview的id
ArrayList<HashMap<String,String>> data = new ArrayList();
for(String item:items){
HashMap<String,String> dd = new HashMap();
dd.put(from[0], item);
data.add(dd);
}
adapter = new SimpleAdapter(this,data,R.layout.activity_main,from,to);
lv=getListView();
//將整個Activity視為listview
//原本lv= (ListView)findViewById(R.id.lv);
lv.setAdapter(adapter);
// lv.setOnClickListener(new OnClickListener(){
//
// @Override
// public void onClick(View v) {
// // TODO Auto-generated method stub
//
// }});
lv.setOnItemClickListener(new OnItemClickListener(){
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int index,
long arg3) {
doJob(index);
}});
}
private void doJob(int index )
{ switch(index)
{
case 0:
Toast.makeText(this, "LinearLayout", Toast.LENGTH_SHORT).show();
break;
case 1:
Toast.makeText(this, "RelativeLayout", Toast.LENGTH_SHORT).show();
break;
}
}
連接後端資料與前端View的配接器
SimpleAdapter:可以自由擴充listItem格式
ArrayAdapter:listitem只能顯示一行
ListView讓手機頁面秀出垂直條列式項目。
約有三種方式:
一、
1.
首先在xml貼上<ListView>標籤,
<ListView
android:id="@+id/lv"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
></ListView>
預覽頁面會是下面這樣:
2.定義Item長相:
Item也是layout一種,一般新增一個xml來做Item版面配置。
假如我們希望Item長相如下:
有Icon,有title以及說明內容。
那麼新增一個item.xml,用來描繪Item的長相
上圖用兩個LinearLayout以及一個ImageView以及兩個TextView實作。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<ImageView
android:id="@+id/item_img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:src="@drawable/TVClose" //圖片所屬資料夾以及檔名
/>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="4"
android:orientation="vertical"
>
<TextView
android:id="@+id/item_title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="TVclose"
android:textSize="24dip"
android:textStyle="bold"
/>
<TextView
android:id="@+id/item_content"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="電視收播圖像"
android:textSize="12dip"
/>
</LinearLayout>
</LinearLayout>
在drawable放圖片檔案:
另外要在res資料夾裏頭,新增資料夾drawable,裡面放想要呈現在listview的圖片,放在res的檔案android會自動配置參考地址(int 型態)。在java要取用時可以打R.drawable.圖片檔名。
在.java宣告
private ListView lv;
lv=(ListView)findViewbyId(R.id.lv)
常見作法用ArrayList以及HashMap配合和泛型實作ListView
ArrayList表示ListView容器本身,HashMap表示一個Item。
ArrayList可以裝多個HashMap。
HashMap可以裝Item的資訊、圖檔
ArrayList<HashMap<String,Object>> list = new ArrayList<HashMap<String,Object>>();
//宣告ArrayList,這個ArrayList可以裝下多個HashMap
//以HashMap實作ListView的Item
//String:是key、index,也可以屬性來比喻他,方便開發者更好寫程式。Object是資料,可以用值來比喻。
HashMap<String,Object> data1 = new HashMap<String,Object>();
data1.put("item_img",R.drawable.freezer );//存放圖檔
data1.put("item_title", "Freezer");//Item圖檔在listview的名字
data1.put("item_content", "佛利沙,過去在宇宙為人人聞之色變的惡魔");
//Item說明
list.add(data1);//將Item塞入listview(將HashMap塞入Arraylist物件)
HashMap<String,Object> data4 = new HashMap<String,Object>();
data4.put("item_img", R.drawable.tvclose);
data4.put("item_title", "TVclose");
data4.put("item_content", "電視收播,以前電視台休息收播會出現影像");
list.add(data4);
//上面已經宣告listview設定,尚未告訴android
//main_activity.java的item與item.xml怎樣連接
//也沒告訴.java的listview與xml的listview連接
//底下實作之
String[] from = {"item_img","item_title","item_content"};
//HashMap的key,為了底下SimpleAdapter使用
int[] to = {R.id.item_img,R.id.item_title,R.id.item_content};
//Item.xml的標籤id
//注意int陣列中元素所代表的物件要正確對應到String的每個字串所代表的物件,例如R.id.item_title在item.xml代表TextView物件,而String[] from的"item_title"在activity.java裡面代表HashMap的字串,所以順序擺放要
正確,否則無法正確顯示listview
如果將順序改成如下,那麼顯示的listView如圖:
//int[] to = {R.id.item_content,R.id.item_title,R.id.item_img};
SimpleAdapter adapter = new SimpleAdapter(this, list,R.layout.item, from, to);
//資料與lItem的配接器,參數缺一不可,android才會幫我們接上對應的
//SimpleAdapter(哪個.java的item(context),哪個xml的item,HashMap的key,Item.xml版面配置單一選項編號)
lv.setAdapter(adapter);
//設置listview的配接器,item要秀在哪個listview
二、
1.
xml放一個<ListView />
<ListView
android:id="@android:id/list"
@android:id/list意思是調用android系統內建的id(資源)
//而且list只能給ListView用,如果用android:id其他的項目則會發生錯誤
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:drawSelectorOnTop="false"
/>
2.
extends ListActivity
3.
制定listview內容
String[] items = {"Aibo","Brad","Clock","David","Enjoy"};
setListAdapter(new ArrayAdapter(this,android.R.layout.XXXX,items));
//ArrayAdapter(context,listview格式,listview(裡面的textView)內容)
//setListAdapter
String[] items ={"Sherry", "Dorara", "Black", "Int", "Five"};
Button button1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//list項目
//setListAdapter(new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,items));
//ArrayAdapter(context , 格式TextViewResourceId(android有內建xml檔案?各式各樣格式, ,項目內容String[] items);
//普通格式
//setListAdapter(new ArrayAdapter<String>(this,android.R.layout.simple_list_item_single_choice,items));
//radiocheck模式
//setListAdapter(new ArrayAdapter<String>(this,android.R.layout.simple_list_item_checked,items));
//打勾圖示
setListAdapter(new ArrayAdapter<String>(this,android.R.layout.simple_list_item_activated_1,items));
//項目反白
//getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
//getListView()從Activity取得ListView物件
//複選模式
//如果不打上這行,預設為Choice_mode_none
//選擇項目
getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
//單選模式
button1=(Button)findViewById(R.id.button1);
}
//callback method
public void onListItemClick(ListView parent,View v, int position, long id){
button1.setText(items[position]);
}
三、整個activity視為ListView
1.準備一個XML描述ListView單一項目
<!-- <Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
/> -->
//若加上這個,每一項目都有button
//setOnItemClickListener失效
<TextView
android:id="@+id/item_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:layout_marginBottom="6dp"
android:textSize="24sp"
android:textStyle="bold|italic"
/>
2.新增一個Activity extends ListActivity
3.
宣告陣列存放ListView的項目內容
//例如Listview每一項目有TextView則宣告字串陣列
String[] item = {"one","two","three"};
//如果ListView項目有圖片就宣告 int陣列
int[] photos={R.drawable.photo1,R..drawable.photo2,R.drawable.photo3};
4.
宣告ArrayList為ListView容器
HashMap代表ListView的每一筆紀錄
一筆紀錄有多個屬性(欄位)
(一筆紀錄有textview以及image)
ArrayList<HashMap<String,String>> data = new ArrayList();
5.
String[] from = {"item_title"};
//item的key名稱,
//目的讓adapter做配接用
int[] to ={R.id.item_title};
//對應到描述listview單一項目的Xml檔案,裡面的元件(wedgit)的ID。
//對應textview的id
//如果xml有TextView以及ImageView元件,元件id分別是R.id.item_title,R.id.pictur
//則宣告int[] to = {R.id.item_title,R.id.picture}
6.將內容塞入HashMap
for(String item:items){
HashMap<String,String> dd = new HashMap();
dd.put(from[0], item);
//將每一筆紀錄第from[0]欄位存放資料內容
data.add(dd);
}
7.將資料與ListView配接
adapter = new SimpleAdapter(this,data,R.layout.activity_main,from,to);
//this 的 data 放在 R.layout.activity_main,hashmap的key(就是from)要與xml的欄位(即to)對應
8.View物件使用配接器
lv=getListView();
//將整個Activity視為listview
//原本lv= (ListView)findViewById(R.id.lv);
lv.setAdapter(adapter);
private ListView lv;
private SimpleAdapter adapter;
private String[] items = {
"LinearLayout", "RelativeLayout",
"TableLayout", "ListView",
"Gallery"
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(R.layout.activity_main);
String[] from = {"item_title"};
//item的key
int[] to ={R.id.item_title};
//對應到listItem每項目裡面的元件。 對應textview的id
ArrayList<HashMap<String,String>> data = new ArrayList();
for(String item:items){
HashMap<String,String> dd = new HashMap();
dd.put(from[0], item);
data.add(dd);
}
adapter = new SimpleAdapter(this,data,R.layout.activity_main,from,to);
lv=getListView();
//將整個Activity視為listview
//原本lv= (ListView)findViewById(R.id.lv);
lv.setAdapter(adapter);
// lv.setOnClickListener(new OnClickListener(){
//
// @Override
// public void onClick(View v) {
// // TODO Auto-generated method stub
//
// }});
lv.setOnItemClickListener(new OnItemClickListener(){
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int index,
long arg3) {
doJob(index);
}});
}
private void doJob(int index )
{ switch(index)
{
case 0:
Toast.makeText(this, "LinearLayout", Toast.LENGTH_SHORT).show();
break;
case 1:
Toast.makeText(this, "RelativeLayout", Toast.LENGTH_SHORT).show();
break;
}
}
訂閱:
文章 (Atom)


