>

javacode

Sunday, June 5, 2016

如何使用ImageView 圖片切換


最近有忙不完的事情...又導致更新的停擺(嘆~)
那天同學問我個問題 如何做到圖片的切換 想了一下 原理其實不難

我們會運用到Bitmap Drawable 

話不多說直接實作一下

在Layout xml的佈局很簡單 就創建兩個圖片 和一個按鈕來讓兩個圖片交換

MainActivity裡面只有兩個方法



在change方法裡先將ImageView dest,target的圖檔強制繪圖緩存

ImageView 是View 的子類別 所以可以直接使用buildDrawingCache()這方法(View父類的方法)

View類別的API

先說說Bitmap Drawable View的差異


Bitmap是指你的電腦裡面存有一張圖片,他的格式可能是bmp,jpg,png或是gif而Android也支援這些圖片檔,因此我們可以利用Bitmap這個類別物件,將我們的圖檔讀進Android,通常讀進去後他就變成串流模式(Stream)(不知道什麼是串流的話....Java I/O 要在讀一下唷)

為什麼會變成串流?很簡單因為電腦沒有眼睛(啊嘶.....sorry情不自禁),痾...其實它是看不懂圖片,電腦只認識二進制碼。
所以我們將圖片轉成串流才可以讓電腦了解我們的"圖"是什麼東東

View 可以想像成一個Container(容器),它可以用來裝你想要呈現的東東(Bitmap之類的),他會根據事先安排好的格式,然後呈現在畫面上。Android根據廣大開發者的需求,制定了一些需要的View容器給大家使用

EX: ImageView,TextView,GridView,ListView,Button....等等

Drawable 可以想成是一個可畫的對象,其中可能是一個BitmapDrawable,也可能是個圖形(ShapeDrawable),還有可能是個圖層(LayerDrawable),我們根據畫圖的需求創建相應的可畫對象。Drawable的子類別當然不只上述那幾種 

可以瞧瞧Drawable這個類別



在MainActivity中
第25行是  dest 這個用於顯示圖片的reference裡的圖片,返回的是一個Drawable類型。如果沒有圖片會回傳null。
再將它轉型轉成(BitmapDrawable) 因為我們要使用.getBitmap()這方法
根據BitmapDrawable的API說明中,它可以處理原始位圖圖形(Bitmap)的管理和改造


BitmapDrawable API


getBitmap()是從一個已知的圖片中獲得圖片的bitmap對象!
將我們所取得的Bitmap注入到我們的容器裡 這樣就完成了換圖片拉!!

效果圖:




進階版

透過之前學到的Animation 動態效果 讓我們換圖生動一點

首先先把Layout換成LinearLayout orientation = "vertical"

MainActivity變動的不多 主要就是修改change裡的方法



在程式 40 行 如果不做宣告 你會發現圖片不會動唷
那LayoutParams在做什麼事情呢?
其實這個LayoutParams是作用於子類別(我們的ImageView)向 parent View(父View 也就是LinearLayout)傳達自己的意願,簡單說呢孩子想要變成什麼樣子需要跟父報告說明(width,hiegh)...每個View都擁有自己的LayoutParams唷

如果還不能理解呢~就想想 小時候要去哪裡是不是要跟家裡的爸爸媽媽說明你要去哪裡,這時候爸爸媽媽肯定會問:去哪裡~跟誰~什麼時候回來

如果還是不能理解呢..就要啟動說故事模式了

LayoutParams繼承於Android.View.ViewGroup.LayoutParams
LayoutParams相當於一個Layout的履歷表,它封裝了Layout的位置,寬,高..等訊息。
假設在螢幕上有一塊區域是是由一個Layout所佔領的,如果將一個TextView or ImageView...添加到一個Layout中,最好告知Layout這個地主期望的佈局方式,也就是傳入一個認可的LayoutParams進去。


效果圖






Friday, May 6, 2016

AlertDialog(對話框)的應用-Callback機制(回調函式)

 對話框
想必大家對這東東並不陌生,不論是應用程式或是網頁 都看得到他的身影

先看看Google的介紹

