Android--UI之ImageView


前言

  這篇博客聊一聊在Android下ImageView的使用,在此篇博客中,會講解到ImageView的一些屬性的使用,以及ImageView展示圖片的放大、縮小、旋轉等操作。最后再講解一下Android4.0項目中最常用的一個功能,從網絡獲取圖片的示例。本文所有講解均會附上示例代碼,並在最后提供源碼下載。

ImageView

  ImageView,圖像視圖,直接繼承自View類,它的主要功能是用於顯示圖片,實際上它不僅僅可以用來顯示圖片,任何Drawable對象都可以使用ImageView來顯示。ImageView可以適用於任何布局中,並且Android為其提供了縮放和着色的一些操作。

  ImageView的一些常用屬性,並且這些屬性都有與之對應的getter、setter方法:

  • android:adjustViewBounds:設置ImageView是否調整自己的邊界來保持所顯示圖片的長寬比。
  • android:maxHeight:設置ImageView的最大高度。
  • android:maxWidth:設置ImageView的最大寬度。
  • android:scaleType:設置所顯示的圖片如何縮放或移動以適應ImageView的大小。
  • android:src:設置ImageView所顯示的Drawable對象的ID。

  對於android:scaleType屬性,因為關於圖像在ImageView中的顯示效果,所以有如下屬性值可以選擇:

  • matrix:使用matrix方式進行縮放。
  • fitXY:橫向、縱向獨立縮放,以適應該ImageView。
  • fitStart:保持縱橫比縮放圖片,並且將圖片放在ImageView的左上角。
  • fitCenter:保持縱橫比縮放圖片,縮放完成后將圖片放在ImageView的中央。
  • fitEnd:保持縱橫比縮放圖片,縮放完成后將圖片放在ImageView的右下角。
  • center:把圖片放在ImageView的中央,但是不進行任何縮放。
  • centerCrop:保持縱橫比縮放圖片,以使圖片能完全覆蓋ImageView。
  • centerInside:保持縱橫比縮放圖片,以使得ImageView能完全顯示該圖片。

圖片基本顯示

  下面通過一個示例效果,來說明一下ImageView是如何顯示圖片的,再此示例中,需要使用到一個green.png的圖片,需要放到Drawable文件夾下,關於Android的資源文件,以后再進行詳解。

  布局代碼:

復制代碼
 1 <?xml version="1.0" encoding="utf-8"?>
 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent"
 5     android:orientation="vertical" >
 6 
 7     <TextView
 8         android:layout_width="match_parent"
 9         android:layout_height="wrap_content"
10         android:text="scaleType:center,未縮放,在ImageView的中心" />
11 
12     <ImageView
13         android:id="@+id/imageview1"
14         android:layout_width="200dp"
15         android:layout_height="100dp"
16         android:background="#F00"
17         android:scaleType="center"
18         android:src="@drawable/green" />
19 
20     <TextView
21         android:layout_width="match_parent"
22         android:layout_height="wrap_content"
23         android:text="scaleType:fitCenter,按比例縮放" />
24 
25     <ImageView
26         android:id="@+id/imageview2"
27         android:layout_width="300dp"
28         android:layout_height="200dp"
29         android:background="#FFF"
30         android:padding="10dp"
31         android:scaleType="fitCenter"
32         android:src="@drawable/green" />
33 
34 </LinearLayout>
復制代碼

  效果展示:

   

縮放與旋轉圖片

  因為ImageView繼承自View,所以在代碼中設置其大小,可以使用View.setLayoutParams(new LinearLayout.LayoutParams(newWidth,newHeight))方法,這個方法可以直接設定View下的所有控件的外觀大小,所以這里也適用於ImageView。

  而對於ImageView的旋轉,這里涉及到一個Matrix類的使用。它表示一個3x3的坐標變換矩陣,可以在這個矩陣內,對其進行變換、旋轉操作,它需要通過構造函數顯式的初始化之后才可以使用。

  下面通過一個示例來說明一下圖片的放大縮小與旋轉的示例,在示例中會提供兩個SeekBar,對於SeekBar如果不了解的話,可以參見我的另外一篇博客,Android—UI之Progress。這兩個SeekBar一個設置ImageView顯示圖片的大小,另一個設置旋轉的角度。對於圖片大小,通過DisplayMetrics設置屏幕的寬度為圖像的最大寬度,具體操作在注釋中已經寫明,這里不在累述。

  布局代碼: 

復制代碼
 1 <?xml version="1.0" encoding="utf-8"?>
 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent"
 5     android:orientation="vertical" >
 6 
 7     <ImageView
 8         android:id="@+id/imageview3"
 9         android:layout_width="200dp"
10         android:layout_height="150dp"
11         android:scaleType="fitCenter"
12         android:src="@drawable/green" />
13 
14     <TextView
15         android:id="@+id/tv1"
16         android:layout_width="match_parent"
17         android:layout_height="wrap_content"
18         android:layout_marginTop="10dp"
19         android:text="圖像寬度:240 圖像高度:150" />
20 
21     <SeekBar
22         android:id="@+id/sbSize"
23         android:layout_width="200dp"
24         android:layout_height="wrap_content"
25         android:layout_marginTop="10dp"
26         android:max="240"
27         android:progress="120" />
28 
29     <TextView
30         android:id="@+id/tv2"
31         android:layout_width="match_parent"
32         android:layout_height="wrap_content"
33         android:layout_marginTop="10dp"
34         android:text="0°" />
35 
36     <SeekBar
37         android:id="@+id/sbRotate"
38         android:layout_width="200dp"
39         android:layout_height="wrap_content"
40         android:layout_marginTop="10dp"
41         android:max="360" />
42 
43 </LinearLayout>
復制代碼

  實現代碼:

復制代碼
 1 package com.bgxt.imageviewdemo;
 2 
 3 import android.annotation.SuppressLint;
 4 import android.app.Activity;
 5 import android.graphics.Bitmap;
 6 import android.graphics.BitmapFactory;
 7 import android.graphics.Matrix;
 8 import android.graphics.drawable.BitmapDrawable;
 9 import android.os.Bundle;
10 import android.util.DisplayMetrics;
11 
12 import android.widget.ImageView;
13 import android.widget.LinearLayout;
14 import android.widget.SeekBar;
15 import android.widget.SeekBar.OnSeekBarChangeListener;
16 import android.widget.TextView;
17 
18 @SuppressLint("NewApi")
19 public class ChangeImageActivity extends Activity implements
20         OnSeekBarChangeListener {
21     private int minWidth = 80;
22     private ImageView imageView;
23     private TextView textview1, textview2;
24     Matrix matrix=new Matrix();
25 
26     @Override
27     protected void onCreate(Bundle savedInstanceState) {
28         // TODO Auto-generated method stub
29         super.onCreate(savedInstanceState);
30         setContentView(R.layout.layout_changeimage);
31 
32         imageView = (ImageView) findViewById(R.id.imageview3);
33         SeekBar seekbar1 = (SeekBar) findViewById(R.id.sbSize);
34         SeekBar seekbar2 = (SeekBar) findViewById(R.id.sbRotate);
35         textview1 = (TextView) findViewById(R.id.tv1);
36         textview2 = (TextView) findViewById(R.id.tv2);
37 
38         //獲取當前屏幕的尺寸,並設置圖片放大的最大尺寸,不能超過屏幕尺寸
39         DisplayMetrics dm = new DisplayMetrics();
40         getWindowManager().getDefaultDisplay().getMetrics(dm);
41         seekbar1.setMax(dm.widthPixels - minWidth);
42         
43         seekbar1.setOnSeekBarChangeListener(this);
44         seekbar2.setOnSeekBarChangeListener(this);        
45     }
46 
47     @Override
48     public void onProgressChanged(SeekBar seekBar, int progress,
49             boolean fromUser) {
50         if (seekBar.getId() == R.id.sbSize) {
51             //設置圖片的大小
52             int newWidth=progress+minWidth;
53             int newHeight=(int)(newWidth*3/4);
54             imageView.setLayoutParams(new LinearLayout.LayoutParams(newWidth, newHeight));
55             textview1.setText("圖像寬度:"+newWidth+"圖像高度:"+newHeight);
56         } else if (seekBar.getId() == R.id.sbRotate){
57             //獲取當前待旋轉的圖片
58             Bitmap bitmap=BitmapFactory.decodeResource(getResources(), R.drawable.green);
59             //設置旋轉角度
60             matrix.setRotate(progress,30,60);
61             //通過待旋轉的圖片和角度生成新的圖片
62             bitmap=Bitmap.createBitmap(bitmap,0,0,bitmap.getWidth(),bitmap.getHeight(),matrix,true);
63             //綁定圖片到控件上
64             imageView.setImageBitmap(bitmap);
65             textview2.setText(progress+"°");
66         }
67     }
68 
69     @Override
70     public void onStartTrackingTouch(SeekBar seekBar) {
71         // TODO Auto-generated method stub
72 
73     }
74 
75     @Override
76     public void onStopTrackingTouch(SeekBar seekBar) {
77         // TODO Auto-generated method stub
78 
79     }
80 
81 }
復制代碼

  效果展示:

  

