Android Browse image, click to enlarge to full screen effect

Source: Internet
Author: User

Recently do a project similar to QQ space, so that the function of photo browsing, for the QQ space click the picture to enlarge to full screen, feel the effect is great, so also did a similar effect. As follows.



I do not know QQ that is how to do, my train of thought is as follows:

First, from the image thumbnail interface to jump to the picture Details page, should be from one activity to another activity, should be the picture Detail page also has a lot of operations, with view or dialog is not very good. So now the difficulty is how to make the ImageView of the previous interface do a scaled cut animation in another interface.

The ImageView of the general abbreviation interface is the square as shown, and is the Center_crop scaling property. The Center_crop property causes the bitmap shown in ImageView to have the effect of being cut to fill.

The ImageView of the detail page is generally the Fit_center zoom attribute. So to ensure that this jump rotation of the smooth painting, to do the following changes:

1, Bitmap zoom, because the thumbnail and detail diagram of the scale certainly not the same

2, bitmap the position of the translation, because the position of the thumbnail is uncertain, we want to make him pan to the middle

3, bitmap cutting, because Center_crop is cut, and fit_center is not cut, then the two images show the content area is different, so also to show the smooth transformation of the area.


To achieve the above effect, if simply refers to the ImageView to do an animated transformation, I think it is not complete this requirement. So I rewrote the ImageView to complete the above transformations.

Directly affixed to the main ImageView

Package Com.roamer.ui.view;import Android.animation.animator;import Android.animation.propertyvaluesholder;import Android.animation.valueanimator;import Android.app.activity;import Android.content.context;import Android.graphics.bitmap;import Android.graphics.canvas;import Android.graphics.matrix;import Android.graphics.paint;import Android.graphics.paint.style;import android.graphics.drawable.BitmapDrawable; Import Android.util.attributeset;import Android.util.log;import Android.view.animation.acceleratedecelerateinterpolator;import android.widget.imageview;/** * The ImageView of a 2d smooth-changing display image is limited to: from one Scaletype==center_crop ImageView to another scaletype= Fit_center ImageView, or vice versa (of course, Have to use the same picture best) * * @author Dean Tao * */public class Smoothimageview extends ImageView {private static final int state_norm AL = 0;private static final int state_transform_in = 1;private static final int state_transform_out = 2;private int Morigi nalwidth;private int Moriginalheight;private int MORIGINALLOCATIONX;PRIvate int moriginallocationy;private int mstate = state_normal;private Matrix msmoothmatrix;private Bitmap mBitmap; Private Boolean Mtransformstart = False;private transfrom mtransfrom;private final int mbgcolor = 0xff000000;private int m Bgalpha = 0;private Paint mpaint;public Smoothimageview (context context) {super (context); init ();} Public Smoothimageview (context context, AttributeSet Attrs) {Super (context, attrs); init ();} Public Smoothimageview (context context, AttributeSet attrs, int defstyle) {Super (context, attrs, defstyle); init ();} private void Init () {Msmoothmatrix = new Matrix (); mpaint=new Paint (); Mpaint.setcolor (Mbgcolor); Mpaint.setstyle ( Style.fill);//setbackgroundcolor (Mbgcolor);}  public void Setoriginalinfo (int width, int height, int locationx, int locationy) {moriginalwidth = Width;moriginalheight = Height;moriginallocationx = Locationx;moriginallocationy = locationy;//because it is screen coordinates, it is converted to the coordinates within that view because the view I am using is Match_ PARENT, so you don't have to position the view, and if not, you need to position the view, and then calculate Moriginallocationx and MoriginallocAtionymoriginallocationy = Moriginallocationy-getstatusbarheight (GetContext ());} /** * Get status bar Height * * @return */public static int getstatusbarheight (context context) {class<?> c = Null;object obj = n Ull;java.lang.reflect.field Field = null;int x = 0;int Statusbarheight = 0;try {c = class.forname ("com.android.internal.r$ Dimen "); obj = C.newinstance (); field = C.getfield (" Status_bar_height "); x = Integer.parseint (Field.get (obj). toString () ); statusbarheight = Context.getresources (). getdimensionpixelsize (x); return statusbarheight;} catch (Exception e) {e.printstacktrace ();} return statusbarheight;} /** * The method used to start the entry. Before calling this party, you need to have called Setoriginalinfo */public void Transformin () {mstate = State_transform_in;mtransformstart = True;invalidate ();} /** * The method used to start exiting. Before calling this party, you need to have already called Setoriginalinfo */public void Transformout () {mstate = State_transform_out;mtransformstart = true; Invalidate ();} Private class Transfrom {float startscale;//picture start scale value float endscale;//picture End scale Value Float scale;//Property Valueanimator calculated Value LocaTionsizef startrect;//start Area Locationsizef endrect;//end of zone Locationsizef rect;//Property Valueanimator calculated value void InitStartIn () {scale = startscale;try {rect = (Locationsizef) startrect.clone ()} catch (Clonenotsupportedexception e) {E.printstack Trace ();}} void Initstartout () {scale = endscale;try {rect = (Locationsizef) endrect.clone ();} catch (Clonenotsupportedexception e) { E.printstacktrace ();}}} /** * Initialize the entered variable information */private void Inittransform () {if (getdrawable () = = null) {return;} if (Mbitmap = = NULL | | mbitmap.isrecycled ()) {Mbitmap = ((bitmapdrawable) getdrawable ()). Getbitmap (); Prevents Mtransfrom from repeating the same initialization if (mtransfrom! = null) {return;} if (getwidth () = = 0 | | getheight () = = 0) {return;} Mtransfrom = new Transfrom ()/** The following is the calculation of the scaling *//* calculate the initial scaling value, the initial value because it is the centr_crop effect, so to ensure that the width and height of the picture at least 1 can match the original width and height, the other 1 is greater than */float Xsscale = Moriginalwidth/((float) mbitmap.getwidth ()), float Ysscale = moriginalheight/((float) mbitmap.getheight ()); f Loat Startscale = xsscale > Ysscale? Xsscale:ysscale;mtransfrom.startscaLe = startscale;/* the zoom value at the end of the calculation, the end value because to achieve the fit_center effect, so to ensure that the width and height of the picture at least 1 can match the original width and height, the other 1 is less than */float Xescale = GetWidth ()/(( float) mbitmap.getwidth () Float Yescale = GetHeight ()/((float) mbitmap.getheight ()); float Endscale = Xescale < Yesca Le? Xescale:yescale;mtransfrom.endscale = endscale;/** * The range of canvas clip is calculated below, which is the extent of the picture being displayed, because the picture is slowly becoming larger and proportional, So this effect also needs to cut the area of the image display *, and the range of the display area is in the original Center_crop effect of the range of the area *, to the final fit_center of the range, the area I use Locationsizef better calculate *, he includes the top left vertex coordinates, and wide height, and finally to the canvas cut rect. *//* Start Area */mtransfrom.startrect = new Locationsizef (); mTransfrom.startRect.left = Moriginallocationx; MTransfrom.startRect.top = Moriginallocationy;mtransfrom.startrect.width = Moriginalwidth; MTransfrom.startRect.height = moriginalheight;/* End Area */mtransfrom.endrect = new Locationsizef (); Float bitmapendwidth = Mbitmap.getwidth () * mtransfrom.endscale;//picture final width float bitmapendheight = mbitmap.getheight () * mtransfrom.endscale;/ /Picture Final width MTransfrom.endRect.left = (getwidth ()-bitmapendwidth)/2;mtransfrom.endrecT.top = (getheight ()-bitmapendheight)/2;mtransfrom.endrect.width = Bitmapendwidth;mtransfrom.endrect.height = Bitmapendheight;mtransfrom.rect = new Locationsizef ();} Private class Locationsizef implements Cloneable{float left;float top;float width;float height; @Overridepublic String ToString () {return "[Left:" +left+ "Top:" +top+ "width:" +width+ "Height:" +height+ "]";} @Overridepublic Object Clone () throws Clonenotsupportedexception {//TODO auto-generated method Stubreturn Super.clone () ;}} /* Below implements the Center_crop function of the matrix, in the process of optimization, has not used */private void Getcentercropmatrix () {if (getdrawable () = = null) {return;} if (Mbitmap = = NULL | | mbitmap.isrecycled ()) {Mbitmap = ((bitmapdrawable) getdrawable ()). Getbitmap (); /* Below implements the function of the center_crop */float XScale = moriginalwidth/((float) mbitmap.getwidth ()), float Yscale = moriginalheight/((f loat) Mbitmap.getheight ()); float scale = XScale > Yscale? Xscale:yscale;msmoothmatrix.reset (); Msmoothmatrix.setscale (scale and scale); Msmoothmatrix.posttranslatE (-(Scale * mbitmap.getwidth ()/2-MORIGINALWIDTH/2),-(Scale * mbitmap.getheight ()/2-MORIGINALHEIGHT/2));} private void Getbmpmatrix () {if (getdrawable () = = null) {return;} if (Mtransfrom = = null) {return;} if (Mbitmap = = NULL | | mbitmap.isrecycled ()) {Mbitmap = ((bitmapdrawable) getdrawable ()). Getbitmap (); /* Below implements the function of Center_crop */msmoothmatrix.setscale (Mtransfrom.scale, Mtransfrom.scale); Msmoothmatrix.posttranslate (- (Mtransfrom.scale * mbitmap.getwidth ()/2-MTRANSFROM.RECT.WIDTH/2),-(Mtransfrom.scale * mbitmap.getheight ()/2-mtr ANSFROM.RECT.HEIGHT/2));} @Overrideprotected void OnDraw (canvas canvas) {if (getdrawable () = = null) {return;//couldn ' t resolve the uri}if (mstate = = State_transform_in | | Mstate = = state_transform_out) {if (Mtransformstart) {inittransform ();} if (Mtransfrom = = null) {Super.ondraw (canvas); return;} if (Mtransformstart) {if (mstate = = state_transform_in) {mtransfrom.initstartin ();} else {mtransfrom.initstartout ();}} if (Mtransformstart) {log.d ("Dean"," Mtransfrom.startscale: "+mtransfrom.startscale); LOG.D ("Dean", "Mtransfrom.startscale:" +mtransfrom.endscale); LOG.D ("Dean", "Mtransfrom.scale:" +mtransfrom.scale); LOG.D ("Dean", "Mtransfrom.startrect:" +mtransfrom.startrect.tostring ()); LOG.D ("Dean", "Mtransfrom.endrect:" +mtransfrom.endrect.tostring ()); LOG.D ("Dean", "Mtransfrom.rect:" +mtransfrom.rect.tostring ());} Mpaint.setalpha (Mbgalpha); Canvas.drawpaint (mpaint); int savecount = Canvas.getsavecount (); Canvas.save ();// First get the picture at the moment of the image Matrix Matrix Getbmpmatrix (); Canvas.translate (MTransfrom.rect.left, mTransfrom.rect.top); Canvas.cliprect (0 , 0, MTransfrom.rect.width, mTransfrom.rect.height); Canvas.concat (Msmoothmatrix); getdrawable (). Draw (canvas); Canvas.restoretocount (Savecount); if (Mtransformstart) {mtransformstart=false;starttransform (mState);}} else {//when the transform in change is complete, the background is changed to black, making the activity opaque mpaint.setalpha (255); Canvas.drawpaint (Mpaint); Super.ondraw ( canvas);}} private void Starttransform (final int state) {if (Mtransfrom = = null) {return;} ValueanimatoR valueanimator = new Valueanimator (); valueanimator.setduration; Valueanimator.setinterpolator (new Acceleratedecelerateinterpolator ()), if (state = = state_transform_in) {Propertyvaluesholder Scaleholder = Propertyvaluesholder.offloat ("scale", Mtransfrom.startscale, Mtransfrom.endscale); Propertyvaluesholder Leftholder = Propertyvaluesholder.offloat ("Left", MTransfrom.startRect.left, MTransfrom.endRect.left); Propertyvaluesholder Topholder = propertyvaluesholder.offloat ("Top", MTransfrom.startRect.top, MTransfrom.endRect.top); Propertyvaluesholder Widthholder = propertyvaluesholder.offloat ("width", mTransfrom.startRect.width, MTransfrom.endRect.width); Propertyvaluesholder Heightholder = propertyvaluesholder.offloat ("height", mTransfrom.startRect.height, MTransfrom.endRect.height); Propertyvaluesholder Alphaholder = propertyvaluesholder.ofint ("Alpha", 0, 255); Valueanimator.setvalues (ScaleHolder, Leftholder, Topholder, Widthholder, Heightholder, Alphaholder);} else {Propertyvaluesholder SCAleholder = propertyvaluesholder.offloat ("scale", Mtransfrom.endscale, Mtransfrom.startscale); Propertyvaluesholder Leftholder = Propertyvaluesholder.offloat ("Left", MTransfrom.endRect.left, MTransfrom.startRect.left); Propertyvaluesholder Topholder = propertyvaluesholder.offloat ("Top", MTransfrom.endRect.top, MTransfrom.startRect.top); Propertyvaluesholder Widthholder = propertyvaluesholder.offloat ("width", mTransfrom.endRect.width, MTransfrom.startRect.width); Propertyvaluesholder Heightholder = propertyvaluesholder.offloat ("height", mTransfrom.endRect.height, MTransfrom.startRect.height); Propertyvaluesholder Alphaholder = propertyvaluesholder.ofint ("Alpha", 255, 0); Valueanimator.setvalues (ScaleHolder, Leftholder, Topholder, Widthholder, Heightholder, Alphaholder);} Valueanimator.addupdatelistener (New Valueanimator.animatorupdatelistener () {@Overridepublic synchronized void Onanimationupdate (Valueanimator animation) {Mtransfrom.scale = (Float) animation.getanimatedvalue ("scale"); MtransfroM.rect.left = (float) animation.getanimatedvalue ("left"), MTransfrom.rect.top = (float) animation.getanimatedvalue (" Top ") MTransfrom.rect.width = (float) animation.getanimatedvalue (" width "); mTransfrom.rect.height = (float) Animation.getanimatedvalue ("height"); mbgalpha = (Integer) animation.getanimatedvalue ("alpha"); invalidate ();(( Activity). GetContext ()). GetWindow (). Getdecorview (). invalidate ();}); Valueanimator.addlistener (New Valueanimator.animatorlistener () {@Overridepublic void Onanimationstart (Animator Animation) {} @Overridepublic void Onanimationrepeat (Animator animation) {} @Overridepublic void Onanimationend ( Animator animation) {/* * * If you enter, of course, you want to stay in the Center_crop area. But if it is out, it should not be the position of the center_crop *, but should be the last change in position, because when the end of the out, not reply to the view is normal, or there will be a sudden flash back to the bug *///TODO This can be modified according to the actual needs of if (state = = state_transform_in) {mstate = State_normal;} if (Mtransformlistener! = null) {Mtransformlistener.ontransformcomplete (state);}} @Overridepublic void Onanimationcancel (Animator animation) {}});Animator.start ();} public void Setontransformlistener (Transformlistener listener) {Mtransformlistener = listener;}            Private Transformlistener Mtransformlistener;public Static interface Transformlistener {/** * * @param mode * State_transform_in 1, state_transform_out 2 */void ontransformcomplete (int mode);//Mode 1}}

When used, the previous activity passes to the details of the activity following several key messages:

Intent Intent = new Intent (mainactivity.this, Spaceimagedetailactivity.class); Intent.putextra ("Images", ArrayList <String>) datas);//Must not Intent.putextra ("position", position); int[] location = new INT[2]; Imageview.getlocationonscreen (location), Intent.putextra ("Locationx", location[0]);//Must Intent.putextra (" Locationy ", location[1]);//Must Be Intent.putextra (" width ", imageview.getwidth ());//Must be Intent.putextra (" height ", Imageview.getheight ());//must startactivity (intent); overridependingtransition (0, 0);

In the details the activity takes these parameters and initializes the location information to the Smoothimageview, which can then be changed.

Mdatas = (arraylist<string>) getintent (). Getserializableextra ("Images"); mposition = Getintent (). GetIntExtra (" Position ", 0); Mlocationx = Getintent (). Getintextra (" Locationx ", 0); mlocationy = Getintent (). Getintextra (" Locationy ", 0); mwidth = Getintent (). Getintextra ("width", 0); mheight = Getintent (). Getintextra ("height", 0); ImageView = new Smoothimageview (this); Imageview.setoriginalinfo (Mwidth, Mheight, Mlocationx, mlocationy); Imageview.transformin (); Imageview.setlayoutparams (New Viewgroup.layoutparams ( -1,-1)); Imageview.setscaletype (Scaletype.fit_center); Setcontentview (ImageView); Imageloader.getinstance (). DisplayImage (Mdatas.get (mposition), ImageView);



The above has already completed the image zoom effect, but also need to set the activity transparent style, in order to make the alpha effect experience, the user experience is better.

The activity is set in the following style, in addition, there is no location to locate the view in Smoothimageview, just do the status bar processing, so to set the activity as Notitlebar, the specific style is as follows:

<style name= "Imtheme.transparent" >        <item name= "Android:windowbackground" > @android: color/ transparent</item>        <item name= "android:windowistranslucent" >true</item>        <item name= "Android:windownotitle" >true</item>        <item name= "Android:windowcontentoverlay" > @null </item ></style>



Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.