Android high imitation Huawei mobile phone Tab sliding navigation Effect

Source: Internet
Author: User

Android high imitation Huawei mobile phone Tab sliding navigation Effect

First, let's take a look at the implementation effect. Two implementation methods are used:
1. implemented based on LinearLayout, the navigation bar cannot respond to finger sliding
2. Based on HorizontalScrollView, the navigation bar can respond to finger sliding

Although the implementation method is different, it uses the same method, because my interface is encapsulated exactly the same, the following shows the implementation effect.
Implementation Based on LinearLayout:

Implementation Based on HorizontalScrollView:

The difference between the two is that the navigation bar can slide with user operations.

The following only describes the implementation of LinearLayout. HorizontalScrollView only sets a layer of LinearLayout, because it only allows one child control.

Requirement Development point:
1. Write custom controls (Common Methods: constructor, init (), onMeasure, onLayout, onDraw, dispatchDraw)
2. Calculation of the offset of the white dot
3. When there are more than five Tab pages, the combination of the white points and LinearLayout slides to achieve the effect of moving the text while the white points do not move.

To achieve these three points, the control is finished. Of course, some details can be optimized according to your own needs.

1. Write Custom Controls
1) Here is mainly the rewrite of the onMeasure method. The default onMeasure cannot be used. We need to calculate the number of tabs, which is the measure result of 1-6 tabs.

The screen width is evenly divided based on the number of tabs. When the number of tabs exceeds 5, only 5 screens are displayed to maintain the effect. The excess content is appended to the screen, the screen is bounded, and the view is unbounded. You can add the screen to the right without limit. If the memory can accommodate it, you can use a for loop to add it infinitely to see what happened.

2) rewrite the dispatchDraw method. Here, the dispatchDraw method is used to draw a white dot.

Calculation of the Offset of a white dot
This must be calculated by the OnPageChangeListener of ViewPager through its onPageScrolled callback. After calculation, the invalidate () method is called for re-painting.

When there are more than five Tab pages, the combination of the white points and the LinearLayout content slides to achieve the effect of moving the text while the white points remain unchanged.
When sliding to 5th tabs, if only a white dot is moved, it will be moved out of the screen. In this case, we also need to link the LinearLayout content through the scrollTo method, move the content to the opposite direction of the white point, so that it is in balance with the white point movement, so that the white point does not move, the above title content moves.

The following analysis shows the variables required by the control:

1. It needs to be white, right? We use a Paint brush, So Paint needs
2. How big is white dot painting? Therefore, a white point radius variable radius is required.
3. the offset of the white point. We define a variable mOffset, Which is dynamically calculated based on the sliding of ViewPager.
4. There is a row of text above, which is implemented using TextView. This TextView is dynamically added based on the number of tabs, and the quantity is uncontrollable. I have not defined it as a variable here. However, the text content corresponds to a Fragment title, that is, the title and Fragment are one-to-one correspondence. OK. Use Map.

/*** Set Key for storing the Tab: Fragment of the navigation bar: navigation page */private Map
  
   
MTabs;
  

TextView is dynamically added based on the quantity of mTabs.
5. How can we calculate the sliding offset? This depends on the OnPageChangeListener of ViewPager to calculate the mOffset through its onPageScrolled callback. It is through this calculation of the dot offset. Here I hold a reference of ViewPager, so there is a variable mViewPager, in fact, it does not matter much.
6. the maximum number of tabs that can be displayed on the screen MAX_VISIBLE_TAB_COUNTS. If there are no 100 tabs, you can display 100.
7. Number of tabs displayed on the actual screen mRealVisibleTabCounts
8. The screen width is calculated by mScreenWidth to assist onMeasure.

The following is the implementation code:

Package com. csm. hwtab; import java. util. arrayList; import java. util. linkedHashMap; import java. util. list; import java. util. map; import android. annotation. suppressLint; import android. content. context; import android. graphics. canvas; import android. graphics. color; import android. graphics. paint; import android. graphics. paint. cap; import android. graphics. paint. style; import android. support. v4.app. fragment; import android. support. v4.view. viewPager; import android. support. v4.view. viewPager. onPageChangeListener; import android. util. attributeSet; import android. util. displayMetrics; import android. util. typedValue; import android. view. gravity; import android. view. view; import android. view. view. onClickListener; import android. widget. linearLayout; import android. widget. textView;/*** @ author Rander. C */@ SuppressLint ("NewApi") public class TabLinearLayout extends LinearLayout implements OnClickListener, OnPageChangeListener {/*** the maximum number of tabs that can be displayed, you can write custom attributes and configure */private static final int MAX_VISIBLE_TAB_COUNTS = 5 in xml;/*** the actual number of visible tabs. For example, there are 8 or more tabs, to ensure the effect, a maximum of five * are displayed. At this time, mRealVisibleTabCounts is 5 *. If only three tabs are smaller than five, mRealVisibleTabCounts is 3 * and the width of each tab is calculated based on this, divide the screen width by mRealVisibleTabCounts */private int mRealVisibleTabCounts;/*** sliding offset of a small dot */private float mOffset;/*** draw a small dot Paint brush */private Paint mPaint; /***** dot radius */private int mCircleRadius;/***** screen width */private int mScreenWidth;/*** set Key for storing tabs: Fragment in the navigation bar title: navigation page */private Map
  
   
MTabs;/*** there is the getContext () method in the View. If you use a variable, * One more Context reference will increase the workload of a virtual machine? * If you do not need variables, but use getContext () every time, do you need to have one more layer * Call Stack? How can you weigh the call stack and find the answer? Or do I think more? */Private Context mContext; private ViewPager mViewPager; public TabLinearLayout (Context context, AttributeSet attrs) {this (context, attrs,-1);} public TabLinearLayout (Context context) {this (context, null);} public TabLinearLayout (Context context, AttributeSet attrs, int defStyleAttr) {super (context, attrs, defStyleAttr); init ();} private void init () {mContext = getContext (); setOrientati On (HORIZONTAL); mPaint = new Paint (); mPaint. setAntiAlias (true); mPaint. setDither (true); mPaint. setStyle (Style. FILL); mPaint. setColor (Color. WHITE); mPaint. setStrokeCap (Cap. ROUND); DisplayMetrics metrics = getResources (). getDisplayMetrics (); mScreenWidth = metrics. widthPixels; mCircleRadius = (int) getResources (). getDimension (R. dimen. radius) ;}@ Override protected void onMeasure (int widthMeasureSpe C, int heightMeasureSpec) {super. onMeasure (widthMeasureSpec, heightMeasureSpec); int tabCount = getChildCount (); if (tabCount = 0) {return;}/** regardless of the default measurement result, we need to re-assign the value */mRealVisibleTabCounts = MAX_VISIBLE_TAB_COUNTS <tabCount? Authorization: tabCount; // re-allocate the mScreenWidth/mRealVisibleTabCounts width int averageWidth = mScreenWidth/mRealVisibleTabCounts; for (int I = 0; I <tabCount; I ++) {View view = getChildAt (I); LinearLayout. layoutParams params = (android. widget. linearLayout. layoutParams) view. getLayoutParams (); params. weight = 0; params. width = averageWidth; view. setLayoutParams (params) ;}}/*** get the Tabs List * @ return */public List
   
    
GetTabs () {return new ArrayList (mTabs. values ();}/*** Add a Tab, add a TextView * @ param title * @ param tab */public void addTab (String title, Fragment tab) to * this view) {if (mTabs = null) {mTabs = new LinkedHashMap <> ();} mTabs. put (title, tab); addView (createTabItem (title, mTabs. size ()-1);}/*** sets ViewPager * and sets the OnPageChangeListener listener for it. * @ Param viewPager */public void setViewPager (ViewPager viewPager) {mViewPager = viewPager; mViewPager. setOnPageChangeListener (this );} /*** create a Tab View * @ param title the title corresponding to Fragment * @ param index the index subscript corresponding to the Fragment * @ return the constructed tab View */private View createTabItem (string title, int index) {TextView TV _title = new TextView (mContext); TV _title.setText (title); TV _title.setTag (index); TV _title.setG Ravity (Gravity. CENTER); TV _title.setTextColor (Color. WHITE); TV _title.setTextSize (TypedValue. COMPLEX_UNIT_SP, 18); TV _title.setOnClickListener (this); return TV _title ;}@ Override public void onClick (View v) {int tabIndex = (Integer) v. getTag (); if (onTabOperatorListener! = Null) {onTabOperatorListener. onTabClick (tabIndex);} mViewPager. setCurrentItem (tabIndex) ;}@ Override public void onPageScrollStateChanged (int state) {if (null! = OnTabOperatorListener) {onTabOperatorListener. listener (state) ;}@override public void watermark (int sourcePosition, float positionOffset, int positionOffsetPixels) {response = Response <getChildCount ()? MAX_VISIBLE_TAB_COUNTS: getChildCount (); int tabWidth = getWidth ()/mRealVisibleTabCounts; // calculates the offset of a small dot. This can be interpreted as mOffset = (int) (tabWidth/2 + sourcePosition * tabWidth + positionOffset * tabWidth); // If you scroll to the last one, you must also scroll to the left tab content. In this case, the origin is moved to the right, at the same time, the overall sliding is done, and the two slides offset each other, which is equivalent to the fact that the origin does not move if (getChildCount ()> mRealVisibleTabCounts & positionOffset> 0 & sourcePosition> = mRealVisibleTabCounts) {scrollTo (( Int) (sourcePosition + 1-mRealVisibleTabCounts) * tabWidth + tabWidth * positionOffset), 0);} invalidate (); if (null! = OnTabOperatorListener) {onTabOperatorListener. onTabScrolled (sourcePosition, positionOffset, positionOffsetPixels); }}@ Override public void onPageSelected (int index) {if (null! = OnTabOperatorListener) {onTabOperatorListener. onTabSelected (index);}/*** do not think too much here, just to ensure that when the Selected tab is the first, reset the layout to the origin */if (index = 0) {scrollTo (0, 0) ;}}/*** Tab operator-related listener * @ author rander */public interface OnTabOperatorListener {void onTabClick (int tabIndex ); void onTabSelected (int tabIndex); void onTabScrolled (int sourcePosition, float positionOffset, int positionOffsetPixels); void merge (int state);} public writable listener; public void setOnTabItemClickListener (partial listener) {this. onTabOperatorListener = onTabOperatorListener;} @ Override protected void dispatchDraw (Canvas canvas) {super. dispatchDraw (canvas); // if there is only one Tab, do not draw the dot if (getChildCount () <= 1) {return ;}// draw the offset canvas according to mOffset. drawCircle (mOffset, getHeight ()-mCircleRadius * 2, mCircleRadius, mPaint );}}
   
  

Understanding of offset calculation drawing:
Offset calculation expression:

mOffset = (int) (tabWidth / 2 + sourcePosition * tabWidth + positionOffset * tabWidth );

Illustration:

The first and second vertical bars: tabWidth/2
The second and third vertical bars: sourcePosition * tabWidth
The third vertical line and the fourth vertical line: pZ vertical? Http://www.bkjia.com/kf/ware/vc/ "target =" _ blank "class =" keylink "> Principal + C8077NysfGq9LGwb/Principal + PGq9LGwb/By6Osc2Nyb2xsVG + Principal + PC9wPg0KPHA + Principal + principal =" brush: java; ">

Use in Activity:

Package com. csm. hwtab; import com. csm. hwtab. adapter. myFragmentPagerAdapter; import com. csm. hwtab. fragment. oneFragment; import android. OS. bundle; import android. support. v4.app. fragmentActivity; import android. support. v4.view. viewPager; import android. view. window; public class TestActivity extends FragmentActivity {private ViewPager mViewPager; private TabLinearLayout mTabview; @ Override protected void onCreate (Bundle savedInstanceState) {super. onCreate (savedInstanceState); requestWindowFeature (Window. FEATURE_NO_TITLE); setContentView (R. layout. tab); initTabsView ();} private void initTabsView () {mViewPager = (ViewPager) findViewById (R. id. view_pager); mTabview = (TabLinearLayout) findViewById (R. id. tab); mTabview. addTab (" 0", new OneFragment (); mTabview. addTab ("Pre-Qin 1", new OneFragment (); mTabview. addTab ("Pre-Qin 2", new OneFragment (); mTabview. addTab ("Pre-Qin 3", new OneFragment (); mTabview. addTab ("Pre-Qin 4", new OneFragment (); mTabview. addTab ("Pre-Qin 5", new OneFragment (); mTabview. addTab (" 6", new OneFragment (); mViewPager. setAdapter (new MyFragmentPagerAdapter (getSupportFragmentManager (), mTabview. getTabs (); mTabview. setViewPager (mViewPager); mViewPager. setCurrentItem (0 );}}

The effect is the same as the above.

Github: https://github.com/shuangmin/HwTab

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.