從互聯網獲取圖片

  一個移動的平台開發,很多資源是不可能一直保存在本地的,更多實時性的東西,是需要直接通過網絡及時獲取的。這里通過一個從網上獲取圖片展示到ImageView的例子,來講解一下這個功能的實現。

  在Android4.0之后,增加了一些新特性,也增加了一些限制。其中有一個限制就是不能在主線程中訪問網絡,必須另開一條線程訪問。但是這里又存在另外一個問題,在子線程中,無法直接操作UI控件的屬性。如果你們使用的開發平台是Android4.0之下,就不存在這個問題,直接在主線程中訪問網絡操作UI控件即可。

  我的解決方案就是,通過Thread類,進行多線程訪問網絡,再通過Handler類,進行消息傳遞。對於Thread類,是Java的知識,不再詳細講解,對於Handler類,這里簡要說明一下。

  在Android平台下,不允許Activity新啟動的線程訪問該Activity里的界面UI控件,這樣就會導致新啟動的線程無法動態改變界面UI控件的屬性值。所以就需要借助Handler的消息傳遞機制來實現。Handler類的主要作用有兩個:

  • 在新啟動的線程中發送消息。
  • 在主線程中獲取、處理消息。

  上面描述的兩個作用,發送消息好說,在需要的時候發送,那怎么確定什么時候接收消息呢?為了讓主線程能接受並處理新啟動的線程發送的消息,Android通過回調的方式來實現,開發人員只需要重寫Handler類中處理消息的方法,handleMessage(Message)即可,其中Message封裝了發送過來的消息。

   Handler包含如下方法,用於實現發送和處理消息:

  • void handleMessage(Message msg):處理消息的方法,用於被重寫。
  • final boolean hasMessage(int what):檢查消息隊列中是否包含what屬性為指定值的消息。
  • sendEmptyMessage(int what):立即發送空消息。
  • final boolean sendEmptyMessageDelayed(int what,long delayMillis):指定delayMillis毫秒之后發送空消息。
  • final boolean sendMessage(Message msg):立即發送消息。
  • final boolean sendMessageDelayed(Message msg,long delayMillis):指定delayMillis毫秒之后發送消息。

   Message封裝了線程中傳遞的消息,如果對於一般的數據,Message提供了getData()和setData()方法來獲取與設置數據,其中操作的數據是一個Bundle對象,這個Bundle對象提供一系列的getXxx()和setXxx()方法用於傳遞基本數據類型,對於基本數據類型,使用起來很簡單,這里不再詳細講解。而對於復雜的數據類型,如一個對象的傳遞就要相對復雜一些。在Bundle中提供了兩個方法,專門用來傳遞對象的,但是這兩個方法也有相應的限制,需要實現特定的接口,當然,一些Android自帶的類,其實已經實現了這兩個接口中的某一個,可以直接使用。方法如下:

  • putParcelable(String key,Parcelable value):需要傳遞的對象類實現Parcelable接口。
  • pubSerializable(String key,Serializable value):需要傳遞的對象類實現Serializable接口。

  還有另外一種方式在Message中傳遞對象,那就是使用Message自帶的obj屬性傳值,它是一個Object類型,所以可以傳遞任意類型的對象,Message自帶的有如下幾個屬性:

  • int arg1:參數一,用於傳遞不復雜的數據,復雜數據使用setData()傳遞。
  • int arg2:參數二,用於傳遞不復雜的數據,復雜數據使用setData()傳遞。
  • Object obj:傳遞一個任意的對象。
  • int what:定義的消息碼,一般用於確定消息的來源。

  下面這個示例,使用了兩種方式獲取傳遞消息,以一個隨機數確定。在這個示例中,訪問網絡的代碼會附上但是不會詳解,如果對於Android中訪問網絡不熟悉的朋友,可以參見我另外一篇博客,Android--Http協議

  布局代碼:

復制代碼
 1 <?xml version="1.0" encoding="utf-8"?>
 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent"
 5     android:orientation="vertical" >
 6     
 7    
 8  <Button android:id="@+id/btnInternet" android:layout_width="wrap_content"
 9     android:layout_height="wrap_content" android:text="下載網絡圖片"/>
10  <TextView android:id="@+id/tbMsgType" android:layout_width="match_parent"
11     android:layout_height="wrap_content"/>
12   <ImageView android:id="@+id/ivInternet" android:layout_width="wrap_content"
13     android:layout_height="wrap_content"/>
14 </LinearLayout>
復制代碼

  實現代碼:

復制代碼
 1 package com.bgxt.imageviewdemo;
 2 
 3 import java.io.InputStream;
 4 import java.net.HttpURLConnection;
 5 import java.util.Random;
 6 
 7 import com.bgxt.httputils.HttpUtils;
 8 
 9 import android.app.Activity;
10 import android.graphics.Bitmap;
11 import android.graphics.BitmapFactory;
12 import android.os.Bundle;
13 import android.os.Handler;
14 import android.os.Message;
15 import android.view.View;
16 import android.widget.Button;
17 import android.widget.ImageView;
18 import android.widget.TextView;
19 import android.widget.Toast;
20 
21 public class InternetImageActivity extends Activity {
22     private Button btnInternet;
23     private ImageView ivInternet;
24     private TextView tvMsgType;
25     private Handler handler;
26 
27     @Override
28     protected void onCreate(Bundle savedInstanceState) {
29         // TODO Auto-generated method stub
30         super.onCreate(savedInstanceState);
31         setContentView(R.layout.activity_internetimage);
32 
33         btnInternet = (Button) findViewById(R.id.btnInternet);
34         ivInternet = (ImageView) findViewById(R.id.ivInternet);
35         tvMsgType = (TextView) findViewById(R.id.tbMsgType);
36 
37         // 定義一個handler,用於接收消息
38         handler = new Handler() {
39             @Override
40             public void handleMessage(Message msg) {
41                 Bitmap bmp = null;
42                 // 通過消息碼確定使用什么方式傳遞圖片信息
43                 if (msg.what == 0) {
44                     bmp = (Bitmap) msg.obj;
45                     tvMsgType.setText("使用obj傳遞數據");
46                 } else {
47                     Bundle ble = msg.getData();
48                     bmp = (Bitmap) ble.get("bmp");
49                     tvMsgType.setText("使用Bundle傳遞數據");
50                 }
51                 // 設置圖片到ImageView中
52                 ivInternet.setImageBitmap(bmp);
53             }
54         };
55 
56         btnInternet.setOnClickListener(new View.OnClickListener() {
57             @Override
58             public void onClick(View v) {
59                 //清空之前獲取的數據
60                 tvMsgType.setText("");
61                 ivInternet.setImageBitmap(null);
62                 //定義一個線程類
63                 new Thread() {
64                     @Override
65                     public void run() {
66                         try {
67                             //獲取網絡圖片
68                             InputStream inputStream = HttpUtils
69                                     .getImageViewInputStream();
70                             Bitmap bitmap = BitmapFactory
71                                     .decodeStream(inputStream);
72                             Message msg = new Message();
73                             Random rd = new Random();
74                             int ird = rd.nextInt(10);
75                             //通過一個隨機數,隨機選擇通過什么方式傳遞圖片信息到消息中
76                             if (ird / 2 == 0) {
77                                 msg.what = 0;
78                                 msg.obj = bitmap;
79                             } else {
80                                 Bundle bun = new Bundle();
81                                 bun.putParcelable("bmp", bitmap);
82                                 msg.what = 1;
83                                 msg.setData(bun);
84                             }
85                             //發送消息
86                             handler.sendMessage(msg);
87                         } catch (Exception e) {
88 
89                         }
90                     }
91                 }.start();
92             }
93         });
94     }
95 }
復制代碼

  訪問網絡類,代碼:

復制代碼
 1 package com.bgxt.httputils;
 2 
 3 import java.io.IOException;
 4 import java.io.InputStream;
 5 import java.net.HttpURLConnection;
 6 import java.net.URL;
 7 
 8 public class HttpUtils {
 9     private final static String URL_PATH = "http://ww4.sinaimg.cn/bmiddle/9e58dccejw1e6xow22oc6j20c80gyaav.jpg";
10 
11     public HttpUtils() {
12     }
13 
14     public static InputStream getImageViewInputStream() throws IOException {
15         InputStream inputStream = null;
16         URL url = new URL(URL_PATH);
17         if (url != null) {
18             HttpURLConnection httpURLConnection = (HttpURLConnection) url
19                     .openConnection();
20             httpURLConnection.setConnectTimeout(3000);
21             httpURLConnection.setRequestMethod("GET");
22             httpURLConnection.setDoInput(true);
23             int response_code = httpURLConnection.getResponseCode();
24             if (response_code == 200) {
25                 inputStream = httpURLConnection.getInputStream();
26             }
27         }
28         return inputStream;
29     }
30 }
復制代碼

  效果展示:

  示例代碼下載

總結

  以上就講解了ImageView的一些基本使用,對於Android項目而言,一般的用到更多的就是從網絡獲取圖片的功能,所以這里着重講解了一下。

  請支持原創,尊重原創,轉載請注明出處。謝謝。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM