具有細節(jié)瀏覽功能的圖片瀏覽器

前言

有網(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界面及功能展示如下:


透明度正常

增大透明度
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市夹纫,隨后出現(xiàn)的幾起案子咽瓷,更是在濱河造成了極大的恐慌,老刑警劉巖舰讹,帶你破解...
    沈念sama閱讀 212,686評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件茅姜,死亡現(xiàn)場離奇詭異,居然都是意外死亡月匣,警方通過查閱死者的電腦和手機钻洒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,668評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來锄开,“玉大人素标,你說我怎么就攤上這事∑笺玻” “怎么了头遭?”我有些...
    開封第一講書人閱讀 158,160評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長癣诱。 經(jīng)常有香客問我计维,道長,這世上最難降的妖魔是什么撕予? 我笑而不...
    開封第一講書人閱讀 56,736評論 1 284
  • 正文 為了忘掉前任鲫惶,我火速辦了婚禮,結(jié)果婚禮上实抡,老公的妹妹穿的比我還像新娘欠母。我一直安慰自己,他們只是感情好澜术,可當(dāng)我...
    茶點故事閱讀 65,847評論 6 386
  • 文/花漫 我一把揭開白布艺蝴。 她就那樣靜靜地躺著猬腰,像睡著了一般鸟废。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上姑荷,一...
    開封第一講書人閱讀 50,043評論 1 291
  • 那天盒延,我揣著相機與錄音,去河邊找鬼鼠冕。 笑死添寺,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的懈费。 我是一名探鬼主播计露,決...
    沈念sama閱讀 39,129評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了票罐?” 一聲冷哼從身側(cè)響起叉趣,我...
    開封第一講書人閱讀 37,872評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎该押,沒想到半個月后疗杉,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,318評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡蚕礼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,645評論 2 327
  • 正文 我和宋清朗相戀三年烟具,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片奠蹬。...
    茶點故事閱讀 38,777評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡朝聋,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出囤躁,到底是詐尸還是另有隱情玖翅,我是刑警寧澤,帶...
    沈念sama閱讀 34,470評論 4 333
  • 正文 年R本政府宣布割以,位于F島的核電站金度,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏严沥。R本人自食惡果不足惜猜极,卻給世界環(huán)境...
    茶點故事閱讀 40,126評論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望消玄。 院中可真熱鬧跟伏,春花似錦、人聲如沸翩瓜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,861評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽兔跌。三九已至勘高,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間坟桅,已是汗流浹背华望。 一陣腳步聲響...
    開封第一講書人閱讀 32,095評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留仅乓,地道東北人赖舟。 一個月前我還...
    沈念sama閱讀 46,589評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像夸楣,于是被迫代替她去往敵國和親宾抓。 傳聞我的和親對象是個殘疾皇子子漩,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,687評論 2 351

推薦閱讀更多精彩內(nèi)容