Google AlertDialog


AlterDialog有個限制 在對話框中的按鈕 最少為一個 最多三個

AlterDialog是利用建構者模式 

內部類別

  • 非靜態的內層類別,稱為內部類別
  • 內部類別的物件必須存在於外部類別物件當中
  • 內外層物件隱含交互參考,內層物件可參考到外層物件,外層物件可參考到內層物件

「instance of a class」的圖片搜尋結果

靜態巢狀類別

  • 內層類別宣告為靜態,稱為 靜態巢狀類別
  • 靜態巢狀類別物件可單獨建立

而AlertDialog則是利用了靜態巢狀類別這方式而設計的

Dialog
關於Dialog(三種按鈕:正面,負面,中立)



首先 
先將layout 設定為LinearLayout 
orientation設定為vertical(垂直)
<LinearLayout
     ......省略........
     android:orientation="vertical"
     ......................
     <TextView
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:id="@+id/text"
         android:gravity="center"
         android:text="Hello World"
         android:textSize="18dp"/>
     <Button
         android:layout_width="match_parent"
         android:layout_height = "wrap_content"
         android:onClick="clickAlterDialog"
         android:textAllCaps="false"
         android:text="AlertDialog Ok"

MainActivity:

將要使用到的物件先宣告出來




我們的Button 利用好萊塢模式(onClick) 所以不需要特別在宣告
我們只需要實作出 代表onClick的方法就可


clickAlertDialog的方法表示 當按下Button時 會生成一個對話框 


這個onClick的方法是實現 DialogInterface.onClickListener 

對話框裡面按鈕所觸發的事件
以上的寫法個人是十分不喜歡 如果是多個對話框 在實作DialogInterface這方法裡就會有一堆的switch...
(光想...就十分頭痛)
所以只用兩個對話框來做這樣的示範...
給對話框一個reference,用reference去做判斷
這當中就會有些狀況發生 當Activity 被銷毀時 並不能保證 reference 參考到的對話框也會一同被銷毀,這時候它就會默默地消耗你的記憶體。 活在你看不到的地方...

以下的對話框都會使用匿名的方式 匿名的好處是使用完它就會被銷毀 不用考慮到他的生命週期
當然程式碼還是會看起來臃腫些..至於愛用哪種方式就見仁見智囉
Layout的宣告就不再贅述了..就是一直加個Button
第三個按鈕的效果圖




提供清單的Dialog


首先在 values裡新增一個新的 resouce file 取名自己命名



我命名為arrays arrays的內容:




綠色區塊為匿名內部類別 
String[] response為區域變數 在匿名內部類別的區域變數必須加上final這個修飾詞 不然的話在textView.setText(response[which])會有錯誤唷

項目可複選的Dialog



 先設定好 多選裡的事件
 再來就是創建 正項按鈕裡要做事件

項目多選一的Dialog



在setSingleChoiceItems 這事件(onClick)執行完後,which就會消失,所以要用一個欄位來記錄到底是點選了哪一個選項。
再將紀錄的選項值放入我們的陣列裡,這樣就會知道選擇了哪一個。


自訂Dialog 

新增Fragment 這是Google推薦的Dialog的用法





先設定好Fragment的Layout



android:fontFamily="sans-serif" 是等寬字體



修改MyDialogFragment

  • 變更繼承的對象為android.support.v4.app.DialogFragment
  • 由於這個DialogFragment並不是一般的Fragment,刪除onCreateView()方法
  • 覆寫DialogFragment的onCreateDialog()



覆寫onCreateDialog方法
在onCreateDialog動態產生畫面



在Activity建立 自訂的 Dialog



MainActivity:



效果圖




Fragment與Activity 通訊

與Activity通訊(Android Developers):為Activity建立回調函式(Callback)

類別圖:


Fragment 透過介面(interface)跟Activity溝通

  • 兩個類別要解除耦合(decoupling),中間透過介面來溝通


程式碼改變的不多 

MyDialogFragment:
多加個interface

在設定正項按鈕裡 將想要傳給Activity的資料注入interface裡的方法


利用回調函式 以後誰想要資料 只需要實作出 這個類的interface CallBack就可以取得資料

MainActivity:


這樣就取得了在DialogFragment editText裡的資料囉



再做稍稍延伸  想要紀錄 登入者登入的次數 同樣的登入者會做累加

我們將會利用Map來達到這樣的目的

先宣告個Map出來
private Map<String,Integer>map = new Map<>();

接著在onInputComplete裡做判斷



效果圖:



Github:程式碼

Tuesday, May 3, 2016

面試題目-動態加載Button


母親節檔期忙到不行.....腿和手默默發出無聲地顫抖抗議呀!!(餐飲業好可怕呀~~)...............遲來的更新m(_ _)m

    面試題目
試著做出 畫面有三個Button 亂數跑這三個Button
跑到的Button會有個 X , 當按下 X , X會消失 這時候會有個TextView紀錄案中多少次
這個做出來後
請延伸為9個按鈕 放入List裡面 將按鈕數據化 不可以使用switch去判斷

最開始三個不難做出來了,但延伸的問題讓我卡住,初學者的我來說 ,基本功沒很到位 ,稍稍做了功課後 實現了一下...

效果圖:

首先先分析 自己會需要什麼東東
1.TextView,GridLayout 用來放9個Button(這9個按鈕 我們會用動態產生出來),一個開始Button
2.不是IO或是費時的工作不要用Thread,用Handler給UI Thread執行
3.實現onClickListener

話不多說 直接實現看看

Layout:RelativeLayout

<ReliativeLayout
  .......
  .......省略......

   <TextView
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:layout_centerHorizontal="true"
       android:text="次數"
       android:id="@+id/count"
       android:textSize="24dp"/>
   <Button
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:layout_alignParentBottom="true"
       android:layout_centerHorizontal="true"
       android:id="@+id/start"
       android:text="start"
       android:onClick="start"/>
    <GridLayout
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:columnCount="3"
       android:rowCount="3"
       android:id="@+id/gridlayout"/>
</RelativeLayout>

MainActivity:


public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private GridLayout gridLayout;
    private TextView textView;
    private Handler handler;
    private int counter = 0;
    private List<Button> list = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initButtons();
    }
    /*初始化*/
    public void initButtons() {
        textView = (TextView) findViewById(R.id.count);
        handler = new Handler();
        gridLayout = (GridLayout) findViewById(R.id.gridlayout);
        /*動態加載Button*/        
            for (int i = 0; i < 9; i++) {
            Button button = new Button(this);
            button.setOnClickListener(this);
            /*將Button放入List裡*/            
            list.add(button);
            /*將List放入GridLayout*/            
            gridLayout.addView(button);
        }
    }
    /*啟動Runnable*/    
    public void Start(View view) {
        textView.setText("次數 :");
        counter = 0;
        handler.post(x_random_runnable);
        handler.postDelayed(x_random_runnableStop, 10000);
    }
    private X_Random_Runnable x_random_runnable = new X_Random_Runnable();
    private X_Random_RunnableStop x_random_runnableStop = new X_Random_RunnableStop();
    /*實現onClickListener*/    
    @Override
    public void onClick(View v) {
        /*判斷按下的Button是不是 X*/
        if ("X".equals(((Button) v).getText().toString())) {
            ++counter;
            textView.setText("擊中" + counter + "次數");
            initButtonSetText();
        }
    }
    /*讓X消失*/
    private void initButtonSetText() {
        for(int i=0;i<list.size();i++){
            list.get(i).setText("");
        }
    }

    /*實現Runnable 亂數跑 9個Button*/
    private class X_Random_Runnable implements Runnable {

        @Override
        public void run() {
            int index = (int) (Math.random() * list.size());
            for (int i = 0; i < list.size(); i++) {
                if (i == index) {
                    list.get(i).setText("X");
                } else {
                    list.get(i).setText("");
                }
            }
            handler.postDelayed(this, 1500);
        }
    }
    /*停止Runnable*/
    private class X_Random_RunnableStop implements Runnable {

        @Override
        public void run() {
            handler.removeCallbacks(x_random_runnable);
        }
    }
}

GitHub
https://github.com/Brian43/MyIntervewTest

Monday, April 18, 2016

Intent認識與應用 Activity切換與數據交互

什麼是Intent『意圖』?

強大的事件處理「Intent」是Android很強大的一種機制

在Android應用程式框架中,有一個非常聰明得事件處理機制,稱之為「Intent」。Intent的作用跟事件(event)很相似,但與傳統的事件處理任然有些差異。傳統的處理事件,講求的是「處理者(handler)的觸發」,當一件事情發生時,便callback讓事件的處理者,或是直接將該事件轉送(forword)給應用程式,由應用程式決定處理方式。

在「Intent」這樣的事件處理觀念裡,Android試圖將事件解釋為「應用程式的意圖」或者「使用者的意圖」,並試著去解釋該意圖的目的,若Android系統本身能理解應用程式的意圖,便會「自行」去處理該意圖所應執行的工作。

Android的做法是,讓每個意圖(Intent)都帶有一個動作(action),並根據不同的的動作去行動。


(最近工作太忙碌...遲來的更新m(_ _)m)


關於Intent(意圖)




對於意圖這個說法 我更加喜歡用喚醒 來形容它所做的事..


實作Intent切換Activity

首先在 activity_main layout裡創建一個Button
<Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_above="@id/btn_edit"
    android:layout_centerHorizontal="true"
    android:text="點我選擇顏色"
    android:onClick="SelectColor"
    android:id="@+id/btn_color"/>
利用好萊塢模式 onClick="SelectColor"

MainActivity

public class MainActivity extends AppCompatActivity {

/*intent會用到的識別碼*/   

private final static int SELECT_REQUEST = 0;

private final static int SELECT_EDIT=1;

private TextView result_text;

private int mcolorInt;

@Override protected void onCreate(Bundle savedInstanceState){

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

}

public void SelectColor(View view){

/*Intent需要能返回結果*/
startActivityForResult(new Intent(this,ColorPickActivity), SELECT_REQUEST);}

SELECT_REQUEST 宣告為 final static 是想讓這個reference 只有一個且值不被改變 而作為Intent裡面的識別碼

在MoveToNext 這個方法 其實也就是對應上面layout中Button裡宣告的onClick

Intent 也可以這樣宣告
                                                           /*從當前的Activity , 到目標的Activity*/
Intent  intent = new Intent(this,Activity1.class);
/*確定回傳值是我們所要的,放入識別碼方便辨認*/
startActivityForResult(intent,SELECT_REQUEST);

其實短短的兩行就完成了 Intent的使用 這樣就可以進行切換Activity了

在切換Activity的同時 也希望將某些資料傳遞給下一個Activity 或者互相傳值


new 一個ColorPickActivity

layout:


<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"
    android:layout_margin="16dp"
    tools:context="apprestart.mylab07_2intent_.ColorPickActivity">

        <RadioGroup
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:id="@+id/radio_rg">
            <RadioButton
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:id="@+id/radio_holo_red_light"
                android:buttonTint="@android:color/holo_red_light"
                android:text="holo_red_light"
                android:checked="true"
                android:onClick="clickColor"
                android:textColor="@android:color/holo_red_light"
                android:textAppearance="@android:style/TextAppearance.Large"/>
            <RadioButton
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:id="@+id/radio_holo_orange_light"
                android:buttonTint="@android:color/holo_orange_light"
                android:text="holo_orange_light"
                android:onClick="clickColor"
                android:textColor="@android:color/holo_orange_light"
                android:textAppearance="@android:style/TextAppearance.Large"/>
            <RadioButton
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:id="@+id/radio_holo_blue_light"
                android:buttonTint="@android:color/holo_blue_light"
                android:text="holo_blue_light"
                android:onClick="clickColor"
                android:textColor="@android:color/holo_blue_light"
                android:textAppearance="@android:style/TextAppearance.Large"/>
            <RadioButton
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:id="@+id/radio_holo_green_dark"
                android:buttonTint="@android:color/holo_green_dark"
                android:text="holo_green_dark"
                android:onClick="clickColor"
                android:textColor="@android:color/holo_green_dark"
                android:textAppearance="@android:style/TextAppearance.Large"/>
            <RadioButton
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:id="@+id/radio_holo_purple"
                android:buttonTint="@android:color/holo_purple"
                android:text="holo_purple"
                android:onClick="clickColor"
                android:textColor="@android:color/holo_purple"
                android:textAppearance="@android:style/TextAppearance.Large"/>
        </RadioGroup>
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignStart="@+id/radio_rg"
            android:layout_below="@id/radio_rg"
            android:text="Cancle"
            android:onClick="SelectCancle"/>
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/radio_rg"
            android:layout_alignEnd="@id/radio_rg"
            android:text="Ok"
            android:onClick="SeleckOk"/>
</RelativeLayout>

利用RadioGroup的好處是 在RadioGroup裡的RadioButton 會互斥達到單選效果。

ColorPickActivity:


public class ColorPickActivity extends AppCompatActivity {
/*Key值 最佳實現方式,以app的package作為前綴詞*/
public final static String  BUNDLE_KEY_COLOR_INT="apprestart.mylab07_2intent_android.colorInt";
public final static String BUNDLE_KEY_COLOR_NAME="apprestart.mylab07_2intent_android.colorName";
private int mColorInt;
private CharSequence mColorName;

@Overrideprotected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_color_pick);

    initColor();

}
    /*初始化*/
    public void initColor(){
    /*預設顏色為紅色*/
    RadioButton radioButton = (RadioButton) findViewById(R.id.radio_holo_red_light);
    /*取得按鈕顏色的值*/    
    mColorInt = radioButton.getCurrentTextColor();
    /*將按鈕文字放入mColorName*/    
    mColorName = radioButton.getText().toString();
}
/*點選RadioButton 每一個RadioButton都有宣告android:onClick:"clickColor"*/
public void clickColor(View view){
/*將View強轉成RadioButton 透過點選取得是哪一個RadioButton*/
    RadioButton radio = (RadioButton)view;
/*取得 android:text裡的字串*/
    mColorName = radio.getText().toString();
/*取得顏色的值*/
    mColorInt = radio.getCurrentTextColor();
}
   /*好萊塢模式*/
   /*利用putEXtra將要傳送的資料放入 
    putExtra(key值,value) 把它想成置物櫃 
    想要拿到置物櫃裡的物品首先要對應的就是Key
    Key對了才取得到值*/
public void SeleckOk(View view){
    /*創建一個Intent的物件*/
    Intent intent = new Intent();
    intent.putExtra(BUNDLE_KEY_COLOR_INT,mColorInt);
    intent.putExtra(BUNDLE_KEY_COLOR_NAME,mColorName);
    /*設定有返回值*/
    setResult(RESULT_OK, intent);
    /*結束目前的Activity*/
    finish();
}
public void SelectCancle(View view){
    setResult(RESULT_CANCELED);
    finish();
}

由於一開始的MainActivity只有切換到ColorPickActivity 在ColorPickActivity選擇好顏色後
將選好顏色的值 傳回MainActivity 而MainActivity需要接收ColorPickActivity傳回來的值
我們只需要在MainActivity 多寫個方法即可

MainActivity

/*Android系統(好萊塢) 回報有結果*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    /*如果回傳的包裹裡的識別碼與我們當初定義的相同,這結果就是我們要的*/
    if (requestCode == SELECT_REQUEST){
        if(resultCode ==RESULT_OK){
            /*取得包裹*/
            Bundle bundle = data.getExtras();
            /*從包裡取得值*/
            mcolorInt = bundle.getInt(ColorPickActivity.BUNDLE_KEY_COLOR_INT);
            String colorName = bundle.getString(ColorPickActivity.BUNDLE_KEY_COLOR_NAME);
            
            /*將Color相關的資訊設定到TextView*/
            result_text = (TextView) findViewById(R.id.result_text);
            result_text.setText(colorName);
            result_text.setTextColor(mcolorInt);
        }
    }
}

執行結果: