亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 系統 > Android > 正文

Android編程實現的超炫圖片瀏覽器

2020-04-11 11:11:35
字體:
來源:轉載
供稿:網友

本文實例講述了Android編程實現的超炫圖片瀏覽器。分享給大家供大家參考,具體如下:

使用過Android自帶的gallery組件的人都知道,gallery實現的效果就是拖動瀏覽一組圖片,相比iphone里也是用于拖動瀏覽圖片的coverflow,顯然遜色不少。實際上,可以通過擴展gallery,通過偽3D變換可以基本實現coverflow的效果。本文通過源代碼解析這一功能的實現。具體代碼作用可參照注釋。

最終實現效果如下:

要使用gallery,我們必須首先給其指定一個adapter。在這里,我們實現了一個自定義的ImageAdapter,為圖片制作倒影效果。

傳入參數為context和程序內drawable中的圖片ID數組。之后調用其中的createReflectedImages()方法分別創造每一個圖像的倒影效果,生成對應的ImageView數組,最后在getView()中返回。

Copyright (C) 2010 Neil Davies * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * [url]http://www.apache.org/licenses/LICENSE-2.0[/url] * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * This code is base on the Android Gallery widget and was Created * by Neil Davies neild001 'at' gmail dot com to be a Coverflow widget * * @author Neil Davies */ public class ImageAdapter extends BaseAdapter { int mGalleryItemBackground; private Context mContext; private Integer[] mImageIds ; private ImageView[] mImages; public ImageAdapter(Context c, int[] ImageIds) { mContext = c; mImageIds = ImageIds; mImages = new ImageView[mImageIds.length]; } public boolean createReflectedImages() { // The gap we want between the reflection and the original image final int reflectionGap = 4; int index = 0; for (int imageId : mImageIds) { Bitmap originalImage = BitmapFactory.decodeResource( mContext.getResources(), imageId); int width = originalImage.getWidth(); int height = originalImage.getHeight(); // This will not scale but will flip on the Y axis Matrix matrix = new Matrix(); matrix.preScale(1, -1); // Create a Bitmap with the flip matrix applied to it. // We only want the bottom half of the image Bitmap reflectionImage = Bitmap.createBitmap(originalImage, 0, height / 2, width, height / 2, matrix, false); // Create a new bitmap with same width but taller to fit // reflection Bitmap bitmapWithReflection = Bitmap.createBitmap(width, (height + height / 2), Config.ARGB_8888); // Create a new Canvas with the bitmap that's big enough for // the image plus gap plus reflection Canvas canvas = new Canvas(bitmapWithReflection); // Draw in the original image canvas.drawBitmap(originalImage, 0, 0, null); // Draw in the gap Paint deafaultPaint = new Paint(); canvas.drawRect(0, height, width, height + reflectionGap, deafaultPaint); // Draw in the reflection canvas.drawBitmap(reflectionImage, 0, height + reflectionGap, null); // Create a shader that is a linear gradient that covers the // reflection Paint paint = new Paint(); LinearGradient shader = new LinearGradient(0, originalImage.getHeight(), 0, bitmapWithReflection.getHeight() + reflectionGap, 0x70ffffff, 0x00ffffff, TileMode.CLAMP); // Set the paint to use this shader (linear gradient) paint.setShader(shader); // Set the Transfer mode to be porter duff and destination in paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN)); // Draw a rectangle using the paint with our linear gradient canvas.drawRect(0, height, width, bitmapWithReflection.getHeight() + reflectionGap, paint); ImageView imageView = new ImageView(mContext); imageView.setImageBitmap(bitmapWithReflection); imageView .setLayoutParams(new GalleryFlow.LayoutParams(160, 240)); // imageView.setScaleType(ScaleType.MATRIX); mImages[index++] = imageView; } return true; } public int getCount() { return mImageIds.length; } public Object getItem(int position) { return position; } public long getItemId(int position) { return position; } public View getView(int position, View convertView, ViewGroup parent) { // Use this code if you want to load from resources /* * ImageView i = new ImageView(mContext); * i.setImageResource(mImageIds[position]); i.setLayoutParams(new * CoverFlow.LayoutParams(350,350)); * i.setScaleType(ImageView.ScaleType.CENTER_INSIDE); * * //Make sure we set anti-aliasing otherwise we get jaggies * BitmapDrawable drawable = (BitmapDrawable) i.getDrawable(); * drawable.setAntiAlias(true); return i; */ return mImages[position]; } /** * Returns the size (0.0f to 1.0f) of the views depending on the * 'offset' to the center. */ public float getScale(boolean focused, int offset) { /* Formula: 1 / (2 ^ offset) */ returnMath.max(0,1.0f / (float) Math.pow(2, Math.abs(offset))); } } }

僅僅實現了圖片的倒影效果還不夠,因為在coverflow中圖片切換是有旋轉和縮放效果的,而自帶的gallery中并沒有實現。因此,我們擴展自帶的gallery,實現自己的galleryflow。在原gallery類中,提供了一個方法getChildStaticTransformation()以實現對圖片的變換。我們通過覆寫這個方法并在其中調用自定義的transformImageBitmap(“每個圖片與gallery中心的距離”)方法,,即可實現每個圖片做相應的旋轉和縮放。其中使用了camera和matrix用于視圖變換。具體可參考代碼注釋。

public class GalleryFlow extendsGallery {   /**    * Graphics Camera used for transforming the matrix of ImageViews    */   privateCamera mCamera = newCamera();   /**    * The maximum angle the Child ImageView will be rotated by    */   privateint mMaxRotationAngle =60;   /**    * The maximum zoom on the centre Child    */   privateint mMaxZoom = -120;   /**    * The Centre of the Coverflow    */   privateint mCoveflowCenter;   publicGalleryFlow(Context context) {     super(context);     this.setStaticTransformationsEnabled(true);   }   publicGalleryFlow(Context context, AttributeSet attrs) {     super(context, attrs);     this.setStaticTransformationsEnabled(true);   }   publicGalleryFlow(Context context, AttributeSet attrs, int defStyle) {     super(context, attrs, defStyle);     this.setStaticTransformationsEnabled(true);   }   /**    * Get the max rotational angle of the image    *    * @return the mMaxRotationAngle    */   publicint getMaxRotationAngle() {     returnmMaxRotationAngle;   }   /**    * Set the max rotational angle of each image    *    * @param maxRotationAngle    *   the mMaxRotationAngle to set    */   publicvoid setMaxRotationAngle(intmaxRotationAngle) {     mMaxRotationAngle = maxRotationAngle;   }   /**    * Get the Max zoom of the centre image    *    * @return the mMaxZoom    */   publicint getMaxZoom() {     returnmMaxZoom;   }   /**    * Set the max zoom of the centre image    *    * @param maxZoom    *   the mMaxZoom to set    */   publicvoid setMaxZoom(intmaxZoom) {     mMaxZoom = maxZoom;   }   /**    * Get the Centre of the Coverflow    *    * @return The centre of this Coverflow.    */   privateint getCenterOfCoverflow() {     return(getWidth() - getPaddingLeft() - getPaddingRight()) / 2         + getPaddingLeft();   }   /**    * Get the Centre of the View    *    * @return The centre of the given view.    */   privatestatic int getCenterOfView(View view) {     returnview.getLeft() + view.getWidth() / 2;   }   /**    * {@inheritDoc}    *    * @see #setStaticTransformationsEnabled(boolean)    */   protectedboolean getChildStaticTransformation(View child, Transformation t) {     finalint childCenter = getCenterOfView(child);     finalint childWidth = child.getWidth();     introtationAngle = 0;     t.clear();     t.setTransformationType(Transformation.TYPE_MATRIX);     if(childCenter == mCoveflowCenter) {       transformImageBitmap((ImageView) child, t,0);     }else {       rotationAngle = (int) (((float) (mCoveflowCenter - childCenter) / childWidth) * mMaxRotationAngle);       if(Math.abs(rotationAngle) > mMaxRotationAngle) {         rotationAngle = (rotationAngle <0) ? -mMaxRotationAngle             : mMaxRotationAngle;       }       transformImageBitmap((ImageView) child, t, rotationAngle);     }     returntrue;   }   /**    * This is called during layout when the size of this view has changed. If    * you were just added to the view hierarchy, you're called with the old    * values of 0.    *    * @param w    *   Current width of this view.    * @param h    *   Current height of this view.    * @param oldw    *   Old width of this view.    * @param oldh    *   Old height of this view.    */   protectedvoid onSizeChanged(intw, int h, int oldw, int oldh) {     mCoveflowCenter = getCenterOfCoverflow();     super.onSizeChanged(w, h, oldw, oldh);   }   /**    * Transform the Image Bitmap by the Angle passed    *    * @param imageView    *   ImageView the ImageView whose bitmap we want to rotate    * @param t    *   transformation    * @param rotationAngle    *   the Angle by which to rotate the Bitmap    */   privatevoid transformImageBitmap(ImageView child, Transformation t,       introtationAngle) {     mCamera.save();     finalMatrix imageMatrix = t.getMatrix();     finalint imageHeight = child.getLayoutParams().height;     finalint imageWidth = child.getLayoutParams().width;     finalint rotation = Math.abs(rotationAngle);     // 在Z軸上正向移動camera的視角,實際效果為放大圖片。     // 如果在Y軸上移動,則圖片上下移動;X軸上對應圖片左右移動。     mCamera.translate(0.0f,0.0f, 100.0f);     // As the angle of the view gets less, zoom in     if(rotation < mMaxRotationAngle) {       floatzoomAmount = (float) (mMaxZoom + (rotation *1.5));       mCamera.translate(0.0f,0.0f, zoomAmount);     }     // 在Y軸上旋轉,對應圖片豎向向里翻轉。     // 如果在X軸上旋轉,則對應圖片橫向向里翻轉。     mCamera.rotateY(rotationAngle);     mCamera.getMatrix(imageMatrix);     imageMatrix.preTranslate(-(imageWidth /2), -(imageHeight /2));     imageMatrix.postTranslate((imageWidth /2), (imageHeight /2));     mCamera.restore();   } }

代碼到這里就結束了。有興趣的話可以自行調整里面的參數來實現更多更炫的效果。
下面是調用的示例:

public void onCreate(Bundle savedInstanceState) {     super.onCreate(savedInstanceState);     setContentView(R.layout.layout_gallery);     Integer[] images = { R.drawable.img0001, R.drawable.img0030,       R.drawable.img0100, R.drawable.img0130, R.drawable.img0200,       R.drawable.img0230, R.drawable.img0300, R.drawable.img0330,       R.drawable.img0354 };     ImageAdapter adapter =new ImageAdapter(this, images);     adapter.createReflectedImages();     GalleryFlow galleryFlow = (GalleryFlow) findViewById(R.id.gallery_flow);     galleryFlow.setAdapter(adapter); }

PS1:

可以看出來這樣實現的gallery鋸齒問題比較嚴重??梢栽赾reateReflectedImages()使用以下代碼:

BitmapDrawable bd = new BitmapDrawable(bitmapWithReflection);bd.setAntiAlias(true);

然后用iv.setImageDrawable(bd);
代替iv.setImageBitmap(bitmapWithReflection);
即可基本消除鋸齒。

PS2:

ImageAdapter有待確定的MemoryLeak問題,貌似的Bitmap的decode方法會造成ML,使用ImageAdapter時多次旋轉屏幕后會出現OOM。目前可以通過將使用完畢的bimap調用recycle()方法和設置null并及時調用system.gc()得到一些改善,但是問題并不明顯。
慶祝精華和推薦,增加3個PS~

PS3 ON PS1:

為什么開啟抗鋸齒后不明顯。答案是,鋸齒不可能完全消除,但開啟抗鋸齒后會有很大改善。
另外還說到為什么android不默認開啟鋸齒,以下是我的一點想法:
插值是我現在所知道的抗鋸齒的算法,也就是計算像素間的相關度對其間插入中間像素以達到平滑圖像邊緣的效果。但這無疑會耗費了大量的運算。
雖然我沒有經過測試,但是我猜測,使用antialias后圖形性能至少會下降30%。
當然,在這里沒有涉及到復雜的圖形運算,所以開啟抗鋸齒不會有很明顯的性能影響,但如果你在模擬器或者低端機型上測試就會發現一點問題。

PS4:

有人問到transformImageBitmap()中這倆句話是什么意思:

imageMatrix.preTranslate(-(imageWidth / 2), -(imageHeight / 2));imageMatrix.postTranslate((imageWidth / 2), (imageHeight / 2));

個人的理解如下:

preTranslate相當于在對圖像進行任何矩陣變換前先進行preTranslate,postTranslate相反,進行所有變換后再執行postTranlate。
這倆句的意思是:在做任何變換前,先將整個圖像從圖像的中心點移動到原點((0,0)點),執行變換完畢后再將圖像從原點移動到之前的中心點。
如果不加這倆句,任何變換將以圖像的原點為變換中心點,加了之后,任何變換都將以圖像的中心點為變換中心點。
舉個例子,對圖像進行旋轉,需要倆個參數:一個是旋轉的角度,另一個是旋轉中心的坐標。旋轉中心的坐標影響旋轉的效果。這個能明白嗎?你拿一根棍子,拿著棍子的一端進行旋轉和拿在棍子中間旋轉,是不一樣的。preTranslate和postTranslate執行后對圖像本身不會有影響,影響的是對圖像進行變換時的旋轉軸。
說了這么多有點繞,其實就是矩陣變換的知識。

PS5 ON PS2:

這個問題在google group下有過很充分的討論,貌似一般只在debug模式下存在?,F在我使用這段代碼沒有出現OOM問題了

希望本文所述對大家Android程序設計有所幫助。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
久久影视电视剧凤归四时歌| 欧美激情视频三区| 欧美午夜精品久久久久久久| 午夜欧美大片免费观看| 亚洲美女又黄又爽在线观看| 亚洲男人天堂2023| 国产精品黄色影片导航在线观看| 欧美与黑人午夜性猛交久久久| 久久久成人的性感天堂| 国产欧美亚洲视频| 福利一区福利二区微拍刺激| 欧美国产日韩在线| 日韩欧美国产成人| 久久久久久久爱| 久热精品视频在线免费观看| 欧美激情图片区| 高清亚洲成在人网站天堂| 亚洲美女中文字幕| 久久久久久国产免费| 中文字幕欧美国内| 色琪琪综合男人的天堂aⅴ视频| 欧美大片在线影院| 日本精品性网站在线观看| 欧美日韩国产一区二区| 久久亚洲国产精品成人av秋霞| 久久99热这里只有精品国产| 亚洲成色777777女色窝| 精品国产乱码久久久久久天美| 日韩中文字幕欧美| 欧美影院在线播放| 91沈先生作品| 国内精品在线一区| 国产成人啪精品视频免费网| 国产成人精品在线观看| 亚洲少妇中文在线| 日韩精品中文在线观看| 爽爽爽爽爽爽爽成人免费观看| 日韩欧美成人免费视频| 欧美xxxx14xxxxx性爽| 欧美成年人在线观看| 久久99久久99精品免观看粉嫩| 欧美韩日一区二区| 久久影视电视剧免费网站清宫辞电视| 色噜噜狠狠狠综合曰曰曰| 日韩免费观看视频| 欧美激情视频网站| 欧美大片欧美激情性色a∨久久| 午夜精品一区二区三区在线视| 亚洲一区第一页| 国产主播在线一区| 夜夜嗨av色一区二区不卡| 在线激情影院一区| 欧美色欧美亚洲高清在线视频| 国产视频精品一区二区三区| 国产丝袜一区视频在线观看| 欧美日韩第一视频| 日韩精品在线视频| 欧美视频在线视频| 久久最新资源网| 久久影院模特热| 日本一区二区不卡| 色播久久人人爽人人爽人人片视av| 全色精品综合影院| 国产精品国产三级国产aⅴ9色| 欧美极品少妇xxxxⅹ免费视频| 欧美—级高清免费播放| 欧美精品一区二区免费| 在线播放日韩专区| 国模精品一区二区三区色天香| 久久久久久亚洲精品| 欧美日韩电影在线观看| 国产精品99久久久久久久久| 欧美大片欧美激情性色a∨久久| 日韩精品视频免费在线观看| 国内精品免费午夜毛片| 亚洲精品视频在线观看视频| 亚洲欧美日本另类| 亚洲精品成人网| 欧美有码在线观看| 亚洲一区二区久久久| 激情久久av一区av二区av三区| 在线播放精品一区二区三区| 午夜剧场成人观在线视频免费观看| 欧美成人亚洲成人日韩成人| 最近2019中文免费高清视频观看www99| 久久理论片午夜琪琪电影网| 亚洲jizzjizz日本少妇| 日韩欧美综合在线视频| 日韩av网址在线| 日韩精品在线观看网站| 亚洲欧美日韩一区二区在线| 日本老师69xxx| 精品国产一区久久久| 日韩中文字幕国产| 97在线视频免费看| 国产精品亚洲欧美导航| 欧美一级电影在线| 国产一区视频在线| 亚洲国产精品资源| 亚洲国内精品在线| 久久久人成影片一区二区三区| 国产精品免费久久久久影院| 久久免费视频在线观看| 成人h视频在线观看播放| 欧美区二区三区| 日韩成人中文字幕在线观看| 日韩av在线网站| 国产欧美日韩综合精品| 久久久久久这里只有精品| 中文字幕精品av| 欧美在线影院在线视频| 亚洲欧洲在线免费| 久久91超碰青草是什么| 日韩中文字幕av| 欧美成aaa人片在线观看蜜臀| 日本成熟性欧美| 国产一区二区三区三区在线观看| 另类少妇人与禽zozz0性伦| 欧洲亚洲女同hd| 国产精品久久999| 亚洲欧洲第一视频| 久久久久久久爱| 国产精品v日韩精品| 97视频网站入口| 亚洲bt欧美bt日本bt| 欧美视频专区一二在线观看| 91av在线网站| 久久99亚洲热视| 亚洲精品福利视频| 欧美激情a∨在线视频播放| 亚洲二区在线播放视频| 久热爱精品视频线路一| 黑人巨大精品欧美一区二区一视频| 欧美性感美女h网站在线观看免费| 日韩美女免费视频| 欧美一区二区色| 揄拍成人国产精品视频| 另类图片亚洲另类| 欧美中文字幕在线观看| 精品视频一区在线视频| 国产热re99久久6国产精品| 78色国产精品| 神马久久桃色视频| 国产69久久精品成人| 91久久夜色精品国产网站| 中文字幕亚洲第一| 亚洲国产精品久久精品怡红院| 久久亚洲综合国产精品99麻豆精品福利| 91免费人成网站在线观看18| 成人免费视频a| 欧美老女人xx| 国产精品免费看久久久香蕉| 国产ts人妖一区二区三区| 成人写真视频福利网| 午夜免费久久久久| 国产成人精品av| 欧美成人精品一区二区| 美女撒尿一区二区三区| 美日韩丰满少妇在线观看| 国产精品电影网| 国产a∨精品一区二区三区不卡| 久99九色视频在线观看| 亚洲美女在线看| 久久久久久九九九|