Android build not the same as the Novice boot page (i)
This series is mainly divided into two blog posts
For the page navigator, you can view my blog. Top navigation indicator for NetEase news
This blog mainly explains how to customize a Circleindicator control?
The next blog mainly explains how to change the effect of the viewpager switch, it is expected to be updated before tomorrow evening.
As follows
1) First let's take a look at how to use our Circleindicator control
It's really simple, the value needs two steps.
1) Inside the XML layout file
<relativelayout xmlns:android="Http://schemas.android.com/apk/res/android"Android:layout_width="Match_parent"android:layout_height="Match_parent"> <android.support.v4.view.viewpager android:layout_below="@id/rl_header"Android:id="@+id/viewpager"Android:layout_width="Match_parent"android:layout_height="Match_parent"android:layout_margintop="20DP"> </android.support.v4.view.ViewPager> < Com.xujun.administrator.customviewspecif.view.CirclePageIndicator android:id="@+id/circle_indicator"Android:layout_width="Match_parent"android:layout_height="Wrap_content"Android:layout_alignparentbottom="true"Android:layout_marginbottom="20DP"> </com.xujun.administrator.customviewspecif.view.CirclePageIndicator></RelativeLayout>
2) inside the code
mViewPager = (ViewPager) findViewById(R.id.viewPager);mCirclePageIndicator = (CirclePageIndicator) findViewById(R.id.circle_indicator);//注意下面初始化的顺序不可以调换new BaseFragemntAdapter( getSupportFragmentManager(), mFragments);mViewPager.setAdapter(mFragemntAdapter);//将mCirclePageIndicator与我们的mViewPager绑定在一起mCirclePageIndicator.setViewPager(mViewPager);
Extended
1) Change our style in the XML layout
xmlns:app="Http://schemas.android.com/apk/res-auto"//For example, change the color of the dots we moveApp:fillcolor="#fff"///Other property changes please refer to our custom properties below<declare-styleable name="Circlepageindicator"> <!--Whether or not the indicators should is centered. -<attr Name="Centered"/> <!--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"/> <!--Orientation of the indicator. -<attr Name="Android:orientation"/> <!--Radius of the circles. This is also the spacing between circles. -<attr Name="radius"format="Dimension"/> <!--Whether or not, the selected indicator snaps to the circles. -<attr Name="Snap"format="Boolean"/> <!--Color of the open circles. -<attr Name="Strokecolor"format="Color"/> <!--Width of the stroke used to draw the circles. -<attr Name="Strokewidth"/> <!--View background-<attr name="Android:background"/></declare-styleable>
2) dynamic changes in Java code
// 设置滑动的时候移动的小圆点是否跳跃mCirclePageIndicator.setSnap(false);//设置小圆点的半径mCirclePageIndicator.setRadius(10 * density);// 设置页面小圆点的颜色mCirclePageIndicator.setPageColor(0x880000FF);// 设置移动的小圆点的颜色mCirclePageIndicator.setFillColor(0xFF888888);// 设置外边框的颜色mCirclePageIndicator.setStrokeColor(0xFF000000);//设置外表框的宽度mCirclePageIndicator.setStrokeWidth(2 * density);
2) Now let's see how we're circleindicator.
Can be divided into the following several steps
- (1) Inherit view, do some initialization work in the construction method, including initializing our custom attributes and brushes, etc.
Public Circlepageindicator(context context, AttributeSet attrs,intDefstyle) {Super(Context, attrs, Defstyle);if(Isineditmode ())return;//Initialize custom properties FinalResources res = getresources ();Final intDefaultpagecolor = Res.getcolor (R.color.default_circle_indicator_page_color);Final intDefaultfillcolor = Res.getcolor (R.color.default_circle_indicator_fill_color);Final intDefaultOrientation = Res.getinteger (R.integer. default_circle_indicator_orientation); A number of methods A.recycle () are omitted here;FinalViewconfiguration Configuration = viewconfiguration.get (context); Mtouchslop = viewconfigurationcompat.getscaledpagingtouchslop (configuration);}
- (2) In our Onmeasure method, we measure our size according to different directions.
@Overrideprotected void onmeasure(intWidthmeasurespec,intHEIGHTMEASURESPEC) {if(morientation = = horizontal) {setmeasureddimension (Measurelong (Widthmeasurespec), Measureshort (Heightmeasurespec)); }Else{setmeasureddimension (Measureshort (Widthmeasurespec), Measurelong (Heightmeasurespec)); }}/** * Determines the width of this view * * @param measurespec A Measurespec Packed to an int * @return the width of the view, honoring constraints from Measurespec * /Private int Measurelong(intMEASURESPEC) {intResultintSpecmode = Measurespec.getmode (Measurespec);intSpecsize = Measurespec.getsize (Measurespec);if((Specmode = = measurespec.exactly) | | (Mviewpager = =NULL)) {//we were told how big to beresult = Specsize; }Else{//calculate The width according the views count Final intCount = Mviewpager.getadapter (). GetCount (); result = (int) (Getpaddingleft () + getpaddingright () + (count *2* Mradius) + (count-1) * Mradius +1);//respect at_most Value if that's what's called for by Measurespec if(Specmode = = measurespec.at_most) {result = Math.min (result, specsize); } }returnResult;}/** * Determines the height of this view * * @param measurespec A Measurespec Packed to an int * @retur n the height of the view, honoring constraints from Measurespec * /Private int Measureshort(intMEASURESPEC) {intResultintSpecmode = Measurespec.getmode (Measurespec);intSpecsize = Measurespec.getsize (Measurespec);if(Specmode = = measurespec.exactly) {//we were told how big to beresult = Specsize; }Else{//measure the heightresult = (int) (2* Mradius + getpaddingtop () + getpaddingbottom () +1);//respect at_most Value if that's what's called for by Measurespec if(Specmode = = measurespec.at_most) {result = Math.min (result, specsize); } }returnResult;}
- (3) Provide a Setviewpager (Viewpager view) method to bind our circlepageindicator together
@Override public void setviewpager (Viewpager view) {if (Mviewpager = = view) {return ; } if (Mviewpager! = null ) {Mviewpager.addon Pagechangelistener (null ); } if (view.getadapter () = = null ) {throw new illegalstateexception ( "Viewpager does not has adapter instance." ); } Mviewpager = view; Mviewpager.addonpagechangelistener (this ); Invalidate ();}
The main logic inside is simply to determine if our Viewpager has been set adapter, no words throw an exception, then a strong Viewpager Pagechanglistener event.
Call the Invalidate () method to redraw the Circlepagerindicator
- (4) When sliding the Viewpager to get the corresponding offset
@Override Public void onpagescrollstatechanged(intState) {mscrollstate = state;if(Mlistener! =NULL) {mlistener.onpagescrollstatechanged (state); }}@Override Public void onpagescrolled(intPositionfloatPositionoffset,intPositionoffsetpixels) {mcurrentpage = position; Mpageoffset = Positionoffset; Invalidate ();if(Mlistener! =NULL) {mlistener.onpagescrolled (position, Positionoffset, positionoffsetpixels); }}@Override Public void onpageselected(intPosition) {if(Msnap | | mscrollstate = = viewpager.scroll_state_idle) {mcurrentpage = position; Msnappage = position; Invalidate (); }if(Mlistener! =NULL) {mlistener.onpageselected (position); }}
- (5) Then draw our small dots in the OnDraw () method based on the offset
@Overrideprotected void OnDraw(Canvas canvas) {Super. OnDraw (canvas);if(Mviewpager = =NULL) {return; }Final intCount = Mviewpager.getadapter (). GetCount ();if(Count = =0) {return; }if(Mcurrentpage >= count) {Setcurrentitem (Count-1);return; }intLongsize;intLongpaddingbefore;intLongpaddingafter;intShortpaddingbefore;//Initialize each variable according to the different direction if(morientation = = horizontal) {longsize = GetWidth (); Longpaddingbefore = Getpaddingleft (); Longpaddingafter = Getpaddingright (); Shortpaddingbefore = Getpaddingtop (); }Else{longsize = GetHeight (); Longpaddingbefore = Getpaddingtop (); Longpaddingafter = Getpaddingbottom (); Shortpaddingbefore = Getpaddingleft (); }Final floatThreeradius = Mradius *3;Final floatShortoffset = Shortpaddingbefore + Mradius;floatLongoffset = Longpaddingbefore + Mradius;/** * Center Display time * / if(mcentered) {Longoffset + = ((longsize-longpaddingbefore-longpaddingafter)/2.0f)-((Count * Threeradius)/2.0f); }floatDX;floatDY;floatPagefillradius = Mradius;if(Mpaintstroke.getstrokewidth () >0) {Pagefillradius-= Mpaintstroke.getstrokewidth ()/2.0F }//draw stroked circles for(intILoop =0; ILoop < count; iloop++) {floatDrawlong = Longoffset + (ILoop * Threeradius);if(morientation = = horizontal) {DX = Drawlong; DY = Shortoffset; }Else{DX = Shortoffset; DY = Drawlong; }//Only paint fill if not completely transparent if(Mpaintpagefill.getalpha () >0) {canvas.drawcircle (DX, DY, Pagefillradius, Mpaintpagefill); }//Only paint stroke if a stroke width is Non-zero if(Pagefillradius! = Mradius) {canvas.drawcircle (DX, DY, Mradius, Mpaintstroke); } }//Draw a moving solid circle below floatCX = (msnap msnappage:mcurrentpage) * Threeradius;//Calculates the offset based on whether the moving solid circle jumps if(!MSNAP) {CX + = Mpageoffset * Threeradius; }if(morientation = = horizontal) {DX = Longoffset + cx; DY = Shortoffset; }Else{DX = Shortoffset; DY = Longoffset + cx; } canvas.drawcircle (DX, DY, Mradius, Mpaintfill);}
In fact, the core is based on the direction of the different plot of our small dots, those offsets are some mathematical operations, but do not underestimate these, the calculation of these offsets is quite cumbersome.
So far, our source code analysis.
Off Topic
Welcome to the star or fork on GitHub if you think it's OK, thanks, GitHub project address Viewpagertabindicator
source GitHub Reference Library Viewpagerindicator:
Reprint please indicate the original blog address:
Source:
Android build not the same as the Novice boot page (i)