>

javacode

Sunday, June 5, 2016

如何使用ImageView 圖片切換


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

我們會運用到Bitmap Drawable 

話不多說直接實作一下

在Layout xml的佈局很簡單 就創建兩個圖片 和一個按鈕來讓兩個圖片交換
<?xml version="1.0" encoding="utf-8"?>
<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:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="myimageviewswitch.myimageviewswitch.MainActivity">
<ImageView
android:layout_width="200dp"
android:layout_height="200dp"
android:id="@+id/m_image1"/>
<ImageView
android:layout_width="200dp"
android:layout_height="200dp"
android:id="@+id/m_image2"
android:layout_below="@id/m_image1"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/m_image2"
android:onClick="ChangeImageView"/>
</RelativeLayout>

MainActivity裡面只有兩個方法


public class MainActivity extends AppCompatActivity {
private ImageView m_image1;
private ImageView m_image2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initImageView();
}
/*初始化*/
public void initImageView(){
m_image1 = (ImageView) findViewById(R.id.m_image1);
m_image2 = (ImageView) findViewById(R.id.m_image2);
m_image1.setImageResource(R.drawable.fun1);
m_image2.setImageResource(R.drawable.fun3);
}
public void ChangeImageView(View view){
change(m_image1,m_image2);
}
private void change(ImageView target,ImageView dest){
/*使用buildDrawCache()方法建立DrawCache
* 也可以使用setDeawingCacheEnable(true)*/
target.buildDrawingCache();
dest.buildDrawingCache();
Bitmap iv1 = ((BitmapDrawable)dest.getDrawable()).getBitmap();
Bitmap iv2 = ((BitmapDrawable)target.getDrawable()).getBitmap();
dest.setImageBitmap(iv2);
target.setImageBitmap(iv1);
}
}
view raw MainActivity hosted with ❤ by GitHub

在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裡的方法


private void change(final ImageView target, final ImageView dest){
/*使用buildDrawCache()方法建立DrawCache
* 也可以使用setDeawingCacheEnable(true)*/
target.buildDrawingCache();
dest.buildDrawingCache();
/*要設定LayoutParams*/
LinearLayout.LayoutParams ll = new LinearLayout.LayoutParams(target.getWidth(),target.getHeight());
target.setLayoutParams(ll);
LinearLayout.LayoutParams ll2 = new LinearLayout.LayoutParams(dest.getWidth(),dest.getHeight());
dest.setLayoutParams(ll2);
/*設定位移動畫*/
TranslateAnimation targetts = new TranslateAnimation(0,dest.getLeft()-target.getLeft(),
0,dest.getTop()-target.getTop());
targetts.setDuration(300);
targetts.setFillAfter(true);
/*將設定好的位移規則注入到target裡*/
target.setAnimation(targetts);
TranslateAnimation destts = new TranslateAnimation(0,target.getLeft()-dest.getLeft(),
0,target.getTop()-dest.getTop());
destts.setDuration(300);
destts.setFillAfter(true);
dest.setAnimation(destts);
/*設定Animation監聽器*/
targetts.setAnimationListener(new Animation.AnimationListener() {
@Override
/*動畫開始時要做的事情*/
public void onAnimationStart(Animation animation) {
/*宣告一個全域變數 boolean 用來做啟動動畫的開關*/
isAnimation = true;
target.setVisibility(View.INVISIBLE);
dest.setVisibility(View.INVISIBLE);
}
@Override
/*動畫結束要做的事情*/
public void onAnimationEnd(Animation animation) {
Bitmap iv1 = ((BitmapDrawable) dest.getDrawable()).getBitmap();
Bitmap iv2 = ((BitmapDrawable) target.getDrawable()).getBitmap();
dest.setVisibility(View.VISIBLE);
target.setVisibility(View.VISIBLE);
dest.setImageBitmap(iv2);
target.setImageBitmap(iv1);
isAnimation = false;
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
}

在程式 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進去。


效果圖