Although there are many online articles, but this effect is few and far between, I sincerely offer for your reference
Implementation principle: Custom ImageView The control to the appropriate layout (dynamic layout).
Here you need to understand several ways to execute the process:
First ImageView is the subclass that inherits from view.
OnLayout Method: is a callback method. This method executes in the layout method in view, and the Setframe method is first executed before the layout method is executed.
Setframe Method: To determine if our view has changed, and if so, to pass the latest l,t,r,b to view, and then refresh to dynamically update the UI. and return to ture. No change returns false.
Before we introduce our custom controls, we need to understand what data we want to get: the width of the screen, the height of the screen . (In fact, you can also viewtreeobserver the linerlayout to get its wide height.), the width and height of the original picture itself, and the maximum minimum value we scaled.
First we'll rewrite the Setimagebitmap method. Function: To get the width of the picture, to find the scaling limit value.
/***
* Settings Display picture * *
@Override public
void Setimagebitmap (Bitmap bm) {
super.setimagebitmap (BM);
/** Get picture width high **/
bitmap_w = Bm.getwidth ();
Bitmap_h = Bm.getheight ();
Max_w = Bitmap_w * 3;
Max_h = Bitmap_h * 3;
Min_w = BITMAP_W/2;
Min_h = BITMAP_H/2;
}
Then we get the initial l,t,r,b in the OnLayout method.
@Override
protected void OnLayout (Boolean changed, int left, int. top, int right,
int bottom) {
Super.onlay Out (changed, left, top, right, bottom);
if (start_top = = 1) {
start_top = top;
Start_left = left;
Start_bottom = Bottom;
Start_right = right;
}
Below we next the key touch method. In fact, we all understand that to say difficult words is estimated to be the logical realization.
say before you understand the difference between a single point and a multiple point:
single finger operation: action_down---action_move----action_up
Multi-finger operation: action_down---action_pointer_down---action_move--action_pointer_up---action_up.
above is simply the next process, please study in detail, this is only explained if used.
/***
* Touch event
/@Override public
boolean ontouchevent (Motionevent event) {
/** processing single point, Multi-Touch **/
switch (event.getaction () & Motionevent.action_mask) {case
Motionevent.action_down:
ontouchdown ( event);
break;
Multi-point Touch case
Motionevent.action_pointer_down:
onpointerdown (event);
break;
Case Motionevent.action_move:
ontouchmove (event);
break;
Case MOTIONEVENT.ACTION_UP:
mode = mode. NONE;
break;
Multi-point release case
motionevent.action_pointer_up:
mode = mode. NONE;
/** perform scaling restore **/
if (isscaleanim) {
doscaleanim ();
}
break;
return true;
}
Here's the realization I have written separately, is advantageous for everybody's viewing, here I by the way the custom control returns the value: if for the control that does not have child, if want to return to touch processing best True. This is often used in game development, if the control has children, do not do so, or the child will not listen to touch events.
Here's one way to look at it:
Ontouchdown: Gets the starting coordinates of the finger when clicked.
/** Press **/
void Ontouchdown (Motionevent event) {
mode = mode. DRAG;
current_x = (int) event.getrawx ();
current_y = (int) event.getrawy ();
start_x = (int) event.getx ();
start_y = Current_y-this.gettop ();
Here we also want to understand EVENT.GETRAWX () and Event.getx (), but I believe that we all understand, I was in front of the ListView drag also mentioned. A relative screen, a relative parent control.
Onpointerdown: Two The distance between the fingers.
/** two fingers can only be magnified **/
void Onpointerdown (Motionevent event) {
if (event.getpointercount () = = 2) {
mode = mode. ZOOM;
Beforelenght = Getdistance (event);//Get two-point distance
}
Ontouchmove: The handling of the move.
/** Mobile processing **/void Ontouchmove (Motionevent event) {int left = 0, top = 0, right = 0, bottom = 0; /** handles drag **/if (mode = = mode.
DRAG) {/** Here to judge the processing, to prevent the DRAG when the Cross-border **//** to obtain the corresponding l,t,r, b **/left = current_x-start_x;
right = current_x + this.getwidth ()-start_x;
top = current_y-start_y;
Bottom = current_y-start_y + this.getheight ();
/** level is judged **/if (iscontrol_h) {if (left >= 0) {left = 0;
right = This.getwidth ();
} if (right <= screen_w) {left = Screen_w-this.getwidth ();
right = Screen_w;
} else {left = This.getleft ();
right = This.getright ();
/** Vertical Judgment **/if (iscontrol_v) {if (top >= 0) {top = 0;
Bottom = This.getheight ();
} if (bottom <= screen_h) {top = Screen_h-this.getheight ();
bottom = Screen_h; } else {top = this.GetTop ();
Bottom = This.getbottom ();
if (Iscontrol_h | | iscontrol_v) this.setposition (left, top, right, bottom);
current_x = (int) event.getrawx ();
current_y = (int) Event.getrawy (); /** handles scaling **/else if (mode = = mode.
ZOOM) {afterlenght = Getdistance (event);//get distance of two points float gaplenght = afterlenght-beforelenght;//change length if (Math.Abs (gaplenght) > 5f) {scale_temp = afterlenght/beforelenght;//scaling proportional This.setscale (s
CALE_TEMP);
Beforelenght = Afterlenght;
}
}
}
The logic of processing more numerous, but most of the appeal code has been commented, I believe we all understand, we can grasp the principle of their own logic to deal with.
Let's take a look at the scaling process because of the cross-border or not.
Setscale Method:
/** processing scaling **/void Setscale (float scale) {int disx = (int) (This.getwidth () * Math.Abs (1-scale))/4;//Get zoom horizontal distance away from int disy = (int) (This.getheight () * Math.Abs (1-scale))/4;//Get zoom vertical distance/Enlarge if (Scale > 1 && Amp
This.getwidth () <= max_w) {current_left = This.getleft ()-DISX;
Current_top = This.gettop ()-Disy;
Current_right = this.getright () + Disx;
Current_bottom = This.getbottom () + Disy;
This.setframe (Current_left, Current_top, Current_right, Current_bottom);
/*** * At this time because of the symmetry, so just do it once again to judge. */if (current_top <= 0 && current_bottom >= screen_h) {log.e ("JJ", "screen height =" + This.getheigh
T ());
Iscontrol_v = true;//Open Vertical Monitor} else {iscontrol_v = false;
} if (current_left <= 0 && current_right >= screen_w) {iscontrol_h = true;//Open Level Monitor
else {iscontrol_h = false; }
}//Reduce else if (Scale < 1 && this.getwidth () >= min_w) {current_left = This.getlef
T () + DISX;
Current_top = This.gettop () + Disy;
Current_right = This.getright ()-DISX;
Current_bottom = This.getbottom ()-Disy; /*** * HERE to zoom processing *//Top Border crossing if (Iscontrol_v && current_top > 0) {Curre
nt_top = 0;
Current_bottom = This.getbottom ()-2 * DISY;
if (Current_bottom < Screen_h) {current_bottom = Screen_h; Iscontrol_v = false;//Turn off vertical listening}//Bottom Border if (Iscontrol_v && Current_bottom < SCR
Een_h) {current_bottom = Screen_h;
Current_top = This.gettop () + 2 * DISY;
if (Current_top > 0) {current_top = 0; Iscontrol_v = false;//Turn off vertical listening}//left Border crossing if (iscontrol_h && current_left >= 0) {Current_left= 0;
Current_right = This.getright ()-2 * DISX;
if (current_right <= screen_w) {current_right = Screen_w; Iscontrol_h = false;//Close}//Right Border crossing if (iscontrol_h && current_right <= screen_
W) {current_right = Screen_w;
Current_left = This.getleft () + 2 * DISX;
if (current_left >= 0) {current_left = 0; Iscontrol_h = false;//Close}} if (Iscontrol_h | | iscontrol_v) {this.setframe (current_le
FT, Current_top, Current_right, Current_bottom);
else {this.setframe (current_left, Current_top, Current_right, Current_bottom);
Isscaleanim = true;//Toggle Zoom Animation}}}
First we look at the amplification method : Here we have to constantly monitor whether horizontal or vertical has been covered (in fact, should be described as a layout), if paved or more than the corresponding horizontal or vertical direction can be carried. The code comment is clear. You can read the notes above.
Next we look at the narrowing , which is a little bit more complicated. First we have to consider the enlarged drag, in this case, we are sure to l,t,r,b they will not shrink to the screen boundary at the same time, so this is the process, if one side first indented to the screen boundary, then you stop to wait for your opposite (remember that at this time you zoom in the opposite rate is twice times the original, Otherwise, the picture will be distorted. Let's think about it, and wait until you're on the other side of the screen, and then turn off the monitor. And then the two of you are huddled together. That's how it works.
Not too clear, we can see the above code, I believe that we all see clearly.
Finally, we have to achieve the scaling back effect (more humane.)
At first I thought of scaleanimation, but half of the problem came up, I shrink back to the end of the animation she automatically returned to the original size, perhaps you will say that you add less setfillafter (true); But after adding the strange phenomenon will appear: again will cover a layer, the reason is unknown, we can try. Since the API to the animation can not achieve, then I do it myself. See the implementation below.
myasynctask asynchronous class.
/*** * Rollback Animation Execute */class Myasynctask extends Asynctask<void, Integer, void> {private int screen_w, C
Urrent_width, Current_height;
private int left, top, right, bottom; Private float scale_wh;//width high proportional/** Current position attribute **/public void setltrb (int left, int top, int right, int bottom)
{this.left = left;
This.top = top;
This.right = right;
This.bottom = bottom; Private float step = 5f;//pace private float step_h, step_v;//horizontal step, vertical pace public myasynctask (int scre
En_w, int current_width, int current_height) {super ();
This.screen_w = Screen_w;
This.current_width = Current_width;
This.current_height = Current_height;
SCALE_WH = (float) current_height/current_width;
Step_h = step;
Step_v = Scale_wh * STEP;
} @Override protected void Doinbackground (void ... params) {while (Current_width <= screen_w) { Left-=Step_h;
Top-= Step_v;
Right + = Step_h;
Bottom + = Step_v;
Current_width + + 2 * STEP_H;
left = Math.max (left, start_left);
top = Math.max (top, start_top);
right = Math.min (right, start_right);
Bottom = Math.min (bottom, start_bottom);
Onprogressupdate (new integer[] {left, top, right, bottom});
try {thread.sleep (10);
catch (Interruptedexception e) {e.printstacktrace ();
} return null;
} @Override protected void Onprogressupdate (final Integer ... values) {super.onprogressupdate (values); Mactivity.runonuithread (New Runnable () {@Override public void run () {Setframe (values
[0], values[1], values[2], values[3]);
}
});
}
}
I will not explain this in detail, we should pay attention to the horizontal and vertical speed.
Finally we look at the layout, the call is quite simple, but also help us add a secondary UI, do not forget to write android:scaletype= "Fitxy" This sentence, or sometimes there will be strange phenomenon.
<?xml version= "1.0" encoding= "Utf-8"?> <linearlayout xmlns:android=
"http://schemas.android.com/apk/" Res/android "
android:layout_width=" fill_parent "
android:layout_height=" Fill_parent "
android: gravity= "center" >
<com.jj.drag.dragimageview
android:id= "@+id/div_main"
android:layout_width = "Wrap_content"
android:layout_height= "wrap_content"
android:scaletype= "Fitxy"
/>
</ Linearlayout>
Called in acitivity:
/** Measurement status bar height **/
viewtreeobserver = Dragimageview.getviewtreeobserver ();
Viewtreeobserver
. Addongloballayoutlistener (New Ongloballayoutlistener () {
@Override public
Void Ongloballayout () {
if (state_height = = 0) {
//Get Status column height
Rect frame = new Rect ();
GetWindow (). Getdecorview ().
getwindowvisibledisplayframe (frame);
State_height = Frame.top;
Dragimageview.setscreen_h (window_height-state_height);
Dragimageview.setscreen_w (window_width);
}
}
);
The above is all realized. Finally, let's look at the effect of the implementation.
Artwork size
Zoom in and drag to upper left corner
After shrinking (slack meeting retraction)
Grow up in the wide
Feel the effect of the operation is also good, and Tencent Sina's almost. As for the auxiliary UI elements, you can modify the add, here I just put this form of implementation to everyone.