Android Premium Sony Scrolling album _android

Source: Internet
Author: User
Tags abs

Although the Sony handset sells is not good, but some things still do well, the industrial design Needless to say, the Sony album's double finger arbitrary scaling function is also particularly cool. Its Desktop widget scrolling album I think it is also very good, than the original Google album Wall function is much better, online search did not find someone to write this, so, the following is the introduction of my high a goods.

The first is the effect chart:

The main gesture operations are:

1. Up/down full speed move, can slide/slide a picture
2. Up/down fast read move, then according to sliding speed, slide/slide more than one picture
3. Click the request system Gallery to show the picture

The main advantage of this widget is that it provides a good picture selection/browsing widget within a small area within the screen, especially when switching pictures with a strong proximity/distance from the animation, and increasing goodwill.

Code Analysis

Just beginning to think of this widget is to use a number of ImageView overlay implementation of the effect, such as Google's original component is the use of a number of imageview superimposed formation, but the effect is far less than this. But feel that through multiple imageview stacking may not be so smooth, performance is not good. The effect itself is also relatively regular, it should be through a view to achieve better performance. So through the view hierarchy analysis, Sony this really is through a view of the implementation, so through the following way this widget.

The code consists mainly of three parts:

Rollimageview: The actual view
cellcalculater: Used to calculate the area and transparency of each picture in real time, which is the core part of this widget. The interface is defined as follows:

  * Get all rects for drawing image
  * @return
 cell[] Getcells ();

  * @param distance the motion distance during the period from Action_down to this moment
  * @return 0 mean s no roll, positive number means roll forward and negative means roll backward
 /public int setstatus (FLOAT dist ance);

  * Set the dimen of view
  * @param widht
  * @param height
 /public void setdimen (int widht, int height);

  * Set to the status for static
 /public void setstatic ();

imageloader: Used to load pictures, provide bitmap for rollimageview rendering. The interface is defined as follows:

  * The images shown roll forward
 /public void Rollforward ();

  * The images shown roll backward
 /public void Rollbackward ();

  * Get bitmaps
  * @return
 /public bitmap[] Getbitmap ();

  * Use invalidate to invalidate the view
  * @param invalidate
 /public void Setinvalidate ( Rollimageview.invalidateview invalidate);

  * Set the dimen of view
  * @param width
  * @param height
 /public void setdimen (int width, int height);

  * The image path to is show
  * @param paths
 /public void setimagepaths (list<string> paths) ;

  * Get large bitmap while static
 /public void Loadcurrentlargebitmap (); 

The core code for each section is analyzed below.

The main responsibility of view is to draw each bitmap and respond to the user's gesture operation, relatively simple.
The drawing part is to draw the various bitmap obtained from the Imageloader according to the drawing area and the transparency which obtains from the Cellcalculater to the screen, the present code realizes relatively simple, does not consider the different size picture needs to carry on some more coordinated display way, For example, some of the display methods as defined in Imageview.scaletype.

@Override public
 void OnDraw (Canvas Canvas) {
  super.ondraw (Canvas);
  bitmap[] bitmaps = Mimageloader.getbitmap ();
  Cell[] cells = Mcellcalculator.getcells (); The display area of each image is obtained with transparency
  canvas.translate (getwidth ()/2, 0);
  for (int i = show_cnt-1 i >= 0; i--) {//Draw
   Bitmap Bitmap = bitmaps[i] from the bottommost image;
   Cell cell = Cells[i];
   if (bitmap!= null &&!bitmap.isrecycled ()) {
    Mpaint.setalpha (Cell.getalpha ());
    LOG ("OnDraw" + i + bitmap.getwidth () + "" + CELL.GETRECTF () + "alpha" + Cell.getalpha ());
    Canvas.drawbitmap (bitmap, NULL, CELL.GETRECTF (), mpaint);

The gesture part uses the Gesturelistener, the main code is as follows:

@Override public boolean ontouchevent (Motionevent event) {if (Event.getpointercount () > 1) {return false;
  } mgesturedetector.ontouchevent (event); Switch (event.getaction ()) {case MOTIONEVENT.ACTION_UP://is mainly used to handle the state if (!misfling) {if) that keeps the interface from moving without triggering the fling event (Mrollresult = = Cellcalculator.roll_forward)
     {Mimageloader.rollforward ();
     else if (Mrollresult = = Cellcalculator.roll_backward &&!mscrollrollback) {mimageloader.rollbackward ();
     LOG ("Ongesturelistener action_up setstatic");
     Mcellcalculator.setstatic ();
    Mimageloader.loadcurrentlargebitmap ();
   } break;
 return true; //Slow Drag @Override public boolean onscroll (Motionevent E1, motionevent E2, float Distancex, float distancey) {mSc
  Rolldistance + = Distancey;
   if (mscrolldistance > 0 &&!mscrollrollback) {mimageloader.rollbackward ();
  Mscrollrollback = true; else if (Mscrolldistance < 0 && Mscrollrollback) {Mimageloader.rollforward ();
  Mscrollrollback = false;
  LOG ("Ongesturelistener onscroll" + Distancey + "all" + mscrolldistance);
  Mrollresult = Mcellcalculator.setstatus (-mscrolldistance);
  Invalidate ();
 return true; }//Quick drag @Override public boolean onfling (Motionevent E1, motionevent E2, float Velocityx, float velocityy) {if (M
   Ath.abs (VELOCITYY) > Min_fling) {LOG ("Ongesturelistener onfling" + velocityy);
   if (Mexecutorservice = = null) {Mexecutorservice = Executors.newsinglethreadexecutor ();
   } misfling = true;
  Mexecutorservice.submit (New Flingtask (Velocityy));
 return true;
  ///Use an asynchronous task to handle scrolling multiple images private class Flingtask implements Runnable {float mvelocity;
  float Mviewheight;
  int msleeptime;

  Boolean Mrollbackward;
   Flingtask (float velocity) {mrollbackward = velocity < 0? true:false;
   mvelocity = Math.Abs (VELOCITY/4);
   Mviewheight = RollImageView.this.getHeight ()/2; Msleeptime = (int) (4000/math.abs (Velocity) * 100);
   The slower velocity of fling, the longer interval for roll} @Override public void Run () {int i = 0;
     try{while (Mvelocity > Mviewheight) {mcellcalculator.setstatus (mrollbackward?-mviewheight:mviewheight);
     Mhandler.sendemptymessage (msg_invalate); Determines the count of roll.
     The using of mviewheight has no strictly logical mvelocity-= Mviewheight; if (((i++) & 1) = = 0) {//roll forward once for every two setstatus if (mrollbackward) {MIMAGELOADER.ROLLB
      Ackward ();
      }else {Mimageloader.rollforward ();
    } thread.sleep (Msleeptime);
    } mcellcalculator.setstatic ();
    Mimageloader.loadcurrentlargebitmap ();
   Mhandler.sendemptymessage (msg_invalate);

 catch (Exception e) {} finally{}}

Cellcalculater Analysis

First, the concept of moving forward/backward is clarified. The picture path that needs to be displayed is stored as a list, assuming that the index of the first picture is indexed, the currently displayed picture is [index,index+3], and the forward indicates index plus 1, and the index minus 1 is backward.

The calculation of Cellcalculater is mainly based on the user's gesture, which expresses the intention to move a picture forward or backward. What can be obtained in view is only the distance of gesture movement, so it is necessary to process the moving distance in the Cellcalculater and output the moving result. In my implementation, when the move is more than half the height of the picture, it means that the displayed picture needs to move one bit, otherwise it will be set to static when the gesture is finished. The main code is as follows:

Public defaultcellcalculator (int showcnt) {mcnt = showcnt;
  Mcells = new CELL[MCNT];
  Malphas = new FLOAT[MCNT];
  Static_alpha = new INT[MCNT]; Static_alpha[mcnt-1] = 0;
  The transparency of the last picture is 0 int alphaunit = (255-first_alpha)/(mCnt-2);
  for (int i = mCnt-2 i >= 0; i--) {//define static when the transparency of each chart static_alpha[i] = First_alpha + (mCnt-2-i) * ALPHAUNIT;
 }} @Override public cell[] Getcells () {return mcells;
   }//user gesture movement, distance indicates moving distance, plus or minus value means the need to move forward/backward @Override public int setstatus (float distance) {if (distance > 0) {
  return Calculateforward (distance);
  else if (distance < 0) {return calculatebackward (distance);
  } else{initcells ();
 return 0;
  //Set the size of the Rollimageview to calculate the appropriate display area @Override public void setdimen (int widht, int height) {mviewwidth = WIDHT;
  Mviewheight = height;
  mwidhtindent = (int) (widht_indent * mviewwidth);
  Mwidths = new INT[MCNT]; for (int i = 0; i < mcnt i++) {Mwidths[i] = Mviewwidth-i * MwidhtindenT
  ///height of each picture.
  If the display of four charts, then there will be three height drop, and then the bottom to retain a height drop, so it is mcnt-1 mimageheight = mviewheight-(mCnt-1) * height_indent;
  LOG ("Mimageheight" + mimageheight);
 Initcells ();
 }//Static, that is @Override public void setstatic () {initcells () at the end of the user gesture operation;
  }//The user has the tendency to move one bit forward private int calculateforward (float status) {float scale = status/mimageheight;
  LOG ("scale" + scale + "Mimageheight" + mimageheight + "status" + status); for (int i = 1; i < mcnt i++) {mcells[i].setwidth (interpolate (Scale * 3, mwidths[i], mwidths[i-1));//*3 make the rear width Rapid increase, experience value mcells[i].movevertical (interpolate (Scale *, 0, height_indent));
  *10 makes the back of the picture quickly forward, the forward animation sense stronger mcells[i].setalpha ((int) interpolate (scale, static_alpha[i], static_alpha[i-1));
  } mcells[0].movevertical (status);
  Mcells[0].setalpha ((int) interpolate (scale, 255, 0));
  if (status >= MIMAGEHEIGHT/3) {return roll_forward;
  else {return 0; }//The user has the tendency to move one bit backward private int Calculatebackward (floAt status) {Float scale = Math.Abs (status/mimageheight);
   for (int i = 1; i < mcnt i++) {mcells[i].setwidth (interpolate (scale, mwidths[i-1], mwidths[i));
   Mcells[i].movevertical (-scale * height_indent);
  Mcells[i].setalpha ((int) interpolate (scale, static_alpha[i-1), Static_alpha[i]);
  } mcells[0].resetrect ();
  Mcells[0].setwidth (Mwidths[0]);
  Mcells[0].setheight (Mimageheight);
  Mcells[0].movevertical (mimageheight + status);
  Mcells[0].setalpha ((int) interpolate (scale, 0, 255));
  if (-status >= mimageheight/3) {return roll_backward;
  else {return 0;
  }/** * Status without move */private void Initcells () {int top =-height_indent;
   for (int i = 0; i < mcnt i++) {RECTF RECTF = new RECTF (0,0,0,0); = top + (mCnt-1-i) * height_indent;
   Rectf.bottom = + mimageheight;
   Mcells[i] = new Cell (RECTF, static_alpha[i]);
  Mcells[i].setwidth (Mwidths[i]); Calculated difference Private float interpolate (float scalE, float start, float end) {if (Scale > 1) {scale = 1;
 Return start + scale * (End-start);


Imageloader Analysis
Imageloader is actually relatively simple, mainly with the following two points:
• Respond to gestures to handle bitmap requests that correspond to forward/backward movements
• When the gesture is still in operation, should load small map, and so on after the gesture operation is over, should load large image. Because only when moving slowly, need to show clearly, and fast moving, show small figure can, so need to load the current index and forward backward a picture.

Load the current index and forward backward three large figure @Override public void Loadcurrentlargebitmap () {for (int i = MCurrentIndex-1 I < mcurrent Index + 2;
   i++) {if (i >= 0 && i < mImagesCnt-1) {Mbitmapcache.getlargebitmap (mallimagepaths[i]);
  //index to move forward one @Override public void Rollforward () {LOG ("Rollforward");
  if (Mcurrentindex > mImagesCnt-1) {mcurrentindex = mImagesCnt-1;
 } setcurrentpaths ();
  //index to move back one @Override public void Rollbackward () {LOG ("Rollbackward");
  if (Mcurrentindex < 0) {Mcurrentindex = 0;
 } setcurrentpaths ();
   @Override public bitmap[] Getbitmap () {if (mcurrentpaths!= null) {LOG ("Getbitmap Paths nut null"); for (int i = mcurrentindex, j = 0 J < mshowcnt + +, i++) {if (i >= 0 && i < mimagescnt) {Mcurren
    TBITMAPS[J] = Mbitmapcache.getbimap (Mallimagepaths[i]);
    } else{Mcurrentbitmaps[j] = Mbitmapcache.getbimap (No_path);
   }} return mcurrentbitmaps;


Finally, all source code: Https://

The above is the entire content of this article, I hope to help you learn, but also hope that we support the cloud habitat community.

Related Article

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: 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.