Transferred from: http://www.codekk.com/open-source-project-analysis/detail/Android/lightSky/ViewPagerindicator%20%E6%BA%90% E7%a0%81%e8%a7%a3%e6%9e%90
Viewpagerindicator Source Code Analysis
This article is the viewpagerindicator part of the source code parsing of Android open source project
Project address: Viewpagerindicator, analyzed version: 8cd549f,demo address: Viewpagerindicator Demo
Analyst: Lightsky, Reviewer: aaronplay, proofreading Status: complete
1. Function Introduction 1.1 Viewpagerindicator
Viewpagerindicator is used for various interface navigation based on Viewpager in Androidsupportlibrary. Main features: Simple to use, full-style, easy to expand.
2. Overall design
The overall design of the project is very simple, a Pageindicator interface class, the specific style of the navigation class implementation of the interface, and then according to the specific style to implement the corresponding logic. The extension of Icslinearlayout:linearlayout supports more than 4.0 of the divider features. Circlepageindicator, Linepageindicator, Underlinepageindicator, titlepagerindicator inherit from view. Tabpageindicator and Iconpageindicator inherit from Horizontalscrollview.
The reason Circlepageindicator, Linepageindicator, and underlinepageindicator inherit from view is that they are relatively simple styles, inheriting view, customizing a set of measurement and drawing logic is easier, And the measure part of the cumbersome steps, more efficient.
Titlepagerindicator is relatively complex, there is no similar control in the Android system, and the precise control of the bottom line is complex, so it can only inherit from view and implement the drawing logic to achieve the desired UI effect.
Tabpageindicator, iconpageindicator inherit from Horizontalscrollview because of their childview more, and have similarity, inherit from LinearLayout, The add-on is simpler through the for loop, and the Horizontalscrollview has a horizontal sliding function, and when the tab is more, it can be left and right.
3. Detailed design of class 3.1 diagrams
3.2 Customizing control-related knowledge
Since the Viewpagerindicator project is all custom view, the analysis of its rationale is the analysis of the custom view, and the core part of the custom view involves: the drawing mechanism of the view and the touch event delivery mechanism. For the view drawing mechanism, here is a detailed elaboration, this part in Android for the public Knowledge point, has already put this part of the content alone, in the tech directory, and for the touch event, because the project is just indicator, Therefore, there is no complex touch transfer mechanism, and the project has only the Ontouch (Event) method associated with the touch mechanism, so only the relevant knowledge involved in this approach is introduced.
3.2.1 Custom Control Steps
Create a custom view
- Inherit a view or view subclass and add the necessary constructors
- Defining custom attributes (appearance and behavior)
- Apply Custom Properties: Specify property values in the layout, get and apply to view on initialization
- Ways to add control properties
Customize the drawing of a view
Override the OnDraw () method to draw a custom view on demand. Each time the screen is drawn and the animation is executed, the OnDraw method is called, avoiding complex operations in the OnDraw method, avoiding the creation of objects, such as the paint used during the drawing process, should be created at initialization time, not in the OnDraw method.
Make View Interactive
A good custom view should also be interactive, allowing users to feel small changes on the UI, and these changes should be as consistent and natural as possible with the physical laws of the real world. Android provides an input event model to help you handle user input events, allowing you to make transitions more natural and fluid with gesturedetector, Scroller, and property animations.
3.2.2 Android Drag and drop event
The project uses Viewpager, which did not have to deal with drag-and-drop events, but the project Circlepageindicator, Linepageindicator, Underlinepageindicator, Titlepageindicator all the ontouchevent was processed, began to understand, and later saw the project issue, asked the question: Circlepageindicator consuming touchevents The original is to imitate the iOS springboard indicator, so that the click Indicator left 1/3 and right 1/3 can switch page, if you use the project at the same time to deal with the touch event, it is possible that they will have conflict problems, Here are the knowledge points related to drag-and-drop events:
3.2.2.1 distinguish between the original point and any subsequent touch points
Action_pointer_down, action_pointer_up: Pressing and lifting events in multi-touch gesture events. This event is triggered whenever a second touch point is pressed or picked up. Can be captured and processed in Ontouchevent ().
3.2.2.2 ensure that the ID of the midpoint of the operation (the active pointer ID) is valid
When the Action_pointer_up event occurs, the sample program removes a reference to the index value for that point, ensuring that the ID of the point in the operation (the active POINTER ID) does not reference a touch point that is not already on the touchscreen. In this case, the app chooses another touch point as the point of Operation (active) and saves its current x, Y. You can always get a valid pointer of the correct calculation distance when you move at the touch point.
3.2.2.3 Mtouchslop
refers to the distance of pixels moved before a user touch event can be recognized as a move gesture. Touchslop is often used to prevent users from accidentally sliding while doing other things, such as touching elements on the screen.
In this project, the processing of Ontouche is a template method, because there is no complex interaction, just to track valid gestures and to determine the timing of page transitions. Detailed explanation of drag and zoom in the official documentation dragging and scaling the code in Ontouchevent in this project is the template code for the official document, to ensure that the available, trusted points are obtained, and then the Viewpager is processed accordingly.
3.2.3 View drawing mechanism
Please refer directly to the public technical point Viewdrawflow section
3.3 Core class and function introduction 3.3.1 Circlepageindicator
Inherited from View implements the Pageindicator, the method call rule used throughout the drawing process is:
(1) Main member variable meaning
1. mCurrentPage index of the current interface
2. mSnapPage SANP mode, the index of the current interface
3. mPageOffset Horizontal offset of Viewpager
4. mScrollState sliding State of the Viewpager
5. mOrientation Indicator mode: horizontal, Vertical
6. mLastMotionX the last offset of the horizontal position at the time of each Ontouch event
7. mActivePointerId the ID of the pointer that is currently active is the default value of-1
8. mIsDragging whether the user subjectively swipe the logo of the screen
9.mSnap
Circle has 2 drawing modes:
Msnap = True:viewpager during sliding, circle is not drawn, only the final solid point is drawn
Msnap = False:viewpager during sliding, the circle is drawn in real time between adjacent circle according to Mpageoffset
10.mTouchSlop
refers to the distance of pixels moved before a user touch event can be recognized as a move gesture.
Touchslop is often used to prevent users from accidentally sliding while doing other things, such as sliding when touching elements on the screen.
(2) Core approach
1.onDraw (canvas canvas)
threeRadiusTwo spacing of adjacent circle
shortOffsetThe center coordinate position of the vertical direction of the current direction
longOffsetThe center position of the current direction
//loop draw circle for (int iLoop = 0; iLoop < count; iloop++) {Floa T Drawlong = Longoffset + (ILoop * Threeradius);//calculates the current direction of each circle offset canvas.drawcircle (DX, DY, Pagefillradius, Mpaintpagefill);//Draw Hollow Circle Canvas.drawcircle (DX, DY, Mradius, Mpaintstroke);//Draw stroke ... Calculates the coordinates of a solid circle ... canvas.drawcircle (DX, DY, Mradius, Mpaintfill);//Draw the Circle}
2. ontouchevent (motionevent ev)
Core idea: Get the effective touch points during the drag process and calculate the moving distance correctly. This section is the template code, in the implementation of several other indicator, the handling of touch events is the same,
motionevent.action_down : Record the ID of the first touch point, get the current horizontal moving distance
motionevent.action_move : Gets the 1th index and calculates its offset, handling whether the user is a subjective sliding screen
motionevent.action_cancel : If the user is not actively sliding, the indicator of 1/3 and 2/3 for the critical point of previous and next
page processing, processing completed, restore Misdragging,mactivepointerid, Viewpager fakedragging status
motionevent.action_up : Ibid.
Motioneventcompat.action_pointer_ Down : When the event is triggered when the first out-of-office screen except the original point is recorded, the new Mlastmotionx,mactivepointerid
motioneventcompat.action_ Pointer_up : Gets the ID of the lifted finger when the non-1th leaves the screen, and if the previously tracked Mactivepointerid is the currently lifted finger ID, it is re-mactivepointerid Assigns a pointerid in another activity, and finally gets the x-coordinate value that is still active on the screen pointer
3.onmeasure (int widthmeasurespec, int heightmeasurespec)
The final size of the view in the measurement phase is determined by the Setmeasureddimension () method, which is the method that must be called, otherwise it will report an exception, where the Setmeasureddimension () method is called directly to set the value. The corresponding width and height are calculated according to the direction of the circleindicator.
if (mOrientation == HORIZONTAL) { setMeasuredDimension(measureLong(widthMeasureSpec), measureShort(heightMeasureSpec)); } else { setMeasuredDimension(measureShort(widthMeasureSpec), measureLong(heightMeasureSpec)); } }
4.Measurelong
Corresponding to the measureshort, but the direction of treatment is different
If the view has a measurement requirement of exactly, you can directly determine the size of the child view, which is the value of Measurespec.getsize (MEASURESPEC)
If the view is measured in unspecified or at_most mode, the width is calculated according to the actual demand
if ((specMode == MeasureSpec.EXACTLY) || (mViewPager == null)){ //We were told how big to be result = specSize; } else { final int count = mViewPager.getAdapter().getCount(); result = (int)(getPaddingLeft() + getPaddingRight() + (count * 2 * mRadius) + (count - 1) * mRadius + 1); //如果父视图的测量要求为AT_MOST,即限定了一个最大值,则再从系统建议值和自己计算值中取一个较小值 if (specMode == MeasureSpec.AT_MOST) { result = Math.min(result, specSize); } } return result;
3.3.2 Iconpageindicator, Tabpageindicator
are inherited from Horizontalscrollview, and the implementation logic is very similar, so here only the Iconpageindicator analysis
(1) Main member variable meaning
1. mIconsLayout manage the parent view of the icon. At initialization time, it is added directly to the root node via AddView ().
2. mIconSelector Iconpageindicator Post's Runnable object, which performs the logic of sliding to the specified icon position.
(2) Core approach
1. notifyDataSetChanged called in Setviewpager, used to create iconpageindicator, internally through a for loop constantly new ImageView, and then add to miconslayout up, immediately after the request layout.
2. animateToIcon swipe to the specified icon to reclaim the last Miconselector and post a new miconselector.
3. onAttachedToWindow This method is called when the view attach to the window, at which point the view has a drawing area where it can do some initialization operations, where the previously selected icon is initialized.
4. onDetachedFromWindow after the method is called, the view no longer has an area that can be drawn. You can perform some cleanup operations on the view at this point. This removes the Miconselector from the message queue.
3.3.3 Titlepageindicator
Because of the real-time and complexity of the effect, the whole indicator is drawn, and the main logic is in the OnDraw.
(1) Main member variable meaning
1. Paint mPaintText The text
2. Paint mPaintFooterLine the bottom line
3. mPaintFooterIndicator Paint of the current title bottom indicator
(2) Core approach
1. calculateAllBounds calculates the boundary value of all the title according to the currently selected title
2. clipViewOnTheLeft set the boundary for the left TextView, and when TextView moves left to the indicator's boundary, the Textviwe is set to always be indicator of the leftmost coordinate value, thereby rendering the lingering effect.
3. clipViewOnTheRight ditto, reverse opposite
The entire drawing process:
3.3.4 Linepageindicator, Underlineindicator
Similar to Circlepageindicator, you can refer to the Circlepageindicator analysis.
3.4 Step analysis for creating a custom view
Here take Circlepageindicator as an example
3.4.1 inherits from view, implements constructors
CirclePageIndicator extends View implements PageIndicator { public CirclePageIndicator(Context context) { this(context, null); } public CirclePageIndicator(Context context, AttributeSet attrs) { this(context, attrs, R.attr.vpiCirclePageIndicatorStyle); } public CirclePageIndicator(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); ... }}
3.4.2 Defining properties
Vpi_attrs.xml
<declare-styleable name="CirclePageIndicator"> <!-- Color of the filled circle that represents the current page. --> <attr name="fillColor" format="color" /> <!-- Color of the filled circles that represents pages. --> <attr name="pageColor" format="color" /> ... </declare-styleable>
3.4.3 Apply Attributes
Apply in Layout
<!--首先指定命名空间,属性才可以使用--><LinearLayout xmlns:app="http://schemas.android.com/apk/res-auto"><!--应用属性值--> <com.viewpagerindicator.CirclePageIndicator ... app:fillColor="#FF888888" app:pageColor="#88FF0000" /></LinearLayout>
Load the property values in the layout in your code and apply:
public CirclePageIndicator(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); //加载默认值 final Resources res = getResources(); final int defaultPageColor = res.getColor(R.color.default_circle_indicator_page_color); //获取并应用属性值 TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CirclePageIndicator, defStyle, 0); //应用属性值 mPaintPageFill.setColor(a.getColor(R.styleable.CirclePageIndicator_pageColor, defaultPageColor)); ... a.recycle();//记得及时释放资源 }
3.4.4 Drawing of Custom view
Please refer to the Circlepageindicator OnDraw above, or refer to the Draw section of the view's drawing process under tech.
3.4.5 to make View interactive
Please refer to the above Circlepageindicator Ontouch, here is just a simple handling of the Ontouch event, interactive better custom controls tend to add some natural animation and so on.
4. Talk
Most of the apps in the navigation are similar, viewpagerindicator can meet the basic needs of your development, if not satisfied, you can on the basis of the source of some simple transformation. One of the things that many friends put forward is that Lineindicator did not achieve the TextView color state linkage. This has an already implemented Open Source Library: Pagerslidingtabstrip, which you can use as a reference.
For when you need custom controls and how to customize them better, you can refer to this article for an in-depth analysis of Android's custom layouts and I believe there are some inspirations.
The whole article looked down, indeed more, but also spent a part of the time to write, in fact, before it was their own sorting out some relevant knowledge, this time all to share with you. The whole article is about the drawing mechanism of the view, the three processes are also detailed through the source code analysis introduced. If you are not clear about the drawing mechanism of the view, and hope that in the future to the more advanced direction, this step will be experienced, then please be patient, you can read several times, the process of problems or the original analysis is not in place, welcome pr.
When you have mastered this basic knowledge, you can study some of the open source projects on GitHub (because the touch event is not much introduced here, and many projects are related to touch events).
Reference documents
Http://developer.android.com/training/gestures/index.html
Http://developer.android.com/training/custom-views/create-view.html
Google Android Official training course Chinese version
Drawing of view:
http://blog.csdn.net/wangjinyu501/article/details/9008271
http://blog.csdn.net/qinjuning/article/details/7110211
http://blog.csdn.net/qinjuning/article/details/8074262
Related Resources
Google I/O 2013-writing Custom views for Android
Best-practices-for-android-user-interface
Deep analysis of Android's custom layouts
MU Lesson Network Custom FlowLayout Course
Touch Event Delivery
http://blog.csdn.net/xiaanming/article/details/21696315
http://blog.csdn.net/wangjinyu501/article/details/22584465
Go Viewpagerindicator Source Code Analysis