If you simply present two blocks, ask a requirement:
1. When you drag a block, the block (that is, the sub view) moves with your finger.
2. When one block moves, another block can follow the move.
3. Move the block to the left area (the right area) and then release it (i.e. the finger leaves the screen) and it will automatically move to the left edge (right edge).
4. Add animation (duang~duang~duang~) to the block when moving.
A summary of the relevant methods of view movement:
1. Layout
In a custom control, the view draws an overridden method layout (), which is used to set the display location. Therefore, you can change the view's position in the parent view by modifying its coordinate value to achieve the effect of moving! However, the disadvantage is that only the specified view can be moved:
Change location by layout method
View.layout (L,T,R,B);
1
2
1
2
2.offsetLeftAndRight () and Offsettopandbottom ()
A very convenient package method, just provide a horizontal, vertical offset, the display effect is the same as the layout () method.
View.offsetleftandright (offset);//change left and right at the same time
View.offsettopandbottom (offset);//change top and bottom at the same time
1
2
1
2
3. Layoutparams
This class preserves the layout parameters of a view and dynamically modifies the layout by layoutparams dynamically changing the position parameters of a layout to achieve the effect of the view position movement! However, when you get Getlayoutparams (), you determine your own layoutparams based on the parent view layout of the child view. So the premise of all is: must have a parent view, otherwise cannot get layoutparams!
You must obtain the layoutparams of the parent view
Linearlayout.layoutparams layoutparams = (linearlayout.layoutparams) getlayoutparams ();
Layoutparams.leftmargin = getLeft () + dx;
Layoutparams.topmargin = GetTop () + dy;
Setlayoutparams (Layoutparams);
1
2
3
4
5
1
2
3
4
5
4. ScrollTo and Scrollby
Move by changing the SCROLLX and scrolly, but you can move all the sub-view. ScrollTo (x, y) represents the move to a specific coordinate point (x, y), while Scrollby (x, y) indicates that the move is in increments of Dx,dy.
ScrollTo (x, y);
Scrollby (Xoffset,yoffset);
1
2
1
2
Note: Scrollby (xoffset,yoffset) is used here, and you will find no effect, as the above two methods move the content of the view. If used in ViewGroup, all sub-view is moved, and if used in view, the contents of the view (such as TextView) are moved.
Therefore, do not use the above method in view! Should be used in the viewgroup where the view is located:
(View) getParent ()). Www.yyzx66.cn/scrollBy (OffsetX, OffsetY);
1
1
"View coordinate system":
Write a picture description here
But even then, you'll find that the view movement works in the opposite direction as you would imagine! This is the reason why Android is trying to move, if the parameter is positive, cwww.lxinyul.cc ontent will move in the negative direction of the axis, the parameter is negative, and the content will move in the positive direction of the axis. So to achieve the effect of sliding with your finger, you should set the offset to a negative number:
(View) getParent ()). Scrollby (-offsetx,-offsety);
1
1
5. Canvas
By changing the location of the canvas to move the view content, use less:
Canvas.drawbitmap (bitmap, left, top, paint)
1
1
Summarize
But to complete the first request, regardless of which method, you need to use the Ontouchevent method to capture the gesture, manually calculate the mobile distance, and then change the layout of the sub-view, there is some trouble, so here to draw the text, Introduce a powerful class to handle the move: Viewdraghelper
Viewdraghelper Introduction:
1. Generated: Viewdraghelper in the V4 package (androiwww.senta7.net d4.4 above v4), at Google's 2013 developer conference
2. Function: It is mainly used to deal with the viewgroup of the pair view.
3. Use: It mainly encapsulates the touch position of the view, touch speed, moving distance and so on detection and scroller, through the interface callback way to inform us. So all we need to do is use the received data to specify whether these sub-view needs to be moved, how much to move, etc.
4. Essence: is an analytic class for touch events.
Viewdraghelper implementation
1. Viewdraghelper Instance Creation
/**
* Factory method to create a new viewdraghelper.
*
* @param forparent Parent view to monitor
* @param sensitivity Multiplier for www.yinbaovip.cn How sensitive the helper should is about detecting
*the start of a drag. Larger values is more sensitive. 1.0f is normal.
* @param CB Callback to provide information www.wuxinvip.cn and receive events
* @return A new Viewdraghelper instance
*/
Viewdraghelper = Viewdraghelper.create (forparent, sensitivity, CB);
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
Create () is the method that creates the Viewdraghelper instance, and the comments in the code are interpreted by the parameters in Create () to see:
(1) Forparent: "Parent view for monitoring". You can monitor all child view in the parent view by passing in the parameter parent view.
(2) Sensitivity: "Sensitivity at the time of detection; the larger the value the more sensitive, 1 is the normal range." For example, when the finger is sliding the screen speed is particularly fast, the greater the sensitivity, the speed can be detected at this time, and vice versa.
(3) Callback: "Providing information and receiving events". The most important parameter! You can get the distance, speed, etc. of the view swipe from the information provided by this callback.
2. Custom View Inheritance Framelayout
Here's a tip: The custom draglayout in the previously implemented layout is inherited from the viewgroup, and the implementation overrides the Onmeasure () method, as follows:
Draglayout.java
public class Draglayout extends viewgroup{
...
@Override
protected void onmeasure (int widthmeasurespec, int heightmeasurespec) {
Super.onmeasure (Widthmeasurespec, Heightmeasurespec);
Method One: Measurement requirements for a pair of view
/* Two ways to get the width of the child view 100DP:
int size = (int) getresources (). Getdimension (R.dimen.width);
int size = Readview.getlayoutparams (). width;*/
int measurespec = Measurespec.makemeasurespec (Redview.getlayoutparams (). width, measurespec.exactly);//Specify wide height for precise mode
Redview.measure (MEASURESPEC,MEASURESPEC);//When the parent control has finished measuring the child controls, it can be filled in (0,0)
Blueview.measure (MEASURESPEC,MEASURESPEC);
/*//Method Two: If there is no special measurement requirement for sub-view, the following methods can be used
Measurechild (REDVIEW,WIDTHMEASURESPEC,HEIGHTMEASURESPEC);
Measurechild (BLUEVIEW,WIDTHMEASURESPEC,HEIGHTMEASURESPEC); * *
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21st
22
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21st
22
But now make Draglayout class inherit from Framelayout!
public class Draglayout extends framelayout{
...
}
1
2
3
1
2
3
Because when customizing ViewGroup, if there is no special requirement for the measurement of a pair of view, you can inherit the existing layout of the system (such as Framelayout, relativelayout) in order to let the existing layout help us implement Onmeasure ().
So after the inheritance, we do not need to implement the Onmeasure () method, all of the above code is not required (here choose to inherit the framelayout frame layout, because it is the simplest implementation in Android source code), so rewrite the inherited onlayout () The method is to rewrite the frame layout of the onlayout (), if also comments, you will find the blue squares covered in red, together in the upper left corner (in fact, the frame layout of the placement rules)
3. Callback Callback Creation
Private Viewdraghelper.callback Callback = new Callback () {
Methods that must be implemented
@Override
public boolean Trycaptureview (View child, int pointerid) {
return false;
}
};
1
2
3
4
5
6
7
1
2
3
4
5
6
7
4. Touch and Intercept events
The creation of the above section of Viewdraghelper has been completed, but it is not finished yet. For example, you are familiar with a class: Gesturedetector gesture recognizer, want it to take effect, must pass a touch event, so that the Gesturedetector class can parse the current gesture. The same reason, before the introduction of Viewdraghelper has been mentioned, it is only a touch event parsing class, need to pass a touch event, will take effect.
Handling whether to intercept
@Override
public boolean onintercepttouchevent (Motionevent ev) {
Viewdraghelper to determine if this event should be intercepted
Boolean result = Viewdraghelper.shouldintercepttouchevent (EV);
return result;
}
@Override
public boolean ontouchevent (Motionevent event) {
Pass the touch event to Viewdraghelper to resolve the processing
Viewdraghelper.processtouchevent (event);
Consume this event and handle it Yourself
return true;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
The above Viewdraghelper can monitor and parse our gestures, and pass the message through a callback to callback.
5. Handling Computescroll ()
This method is the core of the Scroller class, and the system calls this method in draw () when the view is drawn, actually the same as Scrollto ().
@Override
public void Computescroll () {
Super.computescroll ();
if (Scroller.computescrolloffset ()) {
ScrollTo (Scroller.getcurrx (), Scroller.getcurry ());
Invalidate ();
}
1
2
3
4
5
6
7
1
2
3
4
5
6
7
As above, the Scroller class provides the Computescrolloffset () method to determine whether the entire slide has been completed, and Getcurrx () and Getcurry () to obtain the current sliding coordinates.
The focus is on the invalidate () method, because Scrollx and scrolly in the simulation process can only be obtained in the Computescroll () method, but the Computescroll () method is not automatically invoked, only through invalidate ()- > Draw ()->computescroll () to call the Computescroll () method indirectly! The simulation process is finished, if the Computescrolloffset () method returns false, interrupts the loop, and completes the entire smooth moving process!
But!!! We do not take the above approach, previously introduced Viewdraghelper has encapsulated the scroller, with another:
@Override
public void Computescroll () {
Super.computescroll ();
if (Viewdraghelper.continuesettling (true)) {
Viewcompat.postinvalidateonanimation (Draglayout.this);
}
}
}
1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
Continuesettling () method to determine whether the end, similar to the Scroller method, mainly Postinvalidateonanimation (), this method is not like Scroller Scrollto, also need to pass value, In fact, this method has been encapsulated in the body of the mobile method, it will automatically measure the current position to move, so we just call it! (It is also used in the callback method when the finger is lifted, which is described later)
6. Implementing the method in the callback callback
Prior to the creation of callback, only the Trycaptureview () method was implemented by default, and the completion of the requirements was just not enough, and there were other ways to introduce:
(1) Trycaptureview ()
This method is used to determine if the current child's touch event is captured, and you can specify which sub-view Viewdraghelper to move. In this example, you need to move two blocks to determine if the current view is the one you want to move and return a Boolean value.
/** is used to determine if a touch event is captured for the current child
* @param child view of current touch
* @return true: Capture and parse false: do not process
*/
@Override
public boolean Trycaptureview (View child, int pointerid) {
return child = = Blueview | | Child = = Redview;
}
1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
(2) onviewcaptured ()
This method is called when the view is started to be captured and parsed, that is, when the return value in Trycaptureview () is true.
For example, only red squares are captured in the Trycaptureview () method, and when moving the red side, the method will call back and move the blue block.
/** callback (not very useful) when view is started to capture and parse
* @param Capturedchild currently captured child view
*/
@Override
public void onviewcaptured (View capturedchild, int activepointerid) {
Super.onviewcaptured (Capturedchild, Activepointerid);
LOG.E ("tag", "Onviewcaptures");
}
1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
(3) Clampviewpositionhorizontal () and clampviewpositionvertical ()
These two are specific sliding methods that correspond to the horizontal and vertical movements respectively. To move the child view, this method must override the implementation!
The return value of the method is the value that specifies whether the view becomes in the horizontal (left) or vertical (top) direction, and the DX and dy in the parameter represent the increment compared to the previous position.
/** controls the movement of the child in the horizontal direction
* @param child
* @param left Viewdraghelper will change the left value of the current child to the value returned
* @param DX compared to the last time the child moved in the horizontal direction
* @return
*/
@Override
public int Clampviewpositionhorizontal (View child, int left, int dx) {
return left;
}
/** controls the movement of the child in the vertical direction
* @param child
* @param top Viewdraghelper will change the top value of the current child to the returned value
* @param dy compared to the last child in the horizontal direction
* @return
*/
@Override
public int clampviewpositionvertical (View child, int top, int dy) {
return top;
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21st
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21st
Display effect:
Write a picture description here
Write a picture description here
From the above GIF and log printing can be seen, only the return value is set to the parameters in the method, the block can be moved arbitrarily. Also confirms the parameters provided in the method while DX or DY is the distance to move each time, left or top is the location where the specified view is moved, which is calculated, which is equivalent to child.getleft () + DX.
If you want it to not move, then:
return LEFT-DX;
After calculating the distance minus the distance from the last move, the view will not move at this time. So, depending on your needs, you can change the return value of this method to move the view.
(4) Getviewhorizontaldragrange () and Getviewverticaldragrange ()
When you see the above GIF, you will find that when I move the block, it can go beyond the boundary without any restrictions! Some unreasonable, want to limit its moving range, these two methods can get the drag range of view, set its return value to: The parent control's width/height-the width/height of the child control, that is, the scope of the control can be moved.
Get the drag range in the view horizontal direction
@Override
public int Getviewhorizontaldragrange (View child) {
Return Getmeasuredwidth ()-child.getmeasuredwidth ();
}
Get the drag range of the view in the vertical direction
@Override
public int Getviewverticaldragrange (View child) {
Return Getmeasuredheight ()-child.getmeasuredheight ();
}
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
However, after the implementation, you will find that the drag block or can go beyond the boundary, this method does not work! Does this mean that this method is completely useless? What is the value of this return?
No, it does not currently limit boundaries, but the value returned by this method will be used in the following: For example, when the finger is lifted, the calculation of the slow motion time of the view will use this value, preferably not return 0 (return is not wrong)!
But we also want to limit the effect of the view drag boundary, when the 3rd introduction of Clampviewpositionhorizontal () and clampviewpositionvertical () play an effective role, The method is to change the position of the view movement by the return value, in which case the method can be used to determine whether there is an out-of-bounds:
Android View Mobile Summary: Viewdraghelper Learning and usage