前言
有網(wǎng)購經(jīng)歷的小伙伴想必對下面的情景都不陌生:當(dāng)鼠標在商品圖片上滑動時蚯根,下方會有一個小區(qū)域展示商品的細節(jié)谱净。“前端”技術(shù)可以做出這個效果雨膨,但android也不是省油的,下面就帶大家手工制作一個具有上述功能的app(功能更強大读串,還可以改變圖片的透明度)聊记。
基本知識
以下是本次開發(fā)涉及到的知識
View組件之一ImageView
ImageView的主要功能是用來顯示包括圖片在內(nèi)的所有Drawable對象。
主要屬性有:
android:scaleType //設(shè)置圖片如何縮放及移動以適應(yīng)ImageView的大小
對應(yīng)屬性值:
android:scaleType="fitXY" //圖片縱向和橫向獨立縮放直至該圖片完全適應(yīng)該ImageView的大小
android:scaleType="fitCenter //保持縱橫比縮放恢暖,直至圖片能完全顯示在ImageView中排监,圖片的較長邊和ImageView相應(yīng)邊相等,并把圖片放置在ImageView中央
android:scaleType="fitStart //保持縱橫比縮放杰捂,直至圖片能完全顯示在ImageView中舆床,圖片的較長邊和ImageView相應(yīng)邊相等,并把圖片放置在ImageView左上角
android:scaleType="fitEnd //保持縱橫比縮放,直至圖片能完全顯示在ImageView中挨队,圖片的較長邊和ImageView相應(yīng)邊相等谷暮,并把圖片放置在右上角
android:scaleType="center //把圖片放置在ImageView中央,不進行任何縮放
另一個常用的屬性值
android:src//指定ImageView顯示哪張圖片
如
android:src="@drawable/ic_launcher" //該ImageView顯示drawable中名稱為ic_launcher的圖片
ImageView常用方法:
setImageBitmap(Bitmap)//當(dāng)要顯示的是位圖Bitmap對象時調(diào)用此方法
setImageDrawable(Drawable)//當(dāng)要顯示的是Drawable對象時調(diào)用此方法
setImageResource(int)//使用圖片的ID設(shè)置該ImageView顯示的圖片(在我的文章《使用命令行徒手開發(fā)安卓項目》中,我已說過R.id盛垦、R.id.drawable對應(yīng)對象為int類型湿弦,因此讀者不應(yīng)對此方法的形參類型感到疑惑)
setImageAlpha(int alpha)//設(shè)置圖片的透明度,透明度定義為int型
getDrawable()//從ImageView中獲取包裝有位圖的BitmapDrawable對象
上面前三個方法作用和android:src是一樣的腾夯,區(qū)別在于android:src用于xml布局文件颊埃,而這些方法用于java文件中。當(dāng)需要圖片隨著用戶的動作而變化時蝶俱,就需要用到這些方法了班利,android:src適用于圖片恒定不變的情況或者用于設(shè)置第一張圖片。
第一個和第三個方法在實戰(zhàn)中運用到榨呆,讀者可參考加深印象
Bitmap對象和BitmapDrawable對象
Bitmap代表位圖罗标,BitmapDrawable對象用于封裝一個Bitmap對象,它們之間的轉(zhuǎn)化如下:
BitmapDrawable bitmapdrawable=new BitmapDrawable(bitmap)//BitmapDrawable的單參構(gòu)造器积蜻,參數(shù)為Bitmap的一個對象
Bitmap bitmap=bitmapdrawable.getBitmap();//獲取BitmapDrawable對象中所包裝的Bitmap對象
要獲取Bitmap對象闯割,除了可以用上面的方法,還有以下常用方法:
createBitmap(Bitmap source, int x,int y, int width, int height)//在源位圖上從坐標為(x,y)的點開始摳出寬為width浅侨,高為height的圖片纽谒,保存為新的位圖
想一想photoshop中的摳圖對這個方法會有很好的理解证膨,在我們制作app的過程中如输,我們正是使用這個方法顯示一張圖片的細節(jié)部分的。
事件監(jiān)聽器
何為事件監(jiān)聽器央勒,簡單來說不见,我們?yōu)橐恍┙M件(這些組件稱為事件源)添加事件監(jiān)聽器后,當(dāng)出現(xiàn)事件時(如單擊按鈕崔步,觸摸屏幕等)稳吮,事件監(jiān)聽器就會調(diào)用內(nèi)部的事件處理器(通常為各種自定義方法)來進行響應(yīng)。
總結(jié)來說井濒,有三要素:事件源灶似、事件處理器,事件瑞你,我們必須三個元素都給予明確酪惭,下面詳細說明如何明確。
明確事件處理器:
本次開發(fā)我們使用到抽象類View.OnClickListener和View.OnTouchListener,它們的含義通過名稱不難看出者甲,在此不贅述春感。既然是抽象類,我們在創(chuàng)建它的一個對象之前,必須先改寫類內(nèi)部的onClick和onTouch成員方法鲫懒,這其實就是在明確事件處理器嫩实。示例如下:
View.OnClickListener listener=new View.OnClickListener()//創(chuàng)建OnClickListener的一個對象listener
{
public void onClick(View view) //重寫onClick函數(shù)
{
show.setText("請關(guān)注國之利刃2013"); //事件處理器定義:單擊后就在id為show的文本框中顯示”請關(guān)注國之利刃2013"
}
};
指定事件源:
指定事件源比較簡單,只要調(diào)用組件自身提供的方法就行了窥岩。常用的方法有setOnClickListener(OnClickListener)和setOnTouchListener(OnTouchListener)甲献,set可以理解為"注冊"的意思,這些方法就是為組件注冊事件監(jiān)聽器谦秧。在我們調(diào)用這些方法時竟纳,注冊組件的id就會傳給onClick或onTouch函數(shù)的形參view(理解這一點對理解接下來開發(fā)應(yīng)用的代碼很有幫助)
明確事件:這個很簡單,我們的OnClickListener和OnTouchListener就指定事件是單擊還是觸摸屏幕疚鲤。
實戰(zhàn)
有了以上儲備知識锥累,我們就可以著手具有細節(jié)瀏覽功能的圖片瀏覽器的app的開發(fā)了。我們分xml布局文件和業(yè)務(wù)實現(xiàn)java文件兩部分進行講解集歇。
xml文件中定義了四個按鈕桶略,兩個單擊時會切換圖片,兩個單擊時用于改變圖片透明度
除此之外诲宇,還定義了兩個ImageView际歼,一個用于展示完整圖片,當(dāng)觸摸時會將觸摸點附近的部分圖片顯示在另一個ImageView中姑蓝,代碼如下:
<?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"
android:background="@color/colorAccent"http://為了美觀鹅心,把背景色設(shè)為粉紅色
tools:context=".PictureBrowser">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/next"
android:text="下一張" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/next"http://設(shè)置位置
android:layout_marginLeft="50pt"http://設(shè)置左留白
android:id="@+id/last"
android:text="上一張" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/next"http://設(shè)置位置
android:layout_alignLeft="@id/next"http://設(shè)置該按鈕與id為next的組件左對齊
android:id="@+id/improve"
android:text="提高透明度" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/improve"http://設(shè)置位置
android:layout_alignTop="@id/improve"http://頂部對齊
android:layout_alignLeft="@id/last"http://左對齊
android:id="@+id/lower"
android:text="降低透明度" />
<ImageView
android:layout_width="110pt"http://設(shè)定ImageView的大小
android:layout_height="100pt"
android:layout_below="@id/lower"http://位置
android:layout_alignLeft="@id/next"http://左對齊
android:id="@+id/image1"
android:scaleType="fitCenter"/>//設(shè)置圖片放縮及移動的方式
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/image1"http://位置
android:layout_alignLeft="@id/image1"http://左對齊
android:layout_marginLeft="20pt"http://左留白
android:id="@+id/image2" />
</RelativeLayout>
java文件主要就是為各組件添加事件監(jiān)聽器,代碼如下:
package com.golfer.www.picturebrowser;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
public class PictureBrowser extends AppCompatActivity {
int[] photo=new int[]//定義圖片數(shù)組纺荧,元素都是drawable里面的圖片資源
{
R.drawable.wedding2,
R.drawable.wedding1,
R.drawable.wedding3,
R.drawable.wedding4,
R.drawable.wedding5,
R.drawable.wedding6,
R.drawable.wedding7,
R.drawable.wedding8,
};
Button next;
Button last;
Button improve;
Button lower;
ImageView img1;
ImageView img2;
int current=0;
int alpha=255;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
next=(Button)findViewById(R.id.next);
last=(Button)findViewById(R.id.last);
improve=(Button)findViewById(R.id.improve);
lower=(Button)findViewById(R.id.lower);
img1=(ImageView)findViewById(R.id.image1);
img2=(ImageView)findViewById(R.id.image2);
img1.setImageResource(photo[current]);
View.OnClickListener click=new View.OnClickListener()
{ //明確單擊頭兩個按鈕的單擊事件的事件處理器
public void onClick(View view)
{
if(view==next)//如果事件源是next按鈕
img1.setImageResource(photo[(++current)%photo.length]);//顯示下一張圖片
if(view==last)//如果事件源是last按鈕
img1.setImageResource(photo[(--current)%photo.length]);//顯示上一張圖片
}
};
next.setOnClickListener(click);//為next按鈕注冊事件監(jiān)聽器
last.setOnClickListener(click);//為last按鈕注冊事件監(jiān)聽器
View.OnClickListener listener=new View.OnClickListener()
{ //明確后兩個按鈕的事件處理器
public void onClick(View view)
{
if(view==improve) alpha=alpha+20;//如果事件源是improve按鈕旭愧,透明度加20
if(view==lower) alpha=alpha-20;//如果事件源是lower按鈕,透明度減去20
if(alpha>=255) alpha=255;
if(alpha<=0) alpha=0;
img1.setImageAlpha(alpha);//調(diào)用img1的設(shè)置圖片透明度的方法
}
};
improve.setOnClickListener(listener);//為improve按鈕注冊事件監(jiān)聽器
lower.setOnClickListener(listener);//為lower按鈕注冊事件監(jiān)聽器
View.OnTouchListener touch=new View.OnTouchListener()
{ //明確觸摸事件處理器
public boolean onTouch(View view, MotionEvent event)//注意onTouch方法的返回值和onCLick不同
{
BitmapDrawable bitmapDrawable= (BitmapDrawable)img1.getDrawable();//從img1中獲得顯示圖片的BitmapDrawable對象
Bitmap bitmap= bitmapDrawable.getBitmap();//獲取BitmapDrawable中包裝的Bitmap對象
double rate=bitmap.getHeight()/img1.getHeight();
int x=(int)(event.getX()*rate);//通過event.getX()獲取觸摸點的X坐標
int y=(int)(event.getY()*rate);//event從哪里來呢宙暇?看看onTouch方法的參數(shù)吧
if((y+120)>bitmap.getHeight()) y=bitmap.getHeight()-120;//異常處理输枯,防止摳圖越過源位圖的邊界
if((x+120)>bitmap.getWidth()) x=bitmap.getWidth()-120;
Bitmap part=Bitmap.createBitmap(bitmap,x,y,120,120);//摳取圖片的一部分得到新位圖
img2.setImageBitmap(part);//這里用到ImageView顯示圖片的方法之一
return true;
}
};
img1.setOnTouchListener(touch);
}
}
注:讀者可能會對以下幾行代碼有疑惑,為什么要用到這個rate(比率)呢占贫?
double rate=bitmap.getHeight()/img1.getHeight();
int x=(int)(event.getX()*rate);
int y=(int)(event.getY()*rate);
解釋如下:
首先桃熄,從img1得到的位圖大小和img1的大小是不同的(如果我們采用fitCenter或fitStart或fitEnd縮放方式,則圖片的較長邊和img1相應(yīng)邊相等型奥,另一條邊往往不相等)瞳收。其次,event.getX()獲得的是觸摸點在img1上的坐標厢汹,而我們調(diào)用createBitmap函數(shù)摳圖時參數(shù)x和y要求是在位圖上的坐標螟深,因此就有必要將event.getX()乘上比率rate(位圖和img1不相等的邊的長度之比,在這里是它們的高之比)了坑匠。
如果我們不使用rate血崭,將會看到img2顯示的圖片并不是觸摸點附近的圖片。
app界面及功能展示如下: