current position:Home>[reading notes] Android advanced light view system

[reading notes] Android advanced light view system

2022-01-26 23:49:46 B orange Buddha

1. View And ViewGroup

View and ViewGroup The relationship between ?

1. ViewGroup It can be understood as View The combination of , It can contain many View as well as ViewGroup.

2. ViewGroup Also inherit from View.

2. Coordinate system

Android There are two coordinate systems in the system , Respectively Android Coordinate system and View Coordinate system .

2.1 Android Coordinate system

Take the vertex in the upper left corner of the screen as Android Origin of coordinate system , The origin to the right is X Affirmative direction , Down is Y Affirmative direction .

Usage method :getRawX and getRawY

2.2 View Coordinate system

2.2.1 View Get your own width and height

getHeigh() and getWidth()

2.2.2 View The coordinates of itself

  • getTop(): obtain View The distance from the top edge of itself to the top edge of its parent layout .
  • getLeft(): obtain View The distance from the left side of itself to the top edge of its parent layout .
  • getRight(): obtain View The distance from the right side of itself to the top edge of its parent layout .
  • getBottom(): obtain View The distance from the bottom edge of itself to the top edge of its parent layout .

2.2.3 MotionEvent Methods provided

  • getX(): Gets the distance from the click event to the left of the control , That's the view coordinates .
  • getY(): Gets the distance between the click event and the top edge of the control , That's the view coordinates .
  • getRawX(): Get the distance from the click event to the left of the whole screen , Absolute coordinates .
  • getRawY(): Get the distance from the click event to the top edge of the whole screen , Absolute coordinates .

3. View The slide of  

principle : When the click event passes to View when , The system records the coordinates of the touch points , When the finger moves, the system records the coordinates of the touch and calculates the offset , And modify it by offset View Coordinates of . Here are 6 Sliding method :

3.3.1 layout() Method

draw View It will call onLayout Method to set the position of the display .

application :

1.  stay onTouchEvent Method to get the coordinates of the touch point .

2. stay ACTION_MOVE Event to calculate the offset , Call again layout Method to reset the custom View The location of .

3. Call... Every time you move layout Method to rearrange the screen , So as to move View The effect of .

3.3.2 offsetLeftAndRight() And offsetTopAndBottom

These two methods and layout The effect of the method is almost the same , The way to use it is similar .

  • offsetLeftAndRight(offsetX) // Yes left and right Offset
  • offsetTopAndBottom(offsetY) // Yes top and bottom Offset

3.3.3 LayoutParams ( Change layout parameters )

LayoutParams Saved a View The layout parameters of , So we can go through LayoutParams To change View The layout parameters of , To change View The effect of location .

LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) getLayoutParams();
layoutParams.leftMargin = getLeft() + offsetX;
layoutParams.rightMargin = getTop() + offsetY;
 Copy code 

If the parent control is RelativeLayout , Use RelativeLayout.LayoutParams.

3.3.4 Animation

1. View Animation :

Use : stay res Create a new anim Folder and create translate.xml. Finally using loadAnimation(this,R.anim.translate)

shortcoming :View Animation doesn't change View Position parameters of .

2. Attribute animation :

 Copy code 

3.3.5 scrollTo And scrollBy

scrollTo(x,y): It means moving to a specific coordinate point .

scrollBy(dx,dy): Indicates that the increment of movement is dx,dy.

3.3.6 Scroller

Scroller It can't be realized in itself View The sliding of , It needs to work with View Of computeScroll The elastic sliding effect can only be achieved by the combination of methods .

The system is drawing View At the time of draw This method is called in the method. , In this method , We call the parent class's scrollTo Method and pass Scroller To continuously obtain the current sliding value . Every small distance of sliding , We call invalidate The method is to redraw continuously . Redrawing will call computeScroll Method , So it's connected .

4. Attribute animation

4.1 ObjectAnimator

principle :ObjectAnimator Is the most important class of attribute animation , Create a ObjectAnimator Just return a... Directly through its static factory class ObjectAnimator object . Parameters include an object and its attribute name , But this property has to have get Methods and set Method , Its interior will pass through java Reflection mechanism to call set Method to modify the attribute value of the object .

4.2 ValueAnimator

ValueAnimator Does not provide any animation effects , It's more like a value generator , Used to generate regular numbers , This allows the caller to control the implementation process of the animation .

4.3 Monitoring of animation

The complete animation has start,Repeat,end, cancel this 4 A process .

  • onAnimationStart(Animator animation)
  • onAnimationEnd(Animator animation)
  • onAnimationCancel(Animator animation)
  • onAnimationRepeat(Animator animation)

4.4 Combination animation - AnimatorSet

AnimatorSet Provides a play Method , If we pass in a Animator object , Will return a AnimatorSet.Builder Example , This Builder class AnimatorSet The inner class of , Take the builder model . Four methods are provided :

1. after(Animator anim) : Insert the existing animation into the incoming animation and execute .

2. after(long delay) : Delays the execution of an existing animation by a specified number of milliseconds .

3. befor(Animator anim): Inserts an existing animation before the incoming animation .

4. with(Animator anim): Execute the existing animation and the incoming animation at the same time .

4.5 Combination animation - PropertyValueHolder

ObjectAnimator.ofPropertyValuesHolder(Object target, PropertyValuesHolder...values)
 Copy code 

4.6 stay XML Use attribute animation in

and View It's like animation , Attribute animation can also be unloaded directly XML in . stay res New in the file animator file , Create a new scale.xml file .

 Copy code 

5. analysis Scroller

Scroller principle :Scroller Can't directly realize View The slide of , It needs to work with View Of computeScroll() Method . stay computeScroll() Keep letting View Redraw , Each redraw calculates the duration of the slide , Based on this duration, we can calculate this View Sliding position , We call... According to the position of each slide scrollTo() Method to slide , In this way, the above process is repeated continuously to form elastic sliding .

6. View Event distribution mechanism of

6.1 The source code parsing Activity The composition of the

summary : One Activity Contains a Window object , This object is made by PhoneWindw To achieve .PhoneWindow take DecorView As the root of the whole application window View, And this DecorView Divide the screen into two areas , One is TitleView, The other is ContentView, The layout of the application we usually do is shown in ContentView Medium .

6.2 The source code parsing View Event distribution mechanism of

There are three important ways to click events :

  • dispatchTouchEvent(MotionEvent ev) — For event distribution ;

  • onInterceptTouchEvent(MotionEvent ev) — Used to intercept events , stay dispatchTouchEvent() Call in , It should be noted that View The method is not provided ;

  • onTouchEvent(MotionEvent ev) — Used to handle click events , stay dispatchTouchEvent() Method .

6.2.1 View Event distribution mechanism of

When a click event occurs , The event first passes to the current Activity, This will call Activity Of dispatchTouchEvent() Method , Of course, the specific event handling work is entrusted to Activity Medium PhoneWindow To complete , then PhoneWindow Then give the matter to DecorView, After that DecorView Leave the event handling to the root ViewGroup.

A complete sequence of events is based on DOWN Start , With UP The end of the . If at present ViewGrou Intercept the incident , Will call onInterceptTouchEvent(ev), The next sequence of events consists of this ViewGroup Processing is no longer performed onInterceptTouchEvent(ev) Method , And will intercepted = true.

therefore , onInterceptTouchEvent() Methods are not called every time , Default return false.

If at present ViewGroup The event was not intercepted , This series of events will be handed over to the son View Handle .

FLAG_DISALLOW_INTERCEPT Sign a : It mainly prohibits ViewGroup Intercept in addition to DOWN Other events , General Guo Zi View Of requestDisallowInterceptTouchEvent To set up .

View Of dispatchTouchEvent

if onTouchListener Not for null also onTouch Method returns true, Events are consumed , They don't execute onTouchEvent(ev). Otherwise it will carry out onTouchEvent(ev). stay onTouchEvent in , as long as View Of clickable and LONG_CLICKABLE There is one for true, that onTouchEvent() It will return true Consume events .

And then ACTION_UP Call in performClick Method , If click event is set , It will call onClick Method .

onTouchListener The priority of the interface is higher than onTouchEvent Of , If onTouchListener Medium onTouch Method returns true, It means that this event has been consumed , that onTouchEvent You can't receive a message .

If you give one Button Set up a onTouchListener And rewrite onTouch Method , The return value is true, At this time Button Is the click event still handled ?

The answer is :
It can't be handled .
because Button Of performClick It's using onTouchEvent Realization , If onTouchEvent Not called to , that Button Of Click Events are also unresponsive .

summary : 

 1. onTouchListener Of onTouch Method priority ratio onTouchEvent high , Will trigger . 

 2. If onTouch Method returns false Will then trigger onTouchEvent, conversely onTouchEvent Method will not be called . 

3.  Built in such as click The implementation of events and so on are based on onTouchEvent, If onTouch return true, These events will not be triggered . 

( Go back and try , Otherwise, it is difficult to understand )

Events are a series of , If DOWN Where is it consumed , Where are the subsequent events consumed .

6.2.2 Click the delivery rule of event distribution

From top to bottom :

When the click event is generated, it will be generated by Activity To deal with it , Pass to PhoneWindow, And pass it on to DecorView, Finally passed to the top ViewGroup. Generally, only... Is considered in event transmission ViewGroup Of onInterceptTouchEvent Method , Because normally we don't rewrite dispatchTouchEvent Method . For roots ViewGroup, The click event is first passed to it dispatchTouchEvent Method . If it's time to ViewGroup Of onInterceptTouchEvent Method returns true, It means it wants to intercept this event , This event will be handed over to it onTouchEvent Method treatment : If onInterceptTouchEvent Method returns false, It means that it does not intercept this event , This event will be handed over to its child elements dispatchTouchEvent To deal with it , It goes on and on . If passed to the underlying View, The View No son View Of , This will call View Of dispatchTouchEvent Method . Generally, it will eventually be called View Of onTouchEvent Method .

From the bottom up :

When the click event is passed to the underlying View when , If it onTouchEvent Method returns true, The event consists of the underlying View Consume and dispose of : If onTouchEvent Method returns false, It means that View Don't deal with it , And pass it on to the father View Of onTouchEvent Method treatment : If the father View Of onTouchEvent Method still returns false, Continue to pass to the parent View The father of View Handle , It goes on and on .

7. View workflow

measure: To measure View Width and height ;

layout: Used to determine View The location of ;

draw: Used to draw View;

7.1 View Workflow entry

(1) DecorView How to be loaded into Window in ?

7.2 understand MeasureSpec

MeasureSpec The role of :

MeasureSpec yes View The inner class of , It encapsulates a View Specifications and dimensions of , Include View Wide and high information , Its function is , stay Measure In the process , The system will View Of LayoutParams Convert to the corresponding... According to the rules imposed by the parent container MeasureSpec, And then in onMeasure Method according to this MeasureSpec To make sure View Width and height .

Measurement mode specMode:

  • UNSPECIFIED: Mode not specified ,View As big as you want , The parent container has no restrictions .
  • AT_MOST: Maximum mode , Corresponding to wrap_content attribute , Son View The final size of is the parent View designated specSize value , And son View The size of cannot be greater than this value .
  • EXACTLY: Accurate model , Corresponding to match_parent Properties and specific values , The parent container measures View The size needed , That is to say specSize Value .

For each of these View, All hold one MeasureSpec, And the MeasrSpec Save the View Dimensions of . stay View In the measurement process , adopt makeMeasureSpec To save width and height information . adopt getMode or getSize Get pattern and width , high .MeasureSpec By oneself LayoutParams And the parent container MeasureSpect Jointly influenced .

about DecorView Come on , its MeasureSpec By their own LayoutParams And the size of the window , This is the same as ordinary View Is different .                                                                                                                                                                          

7.3 View Of measure technological process

measure To measure View Width and height , Its processes are View Of measure The process and ViewGroup Of measure, It's just ViewGroup Of measure In addition to completing its own measurement , Also call the of child elements iteratively measure() Method .

(1) View Of measure technological process

Measurement process :


getDefaultSize effect :

public static int getDefaultSize(int size, int measureSpec) {
    //size It means View The size information you want , Such as minimum width or minimum height 
    int result = size;
    // from measureSpec Resolve in specMode Information 
    int specMode = MeasureSpec.getMode(measureSpec);
    // from measureSpec Resolve in specSize Information , Don't put specSize With the above size Variables are confused 
    int specSize = MeasureSpec.getSize(measureSpec);

    switch (specMode) {
    // If mode yes UNSPECIFIED, Express View The father of ViewGroup Not given View Set restrictions on size 
    case MeasureSpec.UNSPECIFIED:
        // Here when mode yes UNSPECIFIED when ,View Just use the size you want size As a result of measurement 
        result = size;
    case MeasureSpec.AT_MOST:
    case MeasureSpec.EXACTLY:
        // here mode yes AT_MOST or EXACTLY when ,View Just use his father ViewGroup The specified dimension is used as the result of measurement         result = specSize;      
    return result;
 there result It is obtained through the following function .
protected int getSuggestedMinimumWidth() {
        return (mBackground == null) ? mMinWidth : 
                max(mMinWidth, mBackground.getMinimumWidth());
 You can see mBackground  == null  No background is set for , Then the return mMinWidth , That is to say android:minWidth  The value specified by this property , This value could be zero 0 ; If View  Background set , Then return to mMinWidth  And the minimum width of the background .

getSuggestedMinimumWidth()  The return value of View  stay UNSPECIFIED  Measured width in case .
 Copy code 

According to SpecMode Value to return Different result value , That is to say SpecSize. stay AT_MOST and EXACTLY In mode , All back to SpecSize This value , namely View The measured width and height in both modes depend directly on SpecSize. in other words , For a One is directly inherited from View The custom of View Come on , its wrap_content and match_parent The effect of attributes is the same . 

So if To implement customization View Of wrap_content, Then rewrite onMeasure Method , And customize View Of wrap_content Property to process .

(2) ViewGroup Of measure technological process

ViewGroup Not defined in onMeasure() Method , But it defines measureChildren() Method .

Traverse the child elements and call measureChild Method , call child.getLayoutParams() Method to get the of child elements LayoutParams attribute , Get the MeasureSpec Calling the measure() Method to measure .

look down getChildMeasureSpec() What does the method write ?

     * Does the hard part of measureChildren: figuring out the MeasureSpec to
     * pass to a particular child. This method figures out the right MeasureSpec
     * for one dimension (height or width) of one child view.
     * The goal is to combine information from our MeasureSpec with the
     * LayoutParams of the child to get the best possible results. For example,
     * if the this view knows its size (because its MeasureSpec has a mode of
     * EXACTLY), and the child has indicated in its LayoutParams that it wants
     * to be the same size as the parent, the parent should ask the child to
     * layout given an exact size.
     * @param spec The requirements for this view
     * @param padding The padding of this view for the current dimension and
     *        margins, if applicable
     * @param childDimension How big the child wants to be in the current
     *        dimension
     * @return a MeasureSpec integer for the child
    public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
        int specMode = MeasureSpec.getMode(spec);
        int specSize = MeasureSpec.getSize(spec);

        int size = Math.max(0, specSize - padding);

        int resultSize = 0;
        int resultMode = 0;

        switch (specMode) {
        // Parent has imposed an exact size on us
        case MeasureSpec.EXACTLY:
            if (childDimension >= 0) {
                resultSize = childDimension;
                resultMode = MeasureSpec.EXACTLY;
            } else if (childDimension == LayoutParams.MATCH_PARENT) {
                // Child wants to be our size. So be it.
                resultSize = size;
                resultMode = MeasureSpec.EXACTLY;
            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
                // Child wants to determine its own size. It can't be
                // bigger than us.
                resultSize = size;
                resultMode = MeasureSpec.AT_MOST;

        // Parent has imposed a maximum size on us
        case MeasureSpec.AT_MOST:
            if (childDimension >= 0) {
                // Child wants a specific size... so be it
                resultSize = childDimension;
                resultMode = MeasureSpec.EXACTLY;
            } else if (childDimension == LayoutParams.MATCH_PARENT) {
                // Child wants to be our size, but our size is not fixed.
                // Constrain child to not be bigger than us.
                resultSize = size;
                resultMode = MeasureSpec.AT_MOST;
            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
                // Child wants to determine its own size. It can't be
                // bigger than us.
                resultSize = size;
                resultMode = MeasureSpec.AT_MOST;

        // Parent asked to see how big we want to be
        case MeasureSpec.UNSPECIFIED:
            if (childDimension >= 0) {
                // Child wants a specific size... let him have it
                resultSize = childDimension;
                resultMode = MeasureSpec.EXACTLY;
            } else if (childDimension == LayoutParams.MATCH_PARENT) {
                // Child wants to be our size... find out how big it should
                // be
                resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;
                resultMode = MeasureSpec.UNSPECIFIED;
            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
                // Child wants to determine its own size.... find out how
                // big it should be
                resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;
                resultMode = MeasureSpec.UNSPECIFIED;
        //noinspection ResourceType
        return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
 Copy code 

Obviously , This is based on the parent container MeasureSpec The pattern combines the of the child elements LayoutParams Attribute to get the of the child element MeasureSpec attribute . One thing to note is that , If the parent container MeasureSpec The attribute is AT_MOST, The child element LayoutParams The attribute is WRAP_CONTENT, According to the code above , We will find that the attribute of the child element is also AT_MOST, its SpecSize The value is the of the parent container SpecSize subtract Padding value . let me put it another way , This is related to the child element settings LayoutParams The attribute is MATCH_PARENT Equally effective . To solve this problem , Need to be in LayoutParams by WRAP_CONTENT Specify the default width and height .

7.4 View Of layout technological process

layout The function of the method is to determine the position of the element .ViewGroup Medium layout Method is used to determine the position of child elements ,View Medium layout Method is used to determine its position .

layout Methodical 4 Parameters l,t,r,b Namely View From the left , On , Right , The distance from its parent container .

layout->onLayout  ,onLayout Method is an empty method , This sum onMeasure The method is similar to . When determining the position, there are different implementations according to different controls , So in View and ViewGroup None of them achieve onLayout Method .

With LinearLayout Medium onLayout For example :

among layoutVertical() Will traverse the child elements and call setChildFrame Method .

stay setChildFrame Subelements are invoked in the method. layout Method to determine your position .

7.5 View Of draw technological process

1. if necessary , Then draw the background . 

 2. Save the current canvas layer . 

 3. draw View The content of . 

 4. Sketcher View. 

 5. if necessary , Then draw View Faded edge of , This is similar to the shadow effect . 

 6. Draw decorations, such as . Scroll bar .

One . Drawing the background calls View Of drawBackground(Canvas canvas).

Two . draw View The content of calls View Of onDraw(Canvas canvas) Method .

3、 ... and . Sketcher View Called dispatchDraw**(Canvas canvas)** Method

ViewGroup Rewrite this method , stay dispatchDraw Method for subclasses View Traversal , And call drawChild Method , Here we call View Of draw Method . This will determine whether there is a cache , If not, it will display normally , Show cache when there is .

Four . For drawing decoration onDrawForeground Method , Obviously, this method is used to draw ScrollBar And other decorations , And draw it on the top layer of the view content .

8. Customize View

8.1 Inherit the customization of system controls View

Inherit the of the system View, rewrite onDraw The method can .

8.2 Inherit View The custom of View

8.2.1 Simple implementation of inheritance View The custom of View

It is similar to the customization of inherited system controls above View Different , Inherit View The custom of View It's a little more complicated to implement . It's not just Is to achieve onDraw() Method , And in the implementation process, we should also consider wrap_content Properties and padding Property settings ; in order to Easy to configure your own custom View, You can also provide custom attributes to others . in addition , If you want to change the logic of touch , And rewrite onTouchEvent() And so on

8.2.1 Yes padding Property to process

Use getPaddingLeft(),getPaddingRight() To get padding.

8.2.3 Yes wrap_content Property to process

Customize View Set the default width and height :

**8.2.4 Custom properties

8.3 Custom composite control

1. Inherit RelativeLayout Related components

2. have access to findViewById

3. You can also customize properties

4. Custom attributes need to be added

schemas: xmlns: app="http: //" Namespace

8.4 Customize ViewGroup

1. Need to rewrite onLayout()

2. Yes wrap_content Property to process

3. Reset the width and height according to whether there are child elements

4. rewrite onlayout Method .

If the child element is not GONE, Then call the... Of the child element layout Method , Put it in the right place is that .

8.4.4 Handling sliding conflicts

This customization ViewGroup For horizontal sliding , If it's inside ListView,ListView Vertical sliding , This will lead to sliding conflict . The solution is , If the sliding direction we detect is horizontal , Just let the father View To intercept , Make sure the parent View Used for View Sliding switch of .

8.4.5 Elastic slide to other pages

stay onTouchEvent Method requires sliding to switch pages , Need to use Scroller.

Just entered onTouchEvent Method to get the coordinates of the click event , stay MotionEvent.ACTION_MOVE of use scrollBy Method to handle HorizontalView The effect of the control sliding with the finger . If the width is greater than 1/2, call Scroller To slide .

8.4.6 Quickly slide to other pages

Need to use VelocityTracker To test the sliding speed .

Usage method :

  • tracker = VelocityTracker.obtain();
  • tracker.computeCurrentVelocity(1000);// How many seconds
  • tracker.getXVelocity();
  • tracker.clear()

8.4.7 Touch the screen again to stop the page from sliding

Callable Scroller.isFinished() Judge Scroller Whether it is sliding , If sliding , Call Scroller.abortAnimation Stop sliding .

For your own learning .

copyright notice
author[B orange Buddha],Please bring the original link to reprint, thank you.

Random recommended