Java tutorial
/* * Copyright (C) 2015 Raikun.jp * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jp.raikun.library.widget; import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Typeface; import android.os.Build; import android.support.v4.view.PagerAdapter; import android.util.AttributeSet; import android.util.TypedValue; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; import android.widget.HorizontalScrollView; import android.widget.LinearLayout; import android.widget.TextView; /** * ???????? * @author Raikun.jp */ public class InfiniteTabsLayout extends HorizontalScrollView { private static final int TITLE_OFFSET_DIPS = 24; private static final int TAB_VIEW_PADDING_DIPS = 16; private static final int TAB_VIEW_TEXT_SIZE_SP = 12; /** * ???() */ private static final int DEFAULT_SELECTED_INDICATOR_COLOR = 0xFF33B5E5; private LinearLayout mTabContainer; private LoopViewPager mViewPager; private LoopViewPager.OnPageChangeListener mViewPagerPageChangeListener; private Paint mCenterIndicatorPaint; public InfiniteTabsLayout(Context context) { this(context, null); } public InfiniteTabsLayout(Context context, AttributeSet attrs) { this(context, attrs, 0); } public InfiniteTabsLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); this.setFillViewport(true); this.setWillNotDraw(false); // ? this.mTabContainer = new LinearLayout(context); this.mTabContainer.setOrientation(LinearLayout.HORIZONTAL); // this.mTabContainer.setWeightSum(3); this.addView(this.mTabContainer, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); // ???? this.mCenterIndicatorPaint = new Paint(); this.mCenterIndicatorPaint.setColor(DEFAULT_SELECTED_INDICATOR_COLOR); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); // ? (??) double tabWidth = Math.ceil(w / 3.0); for (int i = 0; i < this.mTabContainer.getChildCount(); i++) { View v = this.mTabContainer.getChildAt(i); v.getLayoutParams().width = (int) tabWidth; } } /** * ???????<br /> * ?????ViewPager????????????<br /> * ????????? * @param listener */ public void setOnPageChangeListener(LoopViewPager.OnPageChangeListener listener) { this.mViewPagerPageChangeListener = listener; } /** * ???????? * @param viewPager */ public void setViewPager(LoopViewPager viewPager) { this.mTabContainer.removeAllViews(); this.mViewPager = viewPager; if (viewPager != null) { viewPager.setOnPageChangeListener(new InternalViewPagerListener()); this.populateTabStrip(); } } /** * ????? * @param color (ARGB) */ public void setCenterIndicatorColor(int color) { this.mCenterIndicatorPaint.setColor(color); this.invalidate(); } /** * ?? * @param context Application context * @return created tab view */ protected TextView createDefaultTabView(Context context) { TextView textView = new TextView(context); textView.setGravity(Gravity.CENTER); textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, TAB_VIEW_TEXT_SIZE_SP); textView.setTypeface(Typeface.DEFAULT_BOLD); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { // If we're running on Honeycomb or newer, then we can use the Theme's // selectableItemBackground to ensure that the View has a pressed state TypedValue outValue = new TypedValue(); getContext().getTheme().resolveAttribute(android.R.attr.selectableItemBackground, outValue, true); textView.setBackgroundResource(outValue.resourceId); } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { // If we're running on ICS or newer, enable all-caps to match the Action Bar tab style textView.setAllCaps(true); } int padding = (int) (TAB_VIEW_PADDING_DIPS * getResources().getDisplayMetrics().density); textView.setPadding(padding, padding, padding, padding); return textView; } /** * ??? */ private void populateTabStrip() { final PagerAdapter adapter = this.mViewPager.getAdapter(); final OnClickListener tabClickListener = new TabClickListener(); int count = adapter.getCount(); double tabWidth = Math.ceil(this.getWidth() / 3.0); if (count <= 0) { return; } // ?????????????????UI???????????? for (int i = 0; i < (count + 3); i++) { View tabView = null; TextView tabTitleView = null; tabView = this.createDefaultTabView(this.getContext()); if (tabTitleView == null && TextView.class.isInstance(tabView)) { tabTitleView = (TextView) tabView; } tabTitleView.setText(adapter.getPageTitle(i)); tabView.setOnClickListener(tabClickListener); this.mTabContainer.addView(tabView, (int) tabWidth, LayoutParams.WRAP_CONTENT); } } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); if (this.mViewPager != null) { this.scrollToTab(this.mViewPager.getCurrentItem(), 0); } } @Override public void onWindowFocusChanged(boolean hasWindowFocus) { super.onWindowFocusChanged(hasWindowFocus); // ????????????? if (hasWindowFocus && this.mViewPager != null) { this.scrollToTab(this.mViewPager.getCurrentItem(), 0); } } /** * ? * @param tabIndex ? * @param positionOffset ???????[0-1 */ private void scrollToTab(int tabIndex, float positionOffset) { // double tabWidth = Math.ceil(this.getWidth() / 3.0); // ??? // ????? int offset = (this.getWidth() - (int) tabWidth) / 2; // int centerTabIndex = tabIndex + 1; View centerTab = this.mTabContainer.getChildAt(centerTabIndex); if (centerTab != null) { // ? int left = centerTab.getLeft() + (int) (Math.round(tabWidth * positionOffset)) - offset; // this.scrollTo(left, 0); } } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); final int height = this.getHeight(); final int width = this.getWidth(); // double tabWidth = Math.ceil(width / 3.0); // ????? int offset = (width - (int) tabWidth) / 2; // ??????? offset += this.getScrollX(); // ??? canvas.drawRect(offset, 0, (float) (offset + tabWidth), height, this.mCenterIndicatorPaint); } @Override public boolean onTouchEvent(MotionEvent ev) { return false; // ?? } /** * ???????????? */ private class InternalViewPagerListener implements LoopViewPager.OnPageChangeListener { private int mScrollState; @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { scrollToTab(position, positionOffset); if (mViewPagerPageChangeListener != null) { mViewPagerPageChangeListener.onPageScrolled(position, positionOffset, positionOffsetPixels); } } @Override public void onPageSelected(int position) { if (mViewPagerPageChangeListener != null) { mViewPagerPageChangeListener.onPageSelected(position); } } @Override public void onPageScrollStateChanged(int state) { this.mScrollState = state; if (mViewPagerPageChangeListener != null) { mViewPagerPageChangeListener.onPageScrollStateChanged(state); } } } /** * ?????????????? */ private class TabClickListener implements OnClickListener { @Override public void onClick(View v) { // ?????? for (int i = 0; i < mTabContainer.getChildCount(); i++) { if (v == mTabContainer.getChildAt(i)) { mViewPager.setCurrentItem(i - 1); // ????????????? return; } } } } }