= ArrayList()
+ try {
+ if (bitmap!!.width == bitmap.height) {
+ pieces.add(BitmapDrawable(bitmap))
+ } else {
+ val matrix = Matrix()
+ matrix.setScale(0.5f, 0.5f)
+
+ val width = bitmap.width
+ val pieceWidth = bitmap.height
+ val pieceHeight = bitmap.height
+ val xPiece = width / pieceWidth
+ for (j in 0 until xPiece) {
+ val xValue = j * pieceWidth
+ pieces.add(
+ BitmapDrawable(
+ Bitmap.createBitmap(
+ bitmap, xValue, 0,
+ pieceWidth, pieceHeight, matrix, true
+ )
+ )
+ )
+ }
+ }
+ } catch (e: java.lang.Exception) {
+ }
+ return pieces
}
private fun loadSVGAFile(url: String, path: String,autoPayer:Boolean = true) {
try {
- logD("loadSVGAFile path:$path url:$url")
+ logD("SVGAView loadSVGAFile path:$path url:$url")
val inputStream = BufferedInputStream(FileInputStream(path))
shareParser().decodeFromInputStream(
inputStream,
@@ -188,7 +278,7 @@ class SVGAView : SVGAImageView, ILog {
)
} catch (e: Exception) {
e.printStackTrace()
- logD("loadSVGAFile url:$url e:${e.message}")
+ logD("SVGAView loadSVGAFile url:$url e:${e.message}")
onViewStateChanged(-1)
}
}
@@ -197,16 +287,16 @@ class SVGAView : SVGAImageView, ILog {
* @param state -1 异常、0 空、1 成功
*/
private fun onViewStateChanged(state: Int) {
- logD("onViewStateChanged state:$state")
+ logD("SVGAView onViewStateChanged state:$state")
}
fun bindCache(cache: SVGACache?) {
- logD("bindCache() cache:$cache")
+ logD("SVGAView bindCache() cache:$cache")
this.svgaCache = cache
}
fun setLogTag(tag: String) {
- logD("setLogTag() newTag:$tag oldTag:$logTag")
+ logD("SVGAView setLogTag() newTag:$tag oldTag:$logTag")
this.logTag = tag
}
@@ -219,23 +309,25 @@ class SVGAView : SVGAImageView, ILog {
}
override fun onDetachedFromWindow() {
- logD("onDetachedFromWindow()")
+ logD("SVGAView onDetachedFromWindow()")
super.onDetachedFromWindow()
}
override fun onAttachedToWindow() {
- logD("onAttachedToWindow()")
+ logD("SVGAView onAttachedToWindow()")
super.onAttachedToWindow()
if (resumePlayAfterAttached) {
if (drawable is SVGADrawable) {
if (!isAnimating) {
- logD("onAttachedToWindow() startAnimation")
+ logD("SVGAView onAttachedToWindow() startAnimation")
startAnimation()
}
}
}
}
+
+
interface SVGACache {
fun get(key: String): SVGAVideoEntity?
diff --git a/library/src/main/java/com/chwl/library/widget/tab/SmartTabIndicationInterpolator.java b/library/src/main/java/com/chwl/library/widget/tab/SmartTabIndicationInterpolator.java
new file mode 100644
index 000000000..2ae177692
--- /dev/null
+++ b/library/src/main/java/com/chwl/library/widget/tab/SmartTabIndicationInterpolator.java
@@ -0,0 +1,96 @@
+/**
+ * Copyright (C) 2015 ogaclejapan
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * 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 com.chwl.library.widget.tab;
+
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.Interpolator;
+
+public abstract class SmartTabIndicationInterpolator {
+
+ public static final SmartTabIndicationInterpolator SMART = new SmartIndicationInterpolator();
+ public static final SmartTabIndicationInterpolator LINEAR = new LinearIndicationInterpolator();
+
+ static final int ID_SMART = 0;
+ static final int ID_LINEAR = 1;
+
+ public static SmartTabIndicationInterpolator of(int id) {
+ switch (id) {
+ case ID_SMART:
+ return SMART;
+ case ID_LINEAR:
+ return LINEAR;
+ default:
+ throw new IllegalArgumentException("Unknown id: " + id);
+ }
+ }
+
+ public abstract float getLeftEdge(float offset);
+
+ public abstract float getRightEdge(float offset);
+
+ public float getThickness(float offset) {
+ return 1f; //Always the same thickness by default
+ }
+
+ public static class SmartIndicationInterpolator extends SmartTabIndicationInterpolator {
+
+ private static final float DEFAULT_INDICATOR_INTERPOLATION_FACTOR = 3.0f;
+
+ private final Interpolator leftEdgeInterpolator;
+ private final Interpolator rightEdgeInterpolator;
+
+ public SmartIndicationInterpolator() {
+ this(DEFAULT_INDICATOR_INTERPOLATION_FACTOR);
+ }
+
+ public SmartIndicationInterpolator(float factor) {
+ leftEdgeInterpolator = new AccelerateInterpolator(factor);
+ rightEdgeInterpolator = new DecelerateInterpolator(factor);
+ }
+
+ @Override
+ public float getLeftEdge(float offset) {
+ return leftEdgeInterpolator.getInterpolation(offset);
+ }
+
+ @Override
+ public float getRightEdge(float offset) {
+ return rightEdgeInterpolator.getInterpolation(offset);
+ }
+
+ @Override
+ public float getThickness(float offset) {
+ return 1f / (1.0f - getLeftEdge(offset) + getRightEdge(offset));
+ }
+
+ }
+
+ public static class LinearIndicationInterpolator extends SmartTabIndicationInterpolator {
+
+ @Override
+ public float getLeftEdge(float offset) {
+ return offset;
+ }
+
+ @Override
+ public float getRightEdge(float offset) {
+ return offset;
+ }
+
+ }
+}
diff --git a/library/src/main/java/com/chwl/library/widget/tab/SmartTabLayout.java b/library/src/main/java/com/chwl/library/widget/tab/SmartTabLayout.java
new file mode 100644
index 000000000..92c8062f7
--- /dev/null
+++ b/library/src/main/java/com/chwl/library/widget/tab/SmartTabLayout.java
@@ -0,0 +1,644 @@
+/**
+ * Copyright (C) 2015 ogaclejapan
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * 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 com.chwl.library.widget.tab;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.content.res.TypedArray;
+import android.graphics.Typeface;
+import android.os.Build;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.HorizontalScrollView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import androidx.core.view.ViewCompat;
+import androidx.viewpager.widget.PagerAdapter;
+import androidx.viewpager.widget.ViewPager;
+
+import com.chwl.library.R;
+
+/**
+ * To be used with ViewPager to provide a tab indicator component which give constant feedback as
+ * to
+ * the user's scroll progress.
+ *
+ * To use the component, simply add it to your view hierarchy. Then in your
+ * {@link android.app.Activity} or {@link androidx.fragment.app.Fragment} call
+ * {@link #setViewPager(ViewPager)} providing it the ViewPager this
+ * layout
+ * is being used for.
+ *
+ * The colors can be customized in two ways. The first and simplest is to provide an array of
+ * colors
+ * via {@link #setSelectedIndicatorColors(int...)} and {@link #setDividerColors(int...)}. The
+ * alternative is via the {@link TabColorizer} interface which provides you complete control over
+ * which color is used for any individual position.
+ *
+ * The views used as tabs can be customized by calling {@link #setCustomTabView(int, int)},
+ * providing the layout ID of your custom layout.
+ *
+ * Forked from Google Samples > SlidingTabsBasic >
+ * SlidingTabLayout
+ */
+public class SmartTabLayout extends HorizontalScrollView {
+
+ private static final boolean DEFAULT_DISTRIBUTE_EVENLY = false;
+ private static final int TITLE_OFFSET_DIPS = 24;
+ private static final int TITLE_OFFSET_AUTO_CENTER = -1;
+ private static final int TAB_VIEW_PADDING_DIPS = 16;
+ private static final boolean TAB_VIEW_TEXT_ALL_CAPS = true;
+ private static final int TAB_VIEW_TEXT_SIZE_SP = 12;
+ private static final int TAB_VIEW_TEXT_COLOR = 0xFC000000;
+ private static final int TAB_VIEW_TEXT_MIN_WIDTH = 0;
+ private static final boolean TAB_CLICKABLE = true;
+ private static final int NO_TEXT_STYLE = -1;
+
+ protected final SmartTabStrip tabStrip;
+ private int titleOffset;
+ private int tabViewBackgroundResId;
+ private boolean tabViewTextAllCaps;
+ private ColorStateList tabViewTextColors;
+ private float tabViewTextSize;
+ private int tabViewTextHorizontalPadding;
+ private int tabViewTextMinWidth;
+ private ViewPager viewPager;
+ private ViewPager.OnPageChangeListener viewPagerPageChangeListener;
+ private OnScrollChangeListener onScrollChangeListener;
+ private TabProvider tabProvider;
+ private InternalTabClickListener internalTabClickListener;
+ private OnTabClickListener onTabClickListener;
+ private boolean distributeEvenly;
+ private int textAppearance;
+
+ public SmartTabLayout(Context context) {
+ this(context, null);
+ }
+
+ public SmartTabLayout(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public SmartTabLayout(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+
+ // Disable the Scroll Bar
+ setHorizontalScrollBarEnabled(false);
+
+ final DisplayMetrics dm = getResources().getDisplayMetrics();
+ final float density = dm.density;
+
+ int tabBackgroundResId = NO_ID;
+ boolean textAllCaps = TAB_VIEW_TEXT_ALL_CAPS;
+ ColorStateList textColors;
+ float textSize = TypedValue.applyDimension(
+ TypedValue.COMPLEX_UNIT_SP, TAB_VIEW_TEXT_SIZE_SP, dm);
+ int textHorizontalPadding = (int) (TAB_VIEW_PADDING_DIPS * density);
+ int textMinWidth = (int) (TAB_VIEW_TEXT_MIN_WIDTH * density);
+ boolean distributeEvenly = DEFAULT_DISTRIBUTE_EVENLY;
+ int customTabLayoutId = NO_ID;
+ int customTabTextViewId = NO_ID;
+ boolean clickable = TAB_CLICKABLE;
+ int titleOffset = (int) (TITLE_OFFSET_DIPS * density);
+ int textStyle = NO_TEXT_STYLE;
+
+ TypedArray a = context.obtainStyledAttributes(
+ attrs, R.styleable.stl_SmartTabLayout, defStyle, 0);
+ tabBackgroundResId = a.getResourceId(
+ R.styleable.stl_SmartTabLayout_stl_defaultTabBackground, tabBackgroundResId);
+ textAllCaps = a.getBoolean(
+ R.styleable.stl_SmartTabLayout_stl_defaultTabTextAllCaps, textAllCaps);
+ textColors = a.getColorStateList(
+ R.styleable.stl_SmartTabLayout_stl_defaultTabTextColor);
+ textSize = a.getDimension(
+ R.styleable.stl_SmartTabLayout_stl_defaultTabTextSize, textSize);
+ textHorizontalPadding = a.getDimensionPixelSize(
+ R.styleable.stl_SmartTabLayout_stl_defaultTabTextHorizontalPadding, textHorizontalPadding);
+ textMinWidth = a.getDimensionPixelSize(
+ R.styleable.stl_SmartTabLayout_stl_defaultTabTextMinWidth, textMinWidth);
+ customTabLayoutId = a.getResourceId(
+ R.styleable.stl_SmartTabLayout_stl_customTabTextLayoutId, customTabLayoutId);
+ customTabTextViewId = a.getResourceId(
+ R.styleable.stl_SmartTabLayout_stl_customTabTextViewId, customTabTextViewId);
+ distributeEvenly = a.getBoolean(
+ R.styleable.stl_SmartTabLayout_stl_distributeEvenly, distributeEvenly);
+ clickable = a.getBoolean(
+ R.styleable.stl_SmartTabLayout_stl_clickable, clickable);
+ titleOffset = a.getLayoutDimension(
+ R.styleable.stl_SmartTabLayout_stl_titleOffset, titleOffset);
+ textStyle = a.getResourceId(R.styleable.stl_SmartTabLayout_stl_tabTextStyle, textStyle);
+ a.recycle();
+
+ this.titleOffset = titleOffset;
+ this.tabViewBackgroundResId = tabBackgroundResId;
+ this.tabViewTextAllCaps = textAllCaps;
+ this.tabViewTextColors = (textColors != null)
+ ? textColors
+ : ColorStateList.valueOf(TAB_VIEW_TEXT_COLOR);
+ this.tabViewTextSize = textSize;
+ this.tabViewTextHorizontalPadding = textHorizontalPadding;
+ this.tabViewTextMinWidth = textMinWidth;
+ this.internalTabClickListener = clickable ? new InternalTabClickListener() : null;
+ this.distributeEvenly = distributeEvenly;
+ this.textAppearance = textStyle;
+
+ if (customTabLayoutId != NO_ID) {
+ setCustomTabView(customTabLayoutId, customTabTextViewId);
+ }
+
+ this.tabStrip = new SmartTabStrip(context, attrs);
+
+ if (distributeEvenly && tabStrip.isIndicatorAlwaysInCenter()) {
+ throw new UnsupportedOperationException(
+ "'distributeEvenly' and 'indicatorAlwaysInCenter' both use does not support");
+ }
+
+ // Make sure that the Tab Strips fills this View
+ setFillViewport(!tabStrip.isIndicatorAlwaysInCenter());
+
+ addView(tabStrip, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+
+ }
+
+ @Override
+ protected void onScrollChanged(int l, int t, int oldl, int oldt) {
+ super.onScrollChanged(l, t, oldl, oldt);
+ if (onScrollChangeListener != null) {
+ onScrollChangeListener.onScrollChanged(l, oldl);
+ }
+ }
+
+ @Override
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ super.onSizeChanged(w, h, oldw, oldh);
+ if (tabStrip.isIndicatorAlwaysInCenter() && tabStrip.getChildCount() > 0) {
+ View firstTab = tabStrip.getChildAt(0);
+ View lastTab = tabStrip.getChildAt(tabStrip.getChildCount() - 1);
+ int start = (w - Utils.getMeasuredWidth(firstTab)) / 2 - Utils.getMarginStart(firstTab);
+ int end = (w - Utils.getMeasuredWidth(lastTab)) / 2 - Utils.getMarginEnd(lastTab);
+ tabStrip.setMinimumWidth(tabStrip.getMeasuredWidth());
+ ViewCompat.setPaddingRelative(this, start, getPaddingTop(), end, getPaddingBottom());
+ setClipToPadding(false);
+ }
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ super.onLayout(changed, l, t, r, b);
+ // Ensure first scroll
+ if (changed && viewPager != null) {
+ scrollToTab(viewPager.getCurrentItem(), 0);
+ }
+ }
+
+ /**
+ * Set the behavior of the Indicator scrolling feedback.
+ *
+ * @param interpolator {@link com.ogaclejapan.smarttablayout.SmartTabIndicationInterpolator}
+ */
+ public void setIndicationInterpolator(SmartTabIndicationInterpolator interpolator) {
+ tabStrip.setIndicationInterpolator(interpolator);
+ }
+
+ /**
+ * Set the custom {@link TabColorizer} to be used.
+ *
+ * If you only require simple customisation then you can use
+ * {@link #setSelectedIndicatorColors(int...)} and {@link #setDividerColors(int...)} to achieve
+ * similar effects.
+ */
+ public void setCustomTabColorizer(TabColorizer tabColorizer) {
+ tabStrip.setCustomTabColorizer(tabColorizer);
+ }
+
+ /**
+ * Set the color used for styling the tab text. This will need to be called prior to calling
+ * {@link #setViewPager(ViewPager)} otherwise it will not get set
+ *
+ * @param color to use for tab text
+ */
+ public void setDefaultTabTextColor(int color) {
+ tabViewTextColors = ColorStateList.valueOf(color);
+ }
+
+ /**
+ * Sets the colors used for styling the tab text. This will need to be called prior to calling
+ * {@link #setViewPager(ViewPager)} otherwise it will not get set
+ *
+ * @param colors ColorStateList to use for tab text
+ */
+ public void setDefaultTabTextColor(ColorStateList colors) {
+ tabViewTextColors = colors;
+ }
+
+ /**
+ * Set the same weight for tab
+ */
+ public void setDistributeEvenly(boolean distributeEvenly) {
+ this.distributeEvenly = distributeEvenly;
+ }
+
+ /**
+ * Sets the colors to be used for indicating the selected tab. These colors are treated as a
+ * circular array. Providing one color will mean that all tabs are indicated with the same color.
+ */
+ public void setSelectedIndicatorColors(int... colors) {
+ tabStrip.setSelectedIndicatorColors(colors);
+ }
+
+ /**
+ * Sets the colors to be used for tab dividers. These colors are treated as a circular array.
+ * Providing one color will mean that all tabs are indicated with the same color.
+ */
+ public void setDividerColors(int... colors) {
+ tabStrip.setDividerColors(colors);
+ }
+
+ /**
+ * Set the {@link ViewPager.OnPageChangeListener}. When using {@link SmartTabLayout} you are
+ * required to set any {@link ViewPager.OnPageChangeListener} through this method. This is so
+ * that the layout can update it's scroll position correctly.
+ *
+ * @see ViewPager#setOnPageChangeListener(ViewPager.OnPageChangeListener)
+ */
+ public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) {
+ viewPagerPageChangeListener = listener;
+ }
+
+ /**
+ * Set {@link OnScrollChangeListener} for obtaining values of scrolling.
+ *
+ * @param listener the {@link OnScrollChangeListener} to set
+ */
+ public void setOnScrollChangeListener(OnScrollChangeListener listener) {
+ onScrollChangeListener = listener;
+ }
+
+ /**
+ * Set {@link OnTabClickListener} for obtaining click event.
+ *
+ * @param listener the {@link OnTabClickListener} to set
+ */
+ public void setOnTabClickListener(OnTabClickListener listener) {
+ onTabClickListener = listener;
+ }
+
+ /**
+ * Set the custom layout to be inflated for the tab views.
+ *
+ * @param layoutResId Layout id to be inflated
+ * @param textViewId id of the {@link TextView} in the inflated view
+ */
+ public void setCustomTabView(int layoutResId, int textViewId) {
+ tabProvider = new SimpleTabProvider(getContext(), layoutResId, textViewId);
+ }
+
+ /**
+ * Set the custom layout to be inflated for the tab views.
+ *
+ * @param provider {@link TabProvider}
+ */
+ public void setCustomTabView(TabProvider provider) {
+ tabProvider = provider;
+ }
+
+ /**
+ * Sets the associated view pager. Note that the assumption here is that the pager content
+ * (number of tabs and tab titles) does not change after this call has been made.
+ */
+ public void setViewPager(ViewPager viewPager) {
+ tabStrip.removeAllViews();
+
+ this.viewPager = viewPager;
+ if (viewPager != null && viewPager.getAdapter() != null) {
+ viewPager.addOnPageChangeListener(new InternalViewPagerListener());
+ populateTabStrip();
+ }
+ }
+
+ /**
+ * Returns the view at the specified position in the tabs.
+ *
+ * @param position the position at which to get the view from
+ * @return the view at the specified position or null if the position does not exist within the
+ * tabs
+ */
+ public View getTabAt(int position) {
+ return tabStrip.getChildAt(position);
+ }
+
+ /**
+ * Create a default view to be used for tabs. This is called if a custom tab view is not set via
+ * {@link #setCustomTabView(int, int)}.
+ */
+ protected TextView createDefaultTabView(CharSequence title) {
+ TextView textView = new TextView(getContext());
+ textView.setGravity(Gravity.CENTER);
+ textView.setText(title);
+ if (textAppearance != NO_TEXT_STYLE) {
+ textView.setTextAppearance(getContext(), textAppearance);
+ } else {
+ textView.setTextColor(tabViewTextColors);
+ textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, tabViewTextSize);
+ textView.setTypeface(Typeface.DEFAULT_BOLD);
+
+ 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(tabViewTextAllCaps);
+ }
+
+ if (tabViewTextMinWidth > 0) {
+ textView.setMinWidth(tabViewTextMinWidth);
+ }
+ }
+ if (tabViewBackgroundResId != NO_ID) {
+ textView.setBackgroundResource(tabViewBackgroundResId);
+ } else {
+ // 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);
+ }
+ textView.setPadding(
+ tabViewTextHorizontalPadding, 0,
+ tabViewTextHorizontalPadding, 0);
+ textView.setLayoutParams(new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.MATCH_PARENT));
+
+ return textView;
+ }
+
+ private void populateTabStrip() {
+ final PagerAdapter adapter = viewPager.getAdapter();
+
+ for (int i = 0; i < adapter.getCount(); i++) {
+
+ final View tabView = (tabProvider == null)
+ ? createDefaultTabView(adapter.getPageTitle(i))
+ : tabProvider.createTabView(tabStrip, i, adapter);
+
+ if (tabView == null) {
+ throw new IllegalStateException("tabView is null.");
+ }
+
+ if (distributeEvenly) {
+ LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) tabView.getLayoutParams();
+ lp.width = 0;
+ lp.weight = 1;
+ }
+
+ if (internalTabClickListener != null) {
+ tabView.setOnClickListener(internalTabClickListener);
+ }
+
+ tabStrip.addView(tabView);
+
+ if (i == viewPager.getCurrentItem()) {
+ tabView.setSelected(true);
+ }
+
+ }
+ }
+
+ private void scrollToTab(int tabIndex, float positionOffset) {
+ final int tabStripChildCount = tabStrip.getChildCount();
+ if (tabStripChildCount == 0 || tabIndex < 0 || tabIndex >= tabStripChildCount) {
+ return;
+ }
+
+ final boolean isLayoutRtl = Utils.isLayoutRtl(this);
+ View selectedTab = tabStrip.getChildAt(tabIndex);
+ int widthPlusMargin = Utils.getWidth(selectedTab) + Utils.getMarginHorizontally(selectedTab);
+ int extraOffset = (int) (positionOffset * widthPlusMargin);
+
+ if (tabStrip.isIndicatorAlwaysInCenter()) {
+
+ if (0f < positionOffset && positionOffset < 1f) {
+ View nextTab = tabStrip.getChildAt(tabIndex + 1);
+ int selectHalfWidth = Utils.getWidth(selectedTab) / 2 + Utils.getMarginEnd(selectedTab);
+ int nextHalfWidth = Utils.getWidth(nextTab) / 2 + Utils.getMarginStart(nextTab);
+ extraOffset = Math.round(positionOffset * (selectHalfWidth + nextHalfWidth));
+ }
+
+ View firstTab = tabStrip.getChildAt(0);
+ int x;
+ if (isLayoutRtl) {
+ int first = Utils.getWidth(firstTab) + Utils.getMarginEnd(firstTab);
+ int selected = Utils.getWidth(selectedTab) + Utils.getMarginEnd(selectedTab);
+ x = Utils.getEnd(selectedTab) - Utils.getMarginEnd(selectedTab) - extraOffset;
+ x -= (first - selected) / 2;
+ } else {
+ int first = Utils.getWidth(firstTab) + Utils.getMarginStart(firstTab);
+ int selected = Utils.getWidth(selectedTab) + Utils.getMarginStart(selectedTab);
+ x = Utils.getStart(selectedTab) - Utils.getMarginStart(selectedTab) + extraOffset;
+ x -= (first - selected) / 2;
+ }
+
+ scrollTo(x, 0);
+ return;
+
+ }
+
+ int x;
+ if (titleOffset == TITLE_OFFSET_AUTO_CENTER) {
+
+ if (0f < positionOffset && positionOffset < 1f) {
+ View nextTab = tabStrip.getChildAt(tabIndex + 1);
+ int selectHalfWidth = Utils.getWidth(selectedTab) / 2 + Utils.getMarginEnd(selectedTab);
+ int nextHalfWidth = Utils.getWidth(nextTab) / 2 + Utils.getMarginStart(nextTab);
+ extraOffset = Math.round(positionOffset * (selectHalfWidth + nextHalfWidth));
+ }
+
+ if (isLayoutRtl) {
+ x = -Utils.getWidthWithMargin(selectedTab) / 2 + getWidth() / 2;
+ x -= Utils.getPaddingStart(this);
+ } else {
+ x = Utils.getWidthWithMargin(selectedTab) / 2 - getWidth() / 2;
+ x += Utils.getPaddingStart(this);
+ }
+
+ } else {
+
+ if (isLayoutRtl) {
+ x = (tabIndex > 0 || positionOffset > 0) ? titleOffset : 0;
+ } else {
+ x = (tabIndex > 0 || positionOffset > 0) ? -titleOffset : 0;
+ }
+
+ }
+
+ int start = Utils.getStart(selectedTab);
+ int startMargin = Utils.getMarginStart(selectedTab);
+ if (isLayoutRtl) {
+ x += start + startMargin - extraOffset - getWidth() + Utils.getPaddingHorizontally(this);
+ } else {
+ x += start - startMargin + extraOffset;
+ }
+
+ scrollTo(x, 0);
+
+ }
+
+ /**
+ * Interface definition for a callback to be invoked when the scroll position of a view changes.
+ */
+ public interface OnScrollChangeListener {
+
+ /**
+ * Called when the scroll position of a view changes.
+ *
+ * @param scrollX Current horizontal scroll origin.
+ * @param oldScrollX Previous horizontal scroll origin.
+ */
+ void onScrollChanged(int scrollX, int oldScrollX);
+ }
+
+ /**
+ * Interface definition for a callback to be invoked when a tab is clicked.
+ */
+ public interface OnTabClickListener {
+
+ /**
+ * Called when a tab is clicked.
+ *
+ * @param position tab's position
+ */
+ void onTabClicked(int position);
+ }
+
+ /**
+ * Create the custom tabs in the tab layout. Set with
+ * {@link #setCustomTabView(com.ogaclejapan.smarttablayout.SmartTabLayout.TabProvider)}
+ */
+ public interface TabProvider {
+
+ /**
+ * @return Return the View of {@code position} for the Tabs
+ */
+ View createTabView(ViewGroup container, int position, PagerAdapter adapter);
+
+ }
+
+ private static class SimpleTabProvider implements TabProvider {
+
+ private final LayoutInflater inflater;
+ private final int tabViewLayoutId;
+ private final int tabViewTextViewId;
+
+ private SimpleTabProvider(Context context, int layoutResId, int textViewId) {
+ inflater = LayoutInflater.from(context);
+ tabViewLayoutId = layoutResId;
+ tabViewTextViewId = textViewId;
+ }
+
+ @Override
+ public View createTabView(ViewGroup container, int position, PagerAdapter adapter) {
+ View tabView = null;
+ TextView tabTitleView = null;
+
+ if (tabViewLayoutId != NO_ID) {
+ tabView = inflater.inflate(tabViewLayoutId, container, false);
+ }
+
+ if (tabViewTextViewId != NO_ID && tabView != null) {
+ tabTitleView = (TextView) tabView.findViewById(tabViewTextViewId);
+ }
+
+ if (tabTitleView == null && TextView.class.isInstance(tabView)) {
+ tabTitleView = (TextView) tabView;
+ }
+
+ if (tabTitleView != null) {
+ tabTitleView.setText(adapter.getPageTitle(position));
+ }
+
+ return tabView;
+ }
+
+ }
+
+ private class InternalViewPagerListener implements ViewPager.OnPageChangeListener {
+
+ private int scrollState;
+
+ @Override
+ public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+ int tabStripChildCount = tabStrip.getChildCount();
+ if ((tabStripChildCount == 0) || (position < 0) || (position >= tabStripChildCount)) {
+ return;
+ }
+
+ tabStrip.onViewPagerPageChanged(position, positionOffset);
+
+ scrollToTab(position, positionOffset);
+
+ if (viewPagerPageChangeListener != null) {
+ viewPagerPageChangeListener.onPageScrolled(position, positionOffset, positionOffsetPixels);
+ }
+ }
+
+ @Override
+ public void onPageScrollStateChanged(int state) {
+ scrollState = state;
+
+ if (viewPagerPageChangeListener != null) {
+ viewPagerPageChangeListener.onPageScrollStateChanged(state);
+ }
+ }
+
+ @Override
+ public void onPageSelected(int position) {
+ if (scrollState == ViewPager.SCROLL_STATE_IDLE) {
+ tabStrip.onViewPagerPageChanged(position, 0f);
+ scrollToTab(position, 0);
+ }
+
+ for (int i = 0, size = tabStrip.getChildCount(); i < size; i++) {
+ tabStrip.getChildAt(i).setSelected(position == i);
+ }
+
+ if (viewPagerPageChangeListener != null) {
+ viewPagerPageChangeListener.onPageSelected(position);
+ }
+ }
+
+ }
+
+ private class InternalTabClickListener implements OnClickListener {
+ @Override
+ public void onClick(View v) {
+ for (int i = 0; i < tabStrip.getChildCount(); i++) {
+ if (v == tabStrip.getChildAt(i)) {
+ if (onTabClickListener != null) {
+ onTabClickListener.onTabClicked(i);
+ }
+ viewPager.setCurrentItem(i);
+ return;
+ }
+ }
+ }
+ }
+
+}
diff --git a/library/src/main/java/com/chwl/library/widget/tab/SmartTabLayout2.java b/library/src/main/java/com/chwl/library/widget/tab/SmartTabLayout2.java
new file mode 100644
index 000000000..2adac7d3a
--- /dev/null
+++ b/library/src/main/java/com/chwl/library/widget/tab/SmartTabLayout2.java
@@ -0,0 +1,705 @@
+/**
+ * Copyright (C) 2015 ogaclejapan
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * 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 com.chwl.library.widget.tab;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.content.res.TypedArray;
+import android.graphics.Typeface;
+import android.os.Build;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.HorizontalScrollView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.core.view.ViewCompat;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.viewpager2.widget.ViewPager2;
+
+import com.chwl.library.R;
+
+/**
+ * To be used with ViewPager2 to provide a tab indicator component which give constant feedback as
+ * to
+ * the user's scroll progress.
+ *
+ * To use the component, simply add it to your view hierarchy. Then in your
+ * {@link android.app.Activity} or {@link androidx.fragment.app.Fragment} call
+ * {@link #setViewPager(ViewPager2, RecyclerView.Adapter, TabTitleProvider)} providing it the ViewPager this
+ * layout
+ * is being used for.
+ *
+ * The colors can be customized in two ways. The first and simplest is to provide an array of
+ * colors
+ * via {@link #setSelectedIndicatorColors(int...)} and {@link #setDividerColors(int...)}. The
+ * alternative is via the {@link TabColorizer} interface which provides you complete control over
+ * which color is used for any individual position.
+ *
+ * The views used as tabs can be customized by calling {@link #setCustomTabView(int, int)},
+ * providing the layout ID of your custom layout.
+ *
+ * Forked from Google Samples > SlidingTabsBasic >
+ * SlidingTabLayout
+ */
+public class SmartTabLayout2 extends HorizontalScrollView {
+
+ private static final boolean DEFAULT_DISTRIBUTE_EVENLY = false;
+ private static final int TITLE_OFFSET_DIPS = 24;
+ private static final int TITLE_OFFSET_AUTO_CENTER = -1;
+ private static final int TAB_VIEW_PADDING_DIPS = 16;
+ private static final boolean TAB_VIEW_TEXT_ALL_CAPS = true;
+ private static final int TAB_VIEW_TEXT_SIZE_SP = 12;
+ private static final int TAB_VIEW_TEXT_COLOR = 0xFC000000;
+ private static final int TAB_VIEW_TEXT_MIN_WIDTH = 0;
+ private static final boolean TAB_CLICKABLE = true;
+ private static final int NO_TEXT_STYLE = -1;
+
+ protected final SmartTabStrip tabStrip;
+ private int titleOffset;
+ private int tabViewBackgroundResId;
+ private boolean tabViewTextAllCaps;
+ private ColorStateList tabViewTextColors;
+ private float tabViewTextSize;
+ private int tabViewTextHorizontalPadding;
+ private int tabViewTextMinWidth;
+ private ViewPager2 viewPager;
+ private ViewPager2.OnPageChangeCallback viewPagerPageChangeCallback;
+ @Nullable
+ private TabTitleProvider tabTitleProvider;
+ private OnScrollChangeListener onScrollChangeListener;
+ private TabProvider tabProvider;
+ private InternalTabClickListener internalTabClickListener;
+ private InternalTabLongClickListener internalTabLongClickListener;
+ private OnTabClickListener onTabClickListener;
+ private OnTabLongClickListener onTabLongClickListener;
+ private boolean distributeEvenly;
+ private int textAppearance;
+
+ private int childCountCache = 0;
+
+ public SmartTabLayout2(Context context) {
+ this(context, null);
+ }
+
+ public SmartTabLayout2(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public SmartTabLayout2(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+
+ // Disable the Scroll Bar
+ setHorizontalScrollBarEnabled(false);
+
+ final DisplayMetrics dm = getResources().getDisplayMetrics();
+ final float density = dm.density;
+
+ int tabBackgroundResId = NO_ID;
+ boolean textAllCaps = TAB_VIEW_TEXT_ALL_CAPS;
+ ColorStateList textColors;
+ float textSize = TypedValue.applyDimension(
+ TypedValue.COMPLEX_UNIT_SP, TAB_VIEW_TEXT_SIZE_SP, dm);
+ int textHorizontalPadding = (int) (TAB_VIEW_PADDING_DIPS * density);
+ int textMinWidth = (int) (TAB_VIEW_TEXT_MIN_WIDTH * density);
+ boolean distributeEvenly = DEFAULT_DISTRIBUTE_EVENLY;
+ int customTabLayoutId = NO_ID;
+ int customTabTextViewId = NO_ID;
+ boolean clickable = TAB_CLICKABLE;
+ int titleOffset = (int) (TITLE_OFFSET_DIPS * density);
+ int textStyle = NO_TEXT_STYLE;
+
+ TypedArray a = context.obtainStyledAttributes(
+ attrs, R.styleable.stl_SmartTabLayout, defStyle, 0);
+ tabBackgroundResId = a.getResourceId(
+ R.styleable.stl_SmartTabLayout_stl_defaultTabBackground, tabBackgroundResId);
+ textAllCaps = a.getBoolean(
+ R.styleable.stl_SmartTabLayout_stl_defaultTabTextAllCaps, textAllCaps);
+ textColors = a.getColorStateList(
+ R.styleable.stl_SmartTabLayout_stl_defaultTabTextColor);
+ textSize = a.getDimension(
+ R.styleable.stl_SmartTabLayout_stl_defaultTabTextSize, textSize);
+ textHorizontalPadding = a.getDimensionPixelSize(
+ R.styleable.stl_SmartTabLayout_stl_defaultTabTextHorizontalPadding, textHorizontalPadding);
+ textMinWidth = a.getDimensionPixelSize(
+ R.styleable.stl_SmartTabLayout_stl_defaultTabTextMinWidth, textMinWidth);
+ customTabLayoutId = a.getResourceId(
+ R.styleable.stl_SmartTabLayout_stl_customTabTextLayoutId, customTabLayoutId);
+ customTabTextViewId = a.getResourceId(
+ R.styleable.stl_SmartTabLayout_stl_customTabTextViewId, customTabTextViewId);
+ distributeEvenly = a.getBoolean(
+ R.styleable.stl_SmartTabLayout_stl_distributeEvenly, distributeEvenly);
+ clickable = a.getBoolean(
+ R.styleable.stl_SmartTabLayout_stl_clickable, clickable);
+ titleOffset = a.getLayoutDimension(
+ R.styleable.stl_SmartTabLayout_stl_titleOffset, titleOffset);
+ textStyle = a.getResourceId(R.styleable.stl_SmartTabLayout_stl_tabTextStyle, textStyle);
+ a.recycle();
+
+ this.titleOffset = titleOffset;
+ this.tabViewBackgroundResId = tabBackgroundResId;
+ this.tabViewTextAllCaps = textAllCaps;
+ this.tabViewTextColors = (textColors != null)
+ ? textColors
+ : ColorStateList.valueOf(TAB_VIEW_TEXT_COLOR);
+ this.tabViewTextSize = textSize;
+ this.tabViewTextHorizontalPadding = textHorizontalPadding;
+ this.tabViewTextMinWidth = textMinWidth;
+ this.internalTabClickListener = clickable ? new InternalTabClickListener() : null;
+ this.internalTabLongClickListener = clickable ? new InternalTabLongClickListener() : null;
+ this.distributeEvenly = distributeEvenly;
+ this.textAppearance = textStyle;
+
+ if (customTabLayoutId != NO_ID) {
+ setCustomTabView(customTabLayoutId, customTabTextViewId);
+ }
+
+ this.tabStrip = new SmartTabStrip(context, attrs);
+
+ if (distributeEvenly && tabStrip.isIndicatorAlwaysInCenter()) {
+ throw new UnsupportedOperationException(
+ "'distributeEvenly' and 'indicatorAlwaysInCenter' both use does not support");
+ }
+
+ // Make sure that the Tab Strips fills this View
+ setFillViewport(!tabStrip.isIndicatorAlwaysInCenter());
+
+ addView(tabStrip, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+
+ }
+
+ @Override
+ protected void onScrollChanged(int l, int t, int oldl, int oldt) {
+ super.onScrollChanged(l, t, oldl, oldt);
+ if (onScrollChangeListener != null) {
+ onScrollChangeListener.onScrollChanged(l, oldl);
+ }
+ }
+
+ @Override
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ super.onSizeChanged(w, h, oldw, oldh);
+ adjustForIndicatorAlwaysInCenter(w, h);
+ }
+
+ private void adjustForIndicatorAlwaysInCenter(int w, int h) {
+ if (tabStrip.isIndicatorAlwaysInCenter() && tabStrip.getChildCount() > 0) {
+ View firstTab = tabStrip.getChildAt(0);
+ View lastTab = tabStrip.getChildAt(tabStrip.getChildCount() - 1);
+ int start = (w - Utils.getMeasuredWidth(firstTab)) / 2 - Utils.getMarginStart(firstTab);
+ int end = (w - Utils.getMeasuredWidth(lastTab)) / 2 - Utils.getMarginEnd(lastTab);
+ tabStrip.setMinimumWidth(tabStrip.getMeasuredWidth());
+ ViewCompat.setPaddingRelative(this, start, getPaddingTop(), end, getPaddingBottom());
+ setClipToPadding(false);
+ }
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ super.onLayout(changed, l, t, r, b);
+ // Ensure first scroll
+ if (changed && viewPager != null) {
+ scrollToTab(viewPager.getCurrentItem(), 0);
+ }
+ if (childCountCache != tabStrip.getChildCount()) {
+ adjustForIndicatorAlwaysInCenter(getMeasuredWidth(), getMeasuredHeight());
+ }
+ childCountCache = tabStrip.getChildCount();
+ }
+
+ /**
+ * Set the behavior of the Indicator scrolling feedback.
+ *
+ * @param interpolator {@link SmartTabIndicationInterpolator}
+ */
+ public void setIndicationInterpolator(SmartTabIndicationInterpolator interpolator) {
+ tabStrip.setIndicationInterpolator(interpolator);
+ }
+
+ /**
+ * Set the custom {@link TabColorizer} to be used.
+ *
+ * If you only require simple customisation then you can use
+ * {@link #setSelectedIndicatorColors(int...)} and {@link #setDividerColors(int...)} to achieve
+ * similar effects.
+ */
+ public void setCustomTabColorizer(TabColorizer tabColorizer) {
+ tabStrip.setCustomTabColorizer(tabColorizer);
+ }
+
+ /**
+ * Set the color used for styling the tab text. This will need to be called prior to calling
+ * {@link #setViewPager(ViewPager2, RecyclerView.Adapter, TabTitleProvider)} otherwise it will not get set
+ *
+ * @param color to use for tab text
+ */
+ public void setDefaultTabTextColor(int color) {
+ tabViewTextColors = ColorStateList.valueOf(color);
+ }
+
+ /**
+ * Sets the colors used for styling the tab text. This will need to be called prior to calling
+ * {@link #setViewPager(ViewPager2, RecyclerView.Adapter, TabTitleProvider)} otherwise it will not get set
+ *
+ * @param colors ColorStateList to use for tab text
+ */
+ public void setDefaultTabTextColor(ColorStateList colors) {
+ tabViewTextColors = colors;
+ }
+
+ /**
+ * Set the same weight for tab
+ */
+ public void setDistributeEvenly(boolean distributeEvenly) {
+ this.distributeEvenly = distributeEvenly;
+ }
+
+ /**
+ * Sets the colors to be used for indicating the selected tab. These colors are treated as a
+ * circular array. Providing one color will mean that all tabs are indicated with the same color.
+ */
+ public void setSelectedIndicatorColors(int... colors) {
+ tabStrip.setSelectedIndicatorColors(colors);
+ }
+
+ /**
+ * Sets the colors to be used for tab dividers. These colors are treated as a circular array.
+ * Providing one color will mean that all tabs are indicated with the same color.
+ */
+ public void setDividerColors(int... colors) {
+ tabStrip.setDividerColors(colors);
+ }
+
+ /**
+ * Set the {@link ViewPager2.OnPageChangeCallback}. When using {@link SmartTabLayout2} you are
+ * required to set any {@link ViewPager2.OnPageChangeCallback} through this method. This is so
+ * that the layout can update it's scroll position correctly.
+ *
+ * @see ViewPager2#registerOnPageChangeCallback(ViewPager2.OnPageChangeCallback)
+ */
+ public void setOnPageChangeCallback(ViewPager2.OnPageChangeCallback listener) {
+ viewPagerPageChangeCallback = listener;
+ }
+
+ /**
+ * Set {@link OnScrollChangeListener} for obtaining values of scrolling.
+ *
+ * @param listener the {@link OnScrollChangeListener} to set
+ */
+ public void setOnScrollChangeListener(OnScrollChangeListener listener) {
+ onScrollChangeListener = listener;
+ }
+
+ /**
+ * Set {@link OnTabClickListener} for obtaining click event.
+ *
+ * @param listener the {@link OnTabClickListener} to set
+ */
+ public void setOnTabClickListener(OnTabClickListener listener) {
+ onTabClickListener = listener;
+ }
+
+ public void setOnTabLongClickListener(OnTabLongClickListener listener) {
+ onTabLongClickListener = listener;
+ }
+
+ /**
+ * Set the custom layout to be inflated for the tab views.
+ *
+ * @param layoutResId Layout id to be inflated
+ * @param textViewId id of the {@link TextView} in the inflated view
+ */
+ public void setCustomTabView(int layoutResId, int textViewId) {
+ tabProvider = new SimpleTabProvider(getContext(), layoutResId, textViewId);
+ }
+
+ /**
+ * Set the custom layout to be inflated for the tab views.
+ *
+ * @param provider {@link TabProvider}
+ */
+ public void setCustomTabView(TabProvider provider) {
+ tabProvider = provider;
+ }
+
+ /**
+ * Sets the associated view pager. Note that the assumption here is that the pager content
+ * (number of tabs and tab titles) does not change after this call has been made.
+ */
+ public void setViewPager(@NonNull ViewPager2 viewPager, @NonNull RecyclerView.Adapter adapter,
+ @Nullable TabTitleProvider titleProvider) {
+ tabStrip.removeAllViews();
+
+ this.viewPager = viewPager;
+ if (this.viewPager.getAdapter() != adapter){
+ this.viewPager.setAdapter(adapter);
+ }
+ this.tabTitleProvider = titleProvider;
+ if (viewPager != null && viewPager.getAdapter() != null) {
+ viewPager.registerOnPageChangeCallback(new InternalViewPagerListener());
+ populateTabStrip();
+ }
+ }
+
+ /**
+ * Returns the view at the specified position in the tabs.
+ *
+ * @param position the position at which to get the view from
+ * @return the view at the specified position or null if the position does not exist within the
+ * tabs
+ */
+ public View getTabAt(int position) {
+ return tabStrip.getChildAt(position);
+ }
+
+ /**
+ * Create a default view to be used for tabs. This is called if a custom tab view is not set via
+ * {@link #setCustomTabView(int, int)}.
+ */
+ protected TextView createDefaultTabView(CharSequence title) {
+ TextView textView = new TextView(getContext());
+ textView.setGravity(Gravity.CENTER);
+ textView.setText(title);
+ if (textAppearance != NO_TEXT_STYLE) {
+ textView.setTextAppearance(getContext(), textAppearance);
+ } else {
+ textView.setTextColor(tabViewTextColors);
+ textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, tabViewTextSize);
+ textView.setTypeface(Typeface.DEFAULT_BOLD);
+
+ 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(tabViewTextAllCaps);
+ }
+
+ if (tabViewTextMinWidth > 0) {
+ textView.setMinWidth(tabViewTextMinWidth);
+ }
+ }
+ if (tabViewBackgroundResId != NO_ID) {
+ textView.setBackgroundResource(tabViewBackgroundResId);
+ } else {
+ // 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);
+ }
+ textView.setPadding(
+ tabViewTextHorizontalPadding, 0,
+ tabViewTextHorizontalPadding, 0);
+ textView.setLayoutParams(new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.MATCH_PARENT));
+
+ return textView;
+ }
+
+ private void populateTabStrip() {
+ final RecyclerView.Adapter adapter = viewPager.getAdapter();
+
+ for (int i = 0; i < adapter.getItemCount(); i++) {
+
+ CharSequence pageTitle = null;
+ if (tabTitleProvider != null) {
+ pageTitle = tabTitleProvider.getPageTitle(i);
+ }
+
+ final View tabView = (tabProvider == null)
+ ? createDefaultTabView(pageTitle)
+ : tabProvider.createTabView(tabStrip, i, pageTitle);
+
+ if (tabView == null) {
+ throw new IllegalStateException("tabView is null.");
+ }
+
+ if (distributeEvenly) {
+ LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) tabView.getLayoutParams();
+ lp.width = 0;
+ lp.weight = 1;
+ }
+
+ if (internalTabClickListener != null) {
+ tabView.setOnClickListener(internalTabClickListener);
+ }
+ if (internalTabLongClickListener != null) {
+ tabView.setOnLongClickListener(internalTabLongClickListener);
+ }
+
+ tabStrip.addView(tabView);
+
+ if (i == viewPager.getCurrentItem()) {
+ tabView.setSelected(true);
+ }
+
+ }
+ }
+
+ private void scrollToTab(int tabIndex, float positionOffset) {
+ final int tabStripChildCount = tabStrip.getChildCount();
+ if (tabStripChildCount == 0 || tabIndex < 0 || tabIndex >= tabStripChildCount) {
+ return;
+ }
+
+ final boolean isLayoutRtl = Utils.isLayoutRtl(this);
+ View selectedTab = tabStrip.getChildAt(tabIndex);
+ int widthPlusMargin = Utils.getWidth(selectedTab) + Utils.getMarginHorizontally(selectedTab);
+ int extraOffset = (int) (positionOffset * widthPlusMargin);
+
+ if (tabStrip.isIndicatorAlwaysInCenter()) {
+
+ if (0f < positionOffset && positionOffset < 1f) {
+ View nextTab = tabStrip.getChildAt(tabIndex + 1);
+ int selectHalfWidth = Utils.getWidth(selectedTab) / 2 + Utils.getMarginEnd(selectedTab);
+ int nextHalfWidth = Utils.getWidth(nextTab) / 2 + Utils.getMarginStart(nextTab);
+ extraOffset = Math.round(positionOffset * (selectHalfWidth + nextHalfWidth));
+ }
+
+ View firstTab = tabStrip.getChildAt(0);
+ int x;
+ if (isLayoutRtl) {
+ int first = Utils.getWidth(firstTab) + Utils.getMarginEnd(firstTab);
+ int selected = Utils.getWidth(selectedTab) + Utils.getMarginEnd(selectedTab);
+ x = Utils.getEnd(selectedTab) - Utils.getMarginEnd(selectedTab) - extraOffset;
+ x -= (first - selected) / 2;
+ } else {
+ int first = Utils.getWidth(firstTab) + Utils.getMarginStart(firstTab);
+ int selected = Utils.getWidth(selectedTab) + Utils.getMarginStart(selectedTab);
+ x = Utils.getStart(selectedTab) - Utils.getMarginStart(selectedTab) + extraOffset;
+ x -= (first - selected) / 2;
+ }
+
+ scrollTo(x, 0);
+ return;
+
+ }
+
+ int x;
+ if (titleOffset == TITLE_OFFSET_AUTO_CENTER) {
+
+ if (0f < positionOffset && positionOffset < 1f) {
+ View nextTab = tabStrip.getChildAt(tabIndex + 1);
+ int selectHalfWidth = Utils.getWidth(selectedTab) / 2 + Utils.getMarginEnd(selectedTab);
+ int nextHalfWidth = Utils.getWidth(nextTab) / 2 + Utils.getMarginStart(nextTab);
+ extraOffset = Math.round(positionOffset * (selectHalfWidth + nextHalfWidth));
+ }
+
+ if (isLayoutRtl) {
+ x = -Utils.getWidthWithMargin(selectedTab) / 2 + getWidth() / 2;
+ x -= Utils.getPaddingStart(this);
+ } else {
+ x = Utils.getWidthWithMargin(selectedTab) / 2 - getWidth() / 2;
+ x += Utils.getPaddingStart(this);
+ }
+
+ } else {
+
+ if (isLayoutRtl) {
+ x = (tabIndex > 0 || positionOffset > 0) ? titleOffset : 0;
+ } else {
+ x = (tabIndex > 0 || positionOffset > 0) ? -titleOffset : 0;
+ }
+
+ }
+
+ int start = Utils.getStart(selectedTab);
+ int startMargin = Utils.getMarginStart(selectedTab);
+ if (isLayoutRtl) {
+ x += start + startMargin - extraOffset - getWidth() + Utils.getPaddingHorizontally(this);
+ } else {
+ x += start - startMargin + extraOffset;
+ }
+
+ scrollTo(x, 0);
+
+ }
+
+ /**
+ * Interface definition for a callback to be invoked when the scroll position of a view changes.
+ */
+ public interface OnScrollChangeListener {
+
+ /**
+ * Called when the scroll position of a view changes.
+ *
+ * @param scrollX Current horizontal scroll origin.
+ * @param oldScrollX Previous horizontal scroll origin.
+ */
+ void onScrollChanged(int scrollX, int oldScrollX);
+ }
+
+ /**
+ * Interface definition for a callback to be invoked when a tab is clicked.
+ */
+ public interface OnTabClickListener {
+
+ /**
+ * Called when a tab is clicked.
+ *
+ * @param position tab's position
+ */
+ void onTabClicked(int position);
+ }
+
+ /**
+ * Interface definition for a callback to be invoked when a tab is long clicked.
+ */
+ public interface OnTabLongClickListener {
+
+ /**
+ * Called when a tab is clicked.
+ *
+ * @param position tab's position
+ */
+ void onTabLongClicked(int position);
+ }
+
+ /**
+ * Create the custom tabs in the tab layout. Set with
+ * {@link #setCustomTabView(TabProvider)}
+ */
+ public interface TabProvider {
+
+ /**
+ * @return Return the View of {@code position} for the Tabs
+ */
+ View createTabView(ViewGroup container, int position, @Nullable CharSequence pageTitle);
+
+ }
+
+ private static class SimpleTabProvider implements TabProvider {
+
+ private final LayoutInflater inflater;
+ private final int tabViewLayoutId;
+ private final int tabViewTextViewId;
+
+ private SimpleTabProvider(Context context, int layoutResId, int textViewId) {
+ inflater = LayoutInflater.from(context);
+ tabViewLayoutId = layoutResId;
+ tabViewTextViewId = textViewId;
+ }
+
+ @Override
+ public View createTabView(ViewGroup container, int position, CharSequence pageTitle) {
+ View tabView = null;
+ TextView tabTitleView = null;
+
+ if (tabViewLayoutId != NO_ID) {
+ tabView = inflater.inflate(tabViewLayoutId, container, false);
+ }
+
+ if (tabViewTextViewId != NO_ID && tabView != null) {
+ tabTitleView = (TextView) tabView.findViewById(tabViewTextViewId);
+ }
+
+ if (tabTitleView == null && TextView.class.isInstance(tabView)) {
+ tabTitleView = (TextView) tabView;
+ }
+
+ if (tabTitleView != null) {
+ tabTitleView.setText(pageTitle);
+ }
+
+ return tabView;
+ }
+
+ }
+
+ private class InternalViewPagerListener extends ViewPager2.OnPageChangeCallback {
+
+ private int scrollState;
+
+ @Override
+ public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+ int tabStripChildCount = tabStrip.getChildCount();
+ if ((tabStripChildCount == 0) || (position < 0) || (position >= tabStripChildCount)) {
+ return;
+ }
+
+ tabStrip.onViewPagerPageChanged(position, positionOffset);
+
+ scrollToTab(position, positionOffset);
+
+ if (viewPagerPageChangeCallback != null) {
+ viewPagerPageChangeCallback.onPageScrolled(position, positionOffset, positionOffsetPixels);
+ }
+ }
+
+ @Override
+ public void onPageScrollStateChanged(int state) {
+ scrollState = state;
+
+ if (viewPagerPageChangeCallback != null) {
+ viewPagerPageChangeCallback.onPageScrollStateChanged(state);
+ }
+ }
+
+ @Override
+ public void onPageSelected(int position) {
+ if (scrollState == ViewPager2.SCROLL_STATE_IDLE) {
+ tabStrip.onViewPagerPageChanged(position, 0f);
+ scrollToTab(position, 0);
+ }
+
+ for (int i = 0, size = tabStrip.getChildCount(); i < size; i++) {
+ tabStrip.getChildAt(i).setSelected(position == i);
+ }
+
+ if (viewPagerPageChangeCallback != null) {
+ viewPagerPageChangeCallback.onPageSelected(position);
+ }
+ }
+
+ }
+
+ private class InternalTabClickListener implements OnClickListener {
+ @Override
+ public void onClick(View v) {
+ for (int i = 0; i < tabStrip.getChildCount(); i++) {
+ if (v == tabStrip.getChildAt(i)) {
+ if (onTabClickListener != null) {
+ onTabClickListener.onTabClicked(i);
+ }
+ viewPager.setCurrentItem(i);
+ return;
+ }
+ }
+ }
+ }
+
+ private class InternalTabLongClickListener implements OnLongClickListener {
+ @Override
+ public boolean onLongClick(View v) {
+ for (int i = 0; i < tabStrip.getChildCount(); i++) {
+ if (v == tabStrip.getChildAt(i)) {
+ if (onTabLongClickListener != null) {
+ onTabLongClickListener.onTabLongClicked(i);
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+}
diff --git a/library/src/main/java/com/chwl/library/widget/tab/SmartTabStrip.java b/library/src/main/java/com/chwl/library/widget/tab/SmartTabStrip.java
new file mode 100644
index 000000000..8ecaf053d
--- /dev/null
+++ b/library/src/main/java/com/chwl/library/widget/tab/SmartTabStrip.java
@@ -0,0 +1,446 @@
+/**
+ * Copyright (C) 2015 ogaclejapan
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * 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 com.chwl.library.widget.tab;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.RectF;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.View;
+import android.widget.LinearLayout;
+
+import com.chwl.library.R;
+
+/**
+ *
+ * Forked from Google Samples > SlidingTabsBasic >
+ * SlidingTabStrip
+ */
+class SmartTabStrip extends LinearLayout {
+
+ private static final int GRAVITY_BOTTOM = 0;
+ private static final int GRAVITY_TOP = 1;
+ private static final int GRAVITY_CENTER = 2;
+
+ private static final int AUTO_WIDTH = -1;
+
+ private static final int DEFAULT_TOP_BORDER_THICKNESS_DIPS = 0;
+ private static final byte DEFAULT_TOP_BORDER_COLOR_ALPHA = 0x26;
+ private static final int DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS = 2;
+ private static final byte DEFAULT_BOTTOM_BORDER_COLOR_ALPHA = 0x26;
+ private static final int SELECTED_INDICATOR_THICKNESS_DIPS = 8;
+ private static final int DEFAULT_SELECTED_INDICATOR_COLOR = 0xFF33B5E5;
+ private static final float DEFAULT_INDICATOR_CORNER_RADIUS = 0f;
+ private static final int DEFAULT_DIVIDER_THICKNESS_DIPS = 1;
+ private static final byte DEFAULT_DIVIDER_COLOR_ALPHA = 0x20;
+ private static final float DEFAULT_DIVIDER_HEIGHT = 0.5f;
+ private static final boolean DEFAULT_INDICATOR_IN_CENTER = false;
+ private static final boolean DEFAULT_INDICATOR_IN_FRONT = false;
+ private static final boolean DEFAULT_INDICATOR_WITHOUT_PADDING = false;
+ private static final int DEFAULT_INDICATOR_GRAVITY = GRAVITY_BOTTOM;
+ private static final boolean DEFAULT_DRAW_DECORATION_AFTER_TAB = false;
+
+ private final int topBorderThickness;
+ private final int topBorderColor;
+ private final int bottomBorderThickness;
+ private final int bottomBorderColor;
+ private final Paint borderPaint;
+ private final RectF indicatorRectF = new RectF();
+ private final boolean indicatorWithoutPadding;
+ private final boolean indicatorAlwaysInCenter;
+ private final boolean indicatorInFront;
+ private final int indicatorThickness;
+ private final int indicatorWidth;
+ private final int indicatorGravity;
+ private final float indicatorCornerRadius;
+ private final Paint indicatorPaint;
+ private final int dividerThickness;
+ private final Paint dividerPaint;
+ private final float dividerHeight;
+ private final SimpleTabColorizer defaultTabColorizer;
+ private final boolean drawDecorationAfterTab;
+
+ private int lastPosition;
+ private int selectedPosition;
+ private float selectionOffset;
+ private SmartTabIndicationInterpolator indicationInterpolator;
+ private TabColorizer customTabColorizer;
+
+ SmartTabStrip(Context context, AttributeSet attrs) {
+ super(context);
+ setWillNotDraw(false);
+
+ final float density = getResources().getDisplayMetrics().density;
+
+ TypedValue outValue = new TypedValue();
+ context.getTheme().resolveAttribute(android.R.attr.colorForeground, outValue, true);
+ final int themeForegroundColor = outValue.data;
+
+ boolean indicatorWithoutPadding = DEFAULT_INDICATOR_WITHOUT_PADDING;
+ boolean indicatorInFront = DEFAULT_INDICATOR_IN_FRONT;
+ boolean indicatorAlwaysInCenter = DEFAULT_INDICATOR_IN_CENTER;
+ int indicationInterpolatorId = SmartTabIndicationInterpolator.ID_SMART;
+ int indicatorGravity = DEFAULT_INDICATOR_GRAVITY;
+ int indicatorColor = DEFAULT_SELECTED_INDICATOR_COLOR;
+ int indicatorColorsId = NO_ID;
+ int indicatorThickness = (int) (SELECTED_INDICATOR_THICKNESS_DIPS * density);
+ int indicatorWidth = AUTO_WIDTH;
+ float indicatorCornerRadius = DEFAULT_INDICATOR_CORNER_RADIUS * density;
+ int overlineColor = setColorAlpha(themeForegroundColor, DEFAULT_TOP_BORDER_COLOR_ALPHA);
+ int overlineThickness = (int) (DEFAULT_TOP_BORDER_THICKNESS_DIPS * density);
+ int underlineColor = setColorAlpha(themeForegroundColor, DEFAULT_BOTTOM_BORDER_COLOR_ALPHA);
+ int underlineThickness = (int) (DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS * density);
+ int dividerColor = setColorAlpha(themeForegroundColor, DEFAULT_DIVIDER_COLOR_ALPHA);
+ int dividerColorsId = NO_ID;
+ int dividerThickness = (int) (DEFAULT_DIVIDER_THICKNESS_DIPS * density);
+ boolean drawDecorationAfterTab = DEFAULT_DRAW_DECORATION_AFTER_TAB;
+
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.stl_SmartTabLayout);
+ indicatorAlwaysInCenter = a.getBoolean(
+ R.styleable.stl_SmartTabLayout_stl_indicatorAlwaysInCenter, indicatorAlwaysInCenter);
+ indicatorWithoutPadding = a.getBoolean(
+ R.styleable.stl_SmartTabLayout_stl_indicatorWithoutPadding, indicatorWithoutPadding);
+ indicatorInFront = a.getBoolean(
+ R.styleable.stl_SmartTabLayout_stl_indicatorInFront, indicatorInFront);
+ indicationInterpolatorId = a.getInt(
+ R.styleable.stl_SmartTabLayout_stl_indicatorInterpolation, indicationInterpolatorId);
+ indicatorGravity = a.getInt(
+ R.styleable.stl_SmartTabLayout_stl_indicatorGravity, indicatorGravity);
+ indicatorColor = a.getColor(
+ R.styleable.stl_SmartTabLayout_stl_indicatorColor, indicatorColor);
+ indicatorColorsId = a.getResourceId(
+ R.styleable.stl_SmartTabLayout_stl_indicatorColors, indicatorColorsId);
+ indicatorThickness = a.getDimensionPixelSize(
+ R.styleable.stl_SmartTabLayout_stl_indicatorThickness, indicatorThickness);
+ indicatorWidth = a.getLayoutDimension(
+ R.styleable.stl_SmartTabLayout_stl_indicatorWidth, indicatorWidth);
+ indicatorCornerRadius = a.getDimension(
+ R.styleable.stl_SmartTabLayout_stl_indicatorCornerRadius, indicatorCornerRadius);
+ overlineColor = a.getColor(
+ R.styleable.stl_SmartTabLayout_stl_overlineColor, overlineColor);
+ overlineThickness = a.getDimensionPixelSize(
+ R.styleable.stl_SmartTabLayout_stl_overlineThickness, overlineThickness);
+ underlineColor = a.getColor(
+ R.styleable.stl_SmartTabLayout_stl_underlineColor, underlineColor);
+ underlineThickness = a.getDimensionPixelSize(
+ R.styleable.stl_SmartTabLayout_stl_underlineThickness, underlineThickness);
+ dividerColor = a.getColor(
+ R.styleable.stl_SmartTabLayout_stl_dividerColor, dividerColor);
+ dividerColorsId = a.getResourceId(
+ R.styleable.stl_SmartTabLayout_stl_dividerColors, dividerColorsId);
+ dividerThickness = a.getDimensionPixelSize(
+ R.styleable.stl_SmartTabLayout_stl_dividerThickness, dividerThickness);
+ drawDecorationAfterTab = a.getBoolean(
+ R.styleable.stl_SmartTabLayout_stl_drawDecorationAfterTab, drawDecorationAfterTab);
+ a.recycle();
+
+ final int[] indicatorColors = (indicatorColorsId == NO_ID)
+ ? new int[] { indicatorColor }
+ : getResources().getIntArray(indicatorColorsId);
+
+ final int[] dividerColors = (dividerColorsId == NO_ID)
+ ? new int[] { dividerColor }
+ : getResources().getIntArray(dividerColorsId);
+
+ this.defaultTabColorizer = new SimpleTabColorizer();
+ this.defaultTabColorizer.setIndicatorColors(indicatorColors);
+ this.defaultTabColorizer.setDividerColors(dividerColors);
+
+ this.topBorderThickness = overlineThickness;
+ this.topBorderColor = overlineColor;
+ this.bottomBorderThickness = underlineThickness;
+ this.bottomBorderColor = underlineColor;
+ this.borderPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+
+ this.indicatorAlwaysInCenter = indicatorAlwaysInCenter;
+ this.indicatorWithoutPadding = indicatorWithoutPadding;
+ this.indicatorInFront = indicatorInFront;
+ this.indicatorThickness = indicatorThickness;
+ this.indicatorWidth = indicatorWidth;
+ this.indicatorPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ this.indicatorCornerRadius = indicatorCornerRadius;
+ this.indicatorGravity = indicatorGravity;
+
+ this.dividerHeight = DEFAULT_DIVIDER_HEIGHT;
+ this.dividerPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ this.dividerPaint.setStrokeWidth(dividerThickness);
+ this.dividerThickness = dividerThickness;
+
+ this.drawDecorationAfterTab = drawDecorationAfterTab;
+
+ this.indicationInterpolator = SmartTabIndicationInterpolator.of(indicationInterpolatorId);
+ }
+
+ /**
+ * Set the alpha value of the {@code color} to be the given {@code alpha} value.
+ */
+ private static int setColorAlpha(int color, byte alpha) {
+ return Color.argb(alpha, Color.red(color), Color.green(color), Color.blue(color));
+ }
+
+ /**
+ * Blend {@code color1} and {@code color2} using the given ratio.
+ *
+ * @param ratio of which to blend. 1.0 will return {@code color1}, 0.5 will give an even blend,
+ * 0.0 will return {@code color2}.
+ */
+ private static int blendColors(int color1, int color2, float ratio) {
+ final float inverseRation = 1f - ratio;
+ float r = (Color.red(color1) * ratio) + (Color.red(color2) * inverseRation);
+ float g = (Color.green(color1) * ratio) + (Color.green(color2) * inverseRation);
+ float b = (Color.blue(color1) * ratio) + (Color.blue(color2) * inverseRation);
+ return Color.rgb((int) r, (int) g, (int) b);
+ }
+
+ void setIndicationInterpolator(SmartTabIndicationInterpolator interpolator) {
+ indicationInterpolator = interpolator;
+ invalidate();
+ }
+
+ void setCustomTabColorizer(TabColorizer customTabColorizer) {
+ this.customTabColorizer = customTabColorizer;
+ invalidate();
+ }
+
+ void setSelectedIndicatorColors(int... colors) {
+ // Make sure that the custom colorizer is removed
+ customTabColorizer = null;
+ defaultTabColorizer.setIndicatorColors(colors);
+ invalidate();
+ }
+
+ void setDividerColors(int... colors) {
+ // Make sure that the custom colorizer is removed
+ customTabColorizer = null;
+ defaultTabColorizer.setDividerColors(colors);
+ invalidate();
+ }
+
+ void onViewPagerPageChanged(int position, float positionOffset) {
+ selectedPosition = position;
+ selectionOffset = positionOffset;
+ if (positionOffset == 0f && lastPosition != selectedPosition) {
+ lastPosition = selectedPosition;
+ }
+ invalidate();
+ }
+
+ boolean isIndicatorAlwaysInCenter() {
+ return indicatorAlwaysInCenter;
+ }
+
+ TabColorizer getTabColorizer() {
+ return (customTabColorizer != null) ? customTabColorizer : defaultTabColorizer;
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ if (!drawDecorationAfterTab) {
+ drawDecoration(canvas);
+ }
+ }
+
+ @Override
+ protected void dispatchDraw(Canvas canvas) {
+ super.dispatchDraw(canvas);
+ if (drawDecorationAfterTab) {
+ drawDecoration(canvas);
+ }
+ }
+
+ private void drawDecoration(Canvas canvas) {
+ final int height = getHeight();
+ final int width = getWidth();
+ final int tabCount = getChildCount();
+ final TabColorizer tabColorizer = getTabColorizer();
+ final boolean isLayoutRtl = Utils.isLayoutRtl(this);
+
+ if (indicatorInFront) {
+ drawOverline(canvas, 0, width);
+ drawUnderline(canvas, 0, width, height);
+ }
+
+ // Thick colored underline below the current selection
+ if (tabCount > 0) {
+ View selectedTab = getChildAt(selectedPosition);
+ int selectedStart = Utils.getStart(selectedTab, indicatorWithoutPadding);
+ int selectedEnd = Utils.getEnd(selectedTab, indicatorWithoutPadding);
+ int left;
+ int right;
+ if (isLayoutRtl) {
+ left = selectedEnd;
+ right = selectedStart;
+ } else {
+ left = selectedStart;
+ right = selectedEnd;
+ }
+
+ int color = tabColorizer.getIndicatorColor(selectedPosition);
+ float thickness = indicatorThickness;
+
+ if (selectionOffset > 0f && selectedPosition < (getChildCount() - 1)) {
+ int nextColor = tabColorizer.getIndicatorColor(selectedPosition + 1);
+ if (color != nextColor) {
+ color = blendColors(nextColor, color, selectionOffset);
+ }
+
+ // Draw the selection partway between the tabs
+ float startOffset = indicationInterpolator.getLeftEdge(selectionOffset);
+ float endOffset = indicationInterpolator.getRightEdge(selectionOffset);
+ float thicknessOffset = indicationInterpolator.getThickness(selectionOffset);
+
+ View nextTab = getChildAt(selectedPosition + 1);
+ int nextStart = Utils.getStart(nextTab, indicatorWithoutPadding);
+ int nextEnd = Utils.getEnd(nextTab, indicatorWithoutPadding);
+ if (isLayoutRtl) {
+ left = (int) (endOffset * nextEnd + (1.0f - endOffset) * left);
+ right = (int) (startOffset * nextStart + (1.0f - startOffset) * right);
+ } else {
+ left = (int) (startOffset * nextStart + (1.0f - startOffset) * left);
+ right = (int) (endOffset * nextEnd + (1.0f - endOffset) * right);
+ }
+ thickness = thickness * thicknessOffset;
+ }
+
+ drawIndicator(canvas, left, right, height, thickness, color);
+
+ }
+
+ if (!indicatorInFront) {
+ drawOverline(canvas, 0, width);
+ drawUnderline(canvas, 0, getWidth(), height);
+ }
+
+ // Vertical separators between the titles
+ drawSeparator(canvas, height, tabCount);
+
+ }
+
+ private void drawSeparator(Canvas canvas, int height, int tabCount) {
+ if (dividerThickness <= 0) {
+ return;
+ }
+
+ final int dividerHeightPx = (int) (Math.min(Math.max(0f, dividerHeight), 1f) * height);
+ final TabColorizer tabColorizer = getTabColorizer();
+
+ // Vertical separators between the titles
+ final int separatorTop = (height - dividerHeightPx) / 2;
+ final int separatorBottom = separatorTop + dividerHeightPx;
+
+ final boolean isLayoutRtl = Utils.isLayoutRtl(this);
+ for (int i = 0; i < tabCount - 1; i++) {
+ View child = getChildAt(i);
+ int end = Utils.getEnd(child);
+ int endMargin = Utils.getMarginEnd(child);
+ int separatorX = isLayoutRtl ? end - endMargin : end + endMargin;
+ dividerPaint.setColor(tabColorizer.getDividerColor(i));
+ canvas.drawLine(separatorX, separatorTop, separatorX, separatorBottom, dividerPaint);
+ }
+ }
+
+ private void drawIndicator(Canvas canvas, int left, int right, int height, float thickness,
+ int color) {
+ if (indicatorThickness <= 0 || indicatorWidth == 0) {
+ return;
+ }
+
+ float center;
+ float top;
+ float bottom;
+
+ switch (indicatorGravity) {
+ case GRAVITY_TOP:
+ center = indicatorThickness / 2f;
+ top = center - (thickness / 2f);
+ bottom = center + (thickness / 2f);
+ break;
+ case GRAVITY_CENTER:
+ center = height / 2f;
+ top = center - (thickness / 2f);
+ bottom = center + (thickness / 2f);
+ break;
+ case GRAVITY_BOTTOM:
+ default:
+ center = height - (indicatorThickness / 2f);
+ top = center - (thickness / 2f);
+ bottom = center + (thickness / 2f);
+ }
+
+ indicatorPaint.setColor(color);
+ if (indicatorWidth == AUTO_WIDTH) {
+ indicatorRectF.set(left, top, right, bottom);
+ } else {
+ float padding = (Math.abs(left - right) - indicatorWidth) / 2f;
+ indicatorRectF.set(left + padding, top, right - padding, bottom);
+ }
+
+ if (indicatorCornerRadius > 0f) {
+ canvas.drawRoundRect(
+ indicatorRectF, indicatorCornerRadius,
+ indicatorCornerRadius, indicatorPaint);
+ } else {
+ canvas.drawRect(indicatorRectF, indicatorPaint);
+ }
+ }
+
+ private void drawOverline(Canvas canvas, int left, int right) {
+ if (topBorderThickness <= 0) {
+ return;
+ }
+ // Thin overline along the entire top edge
+ borderPaint.setColor(topBorderColor);
+ canvas.drawRect(left, 0, right, topBorderThickness, borderPaint);
+ }
+
+ private void drawUnderline(Canvas canvas, int left, int right, int height) {
+ if (bottomBorderThickness <= 0) {
+ return;
+ }
+ // Thin underline along the entire bottom edge
+ borderPaint.setColor(bottomBorderColor);
+ canvas.drawRect(left, height - bottomBorderThickness, right, height, borderPaint);
+ }
+
+ private static class SimpleTabColorizer implements TabColorizer {
+
+ private int[] indicatorColors;
+ private int[] dividerColors;
+
+ @Override
+ public final int getIndicatorColor(int position) {
+ return indicatorColors[position % indicatorColors.length];
+ }
+
+ @Override
+ public final int getDividerColor(int position) {
+ return dividerColors[position % dividerColors.length];
+ }
+
+ void setIndicatorColors(int... colors) {
+ indicatorColors = colors;
+ }
+
+ void setDividerColors(int... colors) {
+ dividerColors = colors;
+ }
+ }
+}
diff --git a/library/src/main/java/com/chwl/library/widget/tab/TabColorizer.java b/library/src/main/java/com/chwl/library/widget/tab/TabColorizer.java
new file mode 100644
index 000000000..24276ea41
--- /dev/null
+++ b/library/src/main/java/com/chwl/library/widget/tab/TabColorizer.java
@@ -0,0 +1,19 @@
+package com.chwl.library.widget.tab;
+
+/**
+ * Allows complete control over the colors drawn in the tab layout. Set with
+ * {@link SmartTabLayout#setCustomTabColorizer(TabColorizer)}.
+ */
+public interface TabColorizer {
+
+ /**
+ * @return return the color of the indicator used when {@code position} is selected.
+ */
+ int getIndicatorColor(int position);
+
+ /**
+ * @return return the color of the divider drawn to the right of {@code position}.
+ */
+ int getDividerColor(int position);
+
+}
diff --git a/library/src/main/java/com/chwl/library/widget/tab/TabTitleProvider.java b/library/src/main/java/com/chwl/library/widget/tab/TabTitleProvider.java
new file mode 100644
index 000000000..a97434194
--- /dev/null
+++ b/library/src/main/java/com/chwl/library/widget/tab/TabTitleProvider.java
@@ -0,0 +1,8 @@
+package com.chwl.library.widget.tab;
+
+import androidx.annotation.Nullable;
+
+public interface TabTitleProvider {
+ @Nullable
+ CharSequence getPageTitle(int position);
+}
diff --git a/library/src/main/java/com/chwl/library/widget/tab/Utils.java b/library/src/main/java/com/chwl/library/widget/tab/Utils.java
new file mode 100644
index 000000000..e5e5528a5
--- /dev/null
+++ b/library/src/main/java/com/chwl/library/widget/tab/Utils.java
@@ -0,0 +1,120 @@
+/**
+ * Copyright (C) 2015 ogaclejapan
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * 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 com.chwl.library.widget.tab;
+
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.core.view.MarginLayoutParamsCompat;
+import androidx.core.view.ViewCompat;
+
+final class Utils {
+
+ private Utils() { }
+
+ static int getMeasuredWidth(View v) {
+ return (v == null) ? 0 : v.getMeasuredWidth();
+ }
+
+ static int getWidth(View v) {
+ return (v == null) ? 0 : v.getWidth();
+ }
+
+ static int getWidthWithMargin(View v) {
+ return getWidth(v) + getMarginHorizontally(v);
+ }
+
+ static int getStart(View v) {
+ return getStart(v, false);
+ }
+
+ static int getStart(View v, boolean withoutPadding) {
+ if (v == null) {
+ return 0;
+ }
+ if (isLayoutRtl(v)) {
+ return (withoutPadding) ? v.getRight() - getPaddingStart(v) : v.getRight();
+ } else {
+ return (withoutPadding) ? v.getLeft() + getPaddingStart(v) : v.getLeft();
+ }
+ }
+
+ static int getEnd(View v) {
+ return getEnd(v, false);
+ }
+
+ static int getEnd(View v, boolean withoutPadding) {
+ if (v == null) {
+ return 0;
+ }
+ if (isLayoutRtl(v)) {
+ return (withoutPadding) ? v.getLeft() + getPaddingEnd(v) : v.getLeft();
+ } else {
+ return (withoutPadding) ? v.getRight() - getPaddingEnd(v) : v.getRight();
+ }
+ }
+
+ static int getPaddingStart(View v) {
+ if (v == null) {
+ return 0;
+ }
+ return ViewCompat.getPaddingStart(v);
+ }
+
+ static int getPaddingEnd(View v) {
+ if (v == null) {
+ return 0;
+ }
+ return ViewCompat.getPaddingEnd(v);
+ }
+
+ static int getPaddingHorizontally(View v) {
+ if (v == null) {
+ return 0;
+ }
+ return v.getPaddingLeft() + v.getPaddingRight();
+ }
+
+ static int getMarginStart(View v) {
+ if (v == null) {
+ return 0;
+ }
+ ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) v.getLayoutParams();
+ return MarginLayoutParamsCompat.getMarginStart(lp);
+ }
+
+ static int getMarginEnd(View v) {
+ if (v == null) {
+ return 0;
+ }
+ ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) v.getLayoutParams();
+ return MarginLayoutParamsCompat.getMarginEnd(lp);
+ }
+
+ static int getMarginHorizontally(View v) {
+ if (v == null) {
+ return 0;
+ }
+ ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) v.getLayoutParams();
+ return MarginLayoutParamsCompat.getMarginStart(lp) + MarginLayoutParamsCompat.getMarginEnd(lp);
+ }
+
+ static boolean isLayoutRtl(View v) {
+ return ViewCompat.getLayoutDirection(v) == ViewCompat.LAYOUT_DIRECTION_RTL;
+ }
+
+}
diff --git a/library/src/main/java/com/chwl/library/widget/tab/util/FragmentPageAdapter.kt b/library/src/main/java/com/chwl/library/widget/tab/util/FragmentPageAdapter.kt
new file mode 100644
index 000000000..da0c2e7e4
--- /dev/null
+++ b/library/src/main/java/com/chwl/library/widget/tab/util/FragmentPageAdapter.kt
@@ -0,0 +1,19 @@
+package com.chwl.library.widget.tab.util
+
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.FragmentActivity
+import androidx.viewpager2.adapter.FragmentStateAdapter
+
+class FragmentPageAdapter(fragmentManager: FragmentActivity, var fgList: List?) :
+ FragmentStateAdapter(fragmentManager) {
+
+
+ override fun getItemCount(): Int {
+ return fgList?.size?:0
+ }
+
+ override fun createFragment(position: Int): Fragment {
+ return fgList?.get(position) ?: Fragment()
+ }
+
+}
\ No newline at end of file
diff --git a/library/src/main/java/com/chwl/library/widget/tab/util/PagerItem.java b/library/src/main/java/com/chwl/library/widget/tab/util/PagerItem.java
new file mode 100644
index 000000000..69772b279
--- /dev/null
+++ b/library/src/main/java/com/chwl/library/widget/tab/util/PagerItem.java
@@ -0,0 +1,38 @@
+/**
+ * Copyright (C) 2015 ogaclejapan
+ *
+ * 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 com.chwl.library.widget.tab.util;
+
+public abstract class PagerItem {
+
+ protected static final float DEFAULT_WIDTH = 1.f;
+
+ private final CharSequence title;
+ private final float width;
+
+ protected PagerItem(CharSequence title, float width) {
+ this.title = title;
+ this.width = width;
+ }
+
+ public CharSequence getTitle() {
+ return title;
+ }
+
+ public float getWidth() {
+ return width;
+ }
+
+}
diff --git a/library/src/main/java/com/chwl/library/widget/tab/util/PagerItems.java b/library/src/main/java/com/chwl/library/widget/tab/util/PagerItems.java
new file mode 100644
index 000000000..6a9636511
--- /dev/null
+++ b/library/src/main/java/com/chwl/library/widget/tab/util/PagerItems.java
@@ -0,0 +1,34 @@
+/**
+ * Copyright (C) 2015 ogaclejapan
+ *
+ * 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 com.chwl.library.widget.tab.util;
+
+import android.content.Context;
+
+import java.util.ArrayList;
+
+public abstract class PagerItems extends ArrayList {
+
+ private final Context context;
+
+ protected PagerItems(Context context) {
+ this.context = context;
+ }
+
+ public Context getContext() {
+ return context;
+ }
+
+}
diff --git a/library/src/main/java/com/chwl/library/widget/tab/util/ViewPagerItem.java b/library/src/main/java/com/chwl/library/widget/tab/util/ViewPagerItem.java
new file mode 100644
index 000000000..ab5eabd4b
--- /dev/null
+++ b/library/src/main/java/com/chwl/library/widget/tab/util/ViewPagerItem.java
@@ -0,0 +1,45 @@
+/**
+ * Copyright (C) 2015 ogaclejapan
+ *
+ * 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 com.chwl.library.widget.tab.util;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.LayoutRes;
+
+public class ViewPagerItem extends PagerItem {
+
+ private final int resource;
+
+ protected ViewPagerItem(CharSequence title, float width, @LayoutRes int resource) {
+ super(title, width);
+ this.resource = resource;
+ }
+
+ public static ViewPagerItem of(CharSequence title, @LayoutRes int resource) {
+ return of(title, DEFAULT_WIDTH, resource);
+ }
+
+ public static ViewPagerItem of(CharSequence title, float width, @LayoutRes int resource) {
+ return new ViewPagerItem(title, width, resource);
+ }
+
+ public View initiate(LayoutInflater inflater, ViewGroup container) {
+ return inflater.inflate(resource, container, false);
+ }
+
+}
diff --git a/library/src/main/java/com/chwl/library/widget/tab/util/ViewPagerItemAdapter.java b/library/src/main/java/com/chwl/library/widget/tab/util/ViewPagerItemAdapter.java
new file mode 100644
index 000000000..4dc50fad7
--- /dev/null
+++ b/library/src/main/java/com/chwl/library/widget/tab/util/ViewPagerItemAdapter.java
@@ -0,0 +1,83 @@
+/**
+ * Copyright (C) 2015 ogaclejapan
+ *
+ * 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 com.chwl.library.widget.tab.util;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.collection.SparseArrayCompat;
+import androidx.viewpager.widget.PagerAdapter;
+
+import java.lang.ref.WeakReference;
+
+public class ViewPagerItemAdapter extends PagerAdapter {
+
+ private final ViewPagerItems pages;
+ private final SparseArrayCompat> holder;
+ private final LayoutInflater inflater;
+
+ public ViewPagerItemAdapter(ViewPagerItems pages) {
+ this.pages = pages;
+ this.holder = new SparseArrayCompat<>(pages.size());
+ this.inflater = LayoutInflater.from(pages.getContext());
+ }
+
+ @Override
+ public int getCount() {
+ return pages.size();
+ }
+
+ @NonNull
+ @Override
+ public Object instantiateItem(@NonNull ViewGroup container, int position) {
+ View view = getPagerItem(position).initiate(inflater, container);
+ container.addView(view);
+ holder.put(position, new WeakReference(view));
+ return view;
+ }
+
+ @Override
+ public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
+ holder.remove(position);
+ container.removeView((View) object);
+ }
+
+ @Override
+ public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
+ return object == view;
+ }
+
+ @Override
+ public CharSequence getPageTitle(int position) {
+ return getPagerItem(position).getTitle();
+ }
+
+ @Override
+ public float getPageWidth(int position) {
+ return getPagerItem(position).getWidth();
+ }
+
+ public View getPage(int position) {
+ final WeakReference weakRefItem = holder.get(position);
+ return (weakRefItem != null) ? weakRefItem.get() : null;
+ }
+
+ protected ViewPagerItem getPagerItem(int position) {
+ return pages.get(position);
+ }
+}
diff --git a/library/src/main/java/com/chwl/library/widget/tab/util/ViewPagerItems.java b/library/src/main/java/com/chwl/library/widget/tab/util/ViewPagerItems.java
new file mode 100644
index 000000000..e456e9de5
--- /dev/null
+++ b/library/src/main/java/com/chwl/library/widget/tab/util/ViewPagerItems.java
@@ -0,0 +1,64 @@
+/**
+ * Copyright (C) 2015 ogaclejapan
+ *
+ * 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 com.chwl.library.widget.tab.util;
+
+import android.content.Context;
+
+import androidx.annotation.LayoutRes;
+import androidx.annotation.StringRes;
+
+public class ViewPagerItems extends PagerItems {
+
+ public ViewPagerItems(Context context) {
+ super(context);
+ }
+
+ public static Creator with(Context context) {
+ return new Creator(context);
+ }
+
+ public static class Creator {
+
+ private final ViewPagerItems items;
+
+ public Creator(Context context) {
+ items = new ViewPagerItems(context);
+ }
+
+ public Creator add(@StringRes int title, @LayoutRes int resource) {
+ return add(ViewPagerItem.of(items.getContext().getString(title), resource));
+ }
+
+ public Creator add(@StringRes int title, float width, @LayoutRes int resource) {
+ return add(ViewPagerItem.of(items.getContext().getString(title), width, resource));
+ }
+
+ public Creator add(CharSequence title, @LayoutRes int resource) {
+ return add(ViewPagerItem.of(title, resource));
+ }
+
+ public Creator add(ViewPagerItem item) {
+ items.add(item);
+ return this;
+ }
+
+ public ViewPagerItems create() {
+ return items;
+ }
+
+ }
+
+}
diff --git a/library/src/main/java/com/chwl/library/widget/tab/util/v4/Bundler.java b/library/src/main/java/com/chwl/library/widget/tab/util/v4/Bundler.java
new file mode 100644
index 000000000..527ae53e4
--- /dev/null
+++ b/library/src/main/java/com/chwl/library/widget/tab/util/v4/Bundler.java
@@ -0,0 +1,520 @@
+/**
+ * Copyright (C) 2015 ogaclejapan
+ *
+ * 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 com.chwl.library.widget.tab.util.v4;
+
+import android.annotation.TargetApi;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Parcelable;
+import android.util.Size;
+import android.util.SizeF;
+import android.util.SparseArray;
+
+import androidx.fragment.app.Fragment;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+
+public class Bundler {
+
+ private final Bundle bundle;
+
+ /**
+ * Constructs a new, empty Bundle.
+ */
+ public Bundler() {
+ this(null);
+ }
+
+ private Bundler(Bundle b) {
+ bundle = (b == null) ? new Bundle() : new Bundle(b);
+ }
+
+ /**
+ * Constructs a Bundle containing a copy of the mappings from the given
+ * Bundle.
+ *
+ * @param b a Bundle to be copied.
+ */
+ public static Bundler of(Bundle b) {
+ return new Bundler(b);
+ }
+
+ /**
+ * Inserts all mappings from the given Bundle into this Bundle.
+ *
+ * @param bundle a Bundle
+ * @return this
+ */
+ public Bundler putAll(Bundle bundle) {
+ this.bundle.putAll(bundle);
+ return this;
+ }
+
+ /**
+ * Inserts a byte value into the mapping of this Bundle, replacing
+ * any existing value for the given key.
+ *
+ * @param key a String, or null
+ * @param value a byte
+ * @return this
+ */
+ public Bundler putByte(String key, byte value) {
+ bundle.putByte(key, value);
+ return this;
+ }
+
+ /**
+ * Inserts a char value into the mapping of this Bundle, replacing
+ * any existing value for the given key.
+ *
+ * @param key a String, or null
+ * @param value a char, or null
+ * @return this
+ */
+ public Bundler putChar(String key, char value) {
+ bundle.putChar(key, value);
+ return this;
+ }
+
+ /**
+ * Inserts a short value into the mapping of this Bundle, replacing
+ * any existing value for the given key.
+ *
+ * @param key a String, or null
+ * @param value a short
+ * @return this
+ */
+ public Bundler putShort(String key, short value) {
+ bundle.putShort(key, value);
+ return this;
+ }
+
+ /**
+ * Inserts a float value into the mapping of this Bundle, replacing
+ * any existing value for the given key.
+ *
+ * @param key a String, or null
+ * @param value a float
+ * @return this
+ */
+ public Bundler putFloat(String key, float value) {
+ bundle.putFloat(key, value);
+ return this;
+ }
+
+ /**
+ * Inserts a CharSequence value into the mapping of this Bundle, replacing
+ * any existing value for the given key. Either key or value may be null.
+ *
+ * @param key a String, or null
+ * @param value a CharSequence, or null
+ * @return this
+ */
+ public Bundler putCharSequence(String key, CharSequence value) {
+ bundle.putCharSequence(key, value);
+ return this;
+ }
+
+ /**
+ * Inserts a Parcelable value into the mapping of this Bundle, replacing
+ * any existing value for the given key. Either key or value may be null.
+ *
+ * @param key a String, or null
+ * @param value a Parcelable object, or null
+ * @return this
+ */
+ public Bundler putParcelable(String key, Parcelable value) {
+ bundle.putParcelable(key, value);
+ return this;
+ }
+
+ /**
+ * Inserts a Size value into the mapping of this Bundle, replacing
+ * any existing value for the given key. Either key or value may be null.
+ *
+ * @param key a String, or null
+ * @param value a Size object, or null
+ * @return this
+ */
+ @TargetApi(21)
+ public Bundler putSize(String key, Size value) {
+ bundle.putSize(key, value);
+ return this;
+ }
+
+ /**
+ * Inserts a SizeF value into the mapping of this Bundle, replacing
+ * any existing value for the given key. Either key or value may be null.
+ *
+ * @param key a String, or null
+ * @param value a SizeF object, or null
+ * @return this
+ */
+ @TargetApi(21)
+ public Bundler putSizeF(String key, SizeF value) {
+ bundle.putSizeF(key, value);
+ return this;
+ }
+
+ /**
+ * Inserts an array of Parcelable values into the mapping of this Bundle,
+ * replacing any existing value for the given key. Either key or value may
+ * be null.
+ *
+ * @param key a String, or null
+ * @param value an array of Parcelable objects, or null
+ * @return this
+ */
+ public Bundler putParcelableArray(String key, Parcelable[] value) {
+ bundle.putParcelableArray(key, value);
+ return this;
+ }
+
+ /**
+ * Inserts a List of Parcelable values into the mapping of this Bundle,
+ * replacing any existing value for the given key. Either key or value may
+ * be null.
+ *
+ * @param key a String, or null
+ * @param value an ArrayList of Parcelable objects, or null
+ * @return this
+ */
+ public Bundler putParcelableArrayList(String key,
+ ArrayList extends Parcelable> value) {
+ bundle.putParcelableArrayList(key, value);
+ return this;
+ }
+
+ /**
+ * Inserts a SparceArray of Parcelable values into the mapping of this
+ * Bundle, replacing any existing value for the given key. Either key
+ * or value may be null.
+ *
+ * @param key a String, or null
+ * @param value a SparseArray of Parcelable objects, or null
+ * @return this
+ */
+ public Bundler putSparseParcelableArray(String key,
+ SparseArray extends Parcelable> value) {
+ bundle.putSparseParcelableArray(key, value);
+ return this;
+ }
+
+ /**
+ * Inserts an ArrayList value into the mapping of this Bundle, replacing
+ * any existing value for the given key. Either key or value may be null.
+ *
+ * @param key a String, or null
+ * @param value an ArrayList object, or null
+ * @return this
+ */
+ public Bundler putIntegerArrayList(String key, ArrayList value) {
+ bundle.putIntegerArrayList(key, value);
+ return this;
+ }
+
+ /**
+ * Inserts an ArrayList value into the mapping of this Bundle, replacing
+ * any existing value for the given key. Either key or value may be null.
+ *
+ * @param key a String, or null
+ * @param value an ArrayList object, or null
+ * @return this
+ */
+ public Bundler putStringArrayList(String key, ArrayList value) {
+ bundle.putStringArrayList(key, value);
+ return this;
+ }
+
+ /**
+ * Inserts an ArrayList value into the mapping of this Bundle, replacing
+ * any existing value for the given key. Either key or value may be null.
+ *
+ * @param key a String, or null
+ * @param value an ArrayList object, or null
+ * @return this
+ */
+ @TargetApi(8)
+ public Bundler putCharSequenceArrayList(String key, ArrayList value) {
+ bundle.putCharSequenceArrayList(key, value);
+ return this;
+ }
+
+ /**
+ * Inserts a Serializable value into the mapping of this Bundle, replacing
+ * any existing value for the given key. Either key or value may be null.
+ *
+ * @param key a String, or null
+ * @param value a Serializable object, or null
+ * @return this
+ */
+ public Bundler putSerializable(String key, Serializable value) {
+ bundle.putSerializable(key, value);
+ return this;
+ }
+
+ /**
+ * Inserts a byte array value into the mapping of this Bundle, replacing
+ * any existing value for the given key. Either key or value may be null.
+ *
+ * @param key a String, or null
+ * @param value a byte array object, or null
+ * @return this
+ */
+ public Bundler putByteArray(String key, byte[] value) {
+ bundle.putByteArray(key, value);
+ return this;
+ }
+
+ /**
+ * Inserts a short array value into the mapping of this Bundle, replacing
+ * any existing value for the given key. Either key or value may be null.
+ *
+ * @param key a String, or null
+ * @param value a short array object, or null
+ * @return this
+ */
+ public Bundler putShortArray(String key, short[] value) {
+ bundle.putShortArray(key, value);
+ return this;
+ }
+
+ /**
+ * Inserts a char array value into the mapping of this Bundle, replacing
+ * any existing value for the given key. Either key or value may be null.
+ *
+ * @param key a String, or null
+ * @param value a char array object, or null
+ * @return this
+ */
+ public Bundler putCharArray(String key, char[] value) {
+ bundle.putCharArray(key, value);
+ return this;
+ }
+
+ /**
+ * Inserts a float array value into the mapping of this Bundle, replacing
+ * any existing value for the given key. Either key or value may be null.
+ *
+ * @param key a String, or null
+ * @param value a float array object, or null
+ * @return this
+ */
+ public Bundler putFloatArray(String key, float[] value) {
+ bundle.putFloatArray(key, value);
+ return this;
+ }
+
+ /**
+ * Inserts a CharSequence array value into the mapping of this Bundle, replacing
+ * any existing value for the given key. Either key or value may be null.
+ *
+ * @param key a String, or null
+ * @param value a CharSequence array object, or null
+ * @return this
+ */
+ @TargetApi(8)
+ public Bundler putCharSequenceArray(String key, CharSequence[] value) {
+ bundle.putCharSequenceArray(key, value);
+ return this;
+ }
+
+ /**
+ * Inserts a Bundle value into the mapping of this Bundle, replacing
+ * any existing value for the given key. Either key or value may be null.
+ *
+ * @param key a String, or null
+ * @param value a Bundle object, or null
+ * @return this
+ */
+ public Bundler putBundle(String key, Bundle value) {
+ bundle.putBundle(key, value);
+ return this;
+ }
+
+ /**
+ * Inserts an {@link IBinder} value into the mapping of this Bundle, replacing
+ * any existing value for the given key. Either key or value may be null.
+ *
+ * You should be very careful when using this function. In many
+ * places where Bundles are used (such as inside of Intent objects), the Bundle
+ * can live longer inside of another process than the process that had originally
+ * created it. In that case, the IBinder you supply here will become invalid
+ * when your process goes away, and no longer usable, even if a new process is
+ * created for you later on.
+ *
+ * @param key a String, or null
+ * @param value an IBinder object, or null
+ * @return this
+ */
+ @TargetApi(18)
+ public Bundler putBinder(String key, IBinder value) {
+ bundle.putBinder(key, value);
+ return this;
+ }
+
+ /**
+ * Inserts a Boolean value into the mapping of this Bundle, replacing
+ * any existing value for the given key. Either key or value may be null.
+ *
+ * @param key a String, or null
+ * @param value a Boolean, or null
+ * @return this
+ */
+ public Bundler putBoolean(String key, boolean value) {
+ bundle.putBoolean(key, value);
+ return this;
+ }
+
+ /**
+ * Inserts an int value into the mapping of this Bundle, replacing
+ * any existing value for the given key.
+ *
+ * @param key a String, or null
+ * @param value an int, or null
+ * @return this
+ */
+ public Bundler putInt(String key, int value) {
+ bundle.putInt(key, value);
+ return this;
+ }
+
+ /**
+ * Inserts a long value into the mapping of this Bundle, replacing
+ * any existing value for the given key.
+ *
+ * @param key a String, or null
+ * @param value a long
+ * @return this
+ */
+ public Bundler putLong(String key, long value) {
+ bundle.putLong(key, value);
+ return this;
+ }
+
+ /**
+ * Inserts a double value into the mapping of this Bundle, replacing
+ * any existing value for the given key.
+ *
+ * @param key a String, or null
+ * @param value a double
+ * @return this
+ */
+ public Bundler putDouble(String key, double value) {
+ bundle.putDouble(key, value);
+ return this;
+ }
+
+ /**
+ * Inserts a String value into the mapping of this Bundle, replacing
+ * any existing value for the given key. Either key or value may be null.
+ *
+ * @param key a String, or null
+ * @param value a String, or null
+ * @return this
+ */
+ public Bundler putString(String key, String value) {
+ bundle.putString(key, value);
+ return this;
+ }
+
+ /**
+ * Inserts a boolean array value into the mapping of this Bundle, replacing
+ * any existing value for the given key. Either key or value may be null.
+ *
+ * @param key a String, or null
+ * @param value a boolean array object, or null
+ * @return this
+ */
+ public Bundler putBooleanArray(String key, boolean[] value) {
+ bundle.putBooleanArray(key, value);
+ return this;
+ }
+
+ /**
+ * Inserts an int array value into the mapping of this Bundle, replacing
+ * any existing value for the given key. Either key or value may be null.
+ *
+ * @param key a String, or null
+ * @param value an int array object, or null
+ * @return this
+ */
+ public Bundler putIntArray(String key, int[] value) {
+ bundle.putIntArray(key, value);
+ return this;
+ }
+
+ /**
+ * Inserts a long array value into the mapping of this Bundle, replacing
+ * any existing value for the given key. Either key or value may be null.
+ *
+ * @param key a String, or null
+ * @param value a long array object, or null
+ * @return this
+ */
+ public Bundler putLongArray(String key, long[] value) {
+ bundle.putLongArray(key, value);
+ return this;
+ }
+
+ /**
+ * Inserts a double array value into the mapping of this Bundle, replacing
+ * any existing value for the given key. Either key or value may be null.
+ *
+ * @param key a String, or null
+ * @param value a double array object, or null
+ * @return this
+ */
+ public Bundler putDoubleArray(String key, double[] value) {
+ bundle.putDoubleArray(key, value);
+ return this;
+ }
+
+ /**
+ * Inserts a String array value into the mapping of this Bundle, replacing
+ * any existing value for the given key. Either key or value may be null.
+ *
+ * @param key a String, or null
+ * @param value a String array object, or null
+ * @return this
+ */
+ public Bundler putStringArray(String key, String[] value) {
+ bundle.putStringArray(key, value);
+ return this;
+ }
+
+ /**
+ * Get the bundle.
+ *
+ * @return a bundle
+ */
+ public Bundle get() {
+ return bundle;
+ }
+
+ /**
+ * Set the argument of Fragment.
+ *
+ * @param fragment a fragment
+ * @return a fragment
+ */
+ public T into(T fragment) {
+ fragment.setArguments(get());
+ return fragment;
+ }
+
+}
diff --git a/library/src/main/java/com/chwl/library/widget/tab/util/v4/FragmentPagerItem.java b/library/src/main/java/com/chwl/library/widget/tab/util/v4/FragmentPagerItem.java
new file mode 100644
index 000000000..7ca6266e7
--- /dev/null
+++ b/library/src/main/java/com/chwl/library/widget/tab/util/v4/FragmentPagerItem.java
@@ -0,0 +1,76 @@
+/**
+ * Copyright (C) 2015 ogaclejapan
+ *
+ * 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 com.chwl.library.widget.tab.util.v4;
+
+import android.content.Context;
+import android.os.Bundle;
+
+import androidx.fragment.app.Fragment;
+
+import com.chwl.library.widget.tab.util.PagerItem;
+
+
+public class FragmentPagerItem extends PagerItem {
+
+ private static final String TAG = "FragmentPagerItem";
+ private static final String KEY_POSITION = TAG + ":Position";
+
+ private final String className;
+ private final Bundle args;
+
+ protected FragmentPagerItem(CharSequence title, float width, String className, Bundle args) {
+ super(title, width);
+ this.className = className;
+ this.args = args;
+ }
+
+ public static FragmentPagerItem of(CharSequence title, Class extends Fragment> clazz) {
+ return of(title, DEFAULT_WIDTH, clazz);
+ }
+
+ public static FragmentPagerItem of(CharSequence title, Class extends Fragment> clazz,
+ Bundle args) {
+ return of(title, DEFAULT_WIDTH, clazz, args);
+ }
+
+ public static FragmentPagerItem of(CharSequence title, float width,
+ Class extends Fragment> clazz) {
+ return of(title, width, clazz, new Bundle());
+ }
+
+ public static FragmentPagerItem of(CharSequence title, float width,
+ Class extends Fragment> clazz, Bundle args) {
+ return new FragmentPagerItem(title, width, clazz.getName(), args);
+ }
+
+ public static boolean hasPosition(Bundle args) {
+ return args != null && args.containsKey(KEY_POSITION);
+ }
+
+ public static int getPosition(Bundle args) {
+ return (hasPosition(args)) ? args.getInt(KEY_POSITION) : 0;
+ }
+
+ static void setPosition(Bundle args, int position) {
+ args.putInt(KEY_POSITION, position);
+ }
+
+ public Fragment instantiate(Context context, int position) {
+ setPosition(args, position);
+ return Fragment.instantiate(context, className, args);
+ }
+
+}
diff --git a/library/src/main/java/com/chwl/library/widget/tab/util/v4/FragmentPagerItemAdapter.java b/library/src/main/java/com/chwl/library/widget/tab/util/v4/FragmentPagerItemAdapter.java
new file mode 100644
index 000000000..dd99fdfe9
--- /dev/null
+++ b/library/src/main/java/com/chwl/library/widget/tab/util/v4/FragmentPagerItemAdapter.java
@@ -0,0 +1,84 @@
+/**
+ * Copyright (C) 2015 ogaclejapan
+ *
+ * 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 com.chwl.library.widget.tab.util.v4;
+
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.collection.SparseArrayCompat;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentManager;
+import androidx.fragment.app.FragmentPagerAdapter;
+
+import java.lang.ref.WeakReference;
+
+public class FragmentPagerItemAdapter extends FragmentPagerAdapter {
+
+ private final FragmentPagerItems pages;
+ private final SparseArrayCompat> holder;
+
+ public FragmentPagerItemAdapter(FragmentManager fm, FragmentPagerItems pages) {
+ super(fm);
+ this.pages = pages;
+ this.holder = new SparseArrayCompat<>(pages.size());
+ }
+
+ @Override
+ public int getCount() {
+ return pages.size();
+ }
+
+ @Override
+ public Fragment getItem(int position) {
+ return getPagerItem(position).instantiate(pages.getContext(), position);
+ }
+
+ @NonNull
+ @Override
+ public Object instantiateItem(@NonNull ViewGroup container, int position) {
+ Object item = super.instantiateItem(container, position);
+ if (item instanceof Fragment) {
+ holder.put(position, new WeakReference((Fragment) item));
+ }
+ return item;
+ }
+
+ @Override
+ public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
+ holder.remove(position);
+ super.destroyItem(container, position, object);
+ }
+
+ @Override
+ public CharSequence getPageTitle(int position) {
+ return getPagerItem(position).getTitle();
+ }
+
+ @Override
+ public float getPageWidth(int position) {
+ return super.getPageWidth(position);
+ }
+
+ public Fragment getPage(int position) {
+ final WeakReference weakRefItem = holder.get(position);
+ return (weakRefItem != null) ? weakRefItem.get() : null;
+ }
+
+ protected FragmentPagerItem getPagerItem(int position) {
+ return pages.get(position);
+ }
+
+}
diff --git a/library/src/main/java/com/chwl/library/widget/tab/util/v4/FragmentPagerItems.java b/library/src/main/java/com/chwl/library/widget/tab/util/v4/FragmentPagerItems.java
new file mode 100644
index 000000000..c5c987761
--- /dev/null
+++ b/library/src/main/java/com/chwl/library/widget/tab/util/v4/FragmentPagerItems.java
@@ -0,0 +1,81 @@
+/**
+ * Copyright (C) 2015 ogaclejapan
+ *
+ * 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 com.chwl.library.widget.tab.util.v4;
+
+import android.content.Context;
+import android.os.Bundle;
+
+import androidx.annotation.StringRes;
+import androidx.fragment.app.Fragment;
+
+import com.chwl.library.widget.tab.util.PagerItems;
+
+
+public class FragmentPagerItems extends PagerItems {
+
+ public FragmentPagerItems(Context context) {
+ super(context);
+ }
+
+ public static Creator with(Context context) {
+ return new Creator(context);
+ }
+
+ public static class Creator {
+
+ private final FragmentPagerItems items;
+
+ public Creator(Context context) {
+ items = new FragmentPagerItems(context);
+ }
+
+ public Creator add(@StringRes int title, Class extends Fragment> clazz) {
+ return add(FragmentPagerItem.of(items.getContext().getString(title), clazz));
+ }
+
+ public Creator add(@StringRes int title, Class extends Fragment> clazz, Bundle args) {
+ return add(FragmentPagerItem.of(items.getContext().getString(title), clazz, args));
+ }
+
+ public Creator add(@StringRes int title, float width, Class extends Fragment> clazz) {
+ return add(FragmentPagerItem.of(items.getContext().getString(title), width, clazz));
+ }
+
+ public Creator add(@StringRes int title, float width, Class extends Fragment> clazz,
+ Bundle args) {
+ return add(FragmentPagerItem.of(items.getContext().getString(title), width, clazz, args));
+ }
+
+ public Creator add(CharSequence title, Class extends Fragment> clazz) {
+ return add(FragmentPagerItem.of(title, clazz));
+ }
+
+ public Creator add(CharSequence title, Class extends Fragment> clazz, Bundle args) {
+ return add(FragmentPagerItem.of(title, clazz, args));
+ }
+
+ public Creator add(FragmentPagerItem item) {
+ items.add(item);
+ return this;
+ }
+
+ public FragmentPagerItems create() {
+ return items;
+ }
+
+ }
+
+}
diff --git a/library/src/main/java/com/chwl/library/widget/tab/util/v4/FragmentStatePagerItemAdapter.java b/library/src/main/java/com/chwl/library/widget/tab/util/v4/FragmentStatePagerItemAdapter.java
new file mode 100644
index 000000000..fe29eb7b5
--- /dev/null
+++ b/library/src/main/java/com/chwl/library/widget/tab/util/v4/FragmentStatePagerItemAdapter.java
@@ -0,0 +1,84 @@
+/**
+ * Copyright (C) 2015 ogaclejapan
+ *
+ * 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 com.chwl.library.widget.tab.util.v4;
+
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.collection.SparseArrayCompat;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentManager;
+import androidx.fragment.app.FragmentStatePagerAdapter;
+
+import java.lang.ref.WeakReference;
+
+public class FragmentStatePagerItemAdapter extends FragmentStatePagerAdapter {
+
+ private final FragmentPagerItems pages;
+ private final SparseArrayCompat> holder;
+
+ public FragmentStatePagerItemAdapter(FragmentManager fm, FragmentPagerItems pages) {
+ super(fm);
+ this.pages = pages;
+ this.holder = new SparseArrayCompat<>(pages.size());
+ }
+
+ @Override
+ public int getCount() {
+ return pages.size();
+ }
+
+ @Override
+ public Fragment getItem(int position) {
+ return getPagerItem(position).instantiate(pages.getContext(), position);
+ }
+
+ @NonNull
+ @Override
+ public Object instantiateItem(@NonNull ViewGroup container, int position) {
+ Object item = super.instantiateItem(container, position);
+ if (item instanceof Fragment) {
+ holder.put(position, new WeakReference((Fragment) item));
+ }
+ return item;
+ }
+
+ @Override
+ public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
+ holder.remove(position);
+ super.destroyItem(container, position, object);
+ }
+
+ @Override
+ public CharSequence getPageTitle(int position) {
+ return getPagerItem(position).getTitle();
+ }
+
+ @Override
+ public float getPageWidth(int position) {
+ return getPagerItem(position).getWidth();
+ }
+
+ public Fragment getPage(int position) {
+ final WeakReference weakRefItem = holder.get(position);
+ return (weakRefItem != null) ? weakRefItem.get() : null;
+ }
+
+ protected FragmentPagerItem getPagerItem(int position) {
+ return pages.get(position);
+ }
+
+}
diff --git a/library/src/main/java/com/chwl/library/widget/text/DrawableTextView.java b/library/src/main/java/com/chwl/library/widget/text/DrawableTextView.java
index 562313377..0ab96cb24 100644
--- a/library/src/main/java/com/chwl/library/widget/text/DrawableTextView.java
+++ b/library/src/main/java/com/chwl/library/widget/text/DrawableTextView.java
@@ -120,7 +120,7 @@ public class DrawableTextView extends AppCompatTextView {
strikeColor = a.getColor(R.styleable.DrawableTextView_dt_strikeColor, -1);
strikeWidth = a.getDimensionPixelSize(R.styleable.DrawableTextView_dt_strikeWidth, 0);
//填充颜色
- soildColor = a.getColor(R.styleable.DrawableTextView_dt_soildColor, 0xffffffff);
+ soildColor = a.getColor(R.styleable.DrawableTextView_dt_soildColor, 0x00000000);
//渐变相关
angle = a.getInt(R.styleable.DrawableTextView_dt_angle, 0);
startColor = a.getColor(R.styleable.DrawableTextView_dt_startColor, -1);
diff --git a/library/src/main/res/values/attrs.xml b/library/src/main/res/values/attrs.xml
index 185b1dfd3..68afd3200 100644
--- a/library/src/main/res/values/attrs.xml
+++ b/library/src/main/res/values/attrs.xml
@@ -191,4 +191,64 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/library/src/module_common/java/com/chwl/library/common/glide/AnimEffectUtil.kt b/library/src/module_common/java/com/chwl/library/common/glide/AnimEffectUtil.kt
new file mode 100644
index 000000000..d4ac20d19
--- /dev/null
+++ b/library/src/module_common/java/com/chwl/library/common/glide/AnimEffectUtil.kt
@@ -0,0 +1,434 @@
+//package com.kelly.dawi.util
+//
+//import android.graphics.Bitmap
+//import android.graphics.Paint
+//import android.os.Looper
+//import android.text.TextPaint
+//import android.view.View
+//import android.widget.ImageView
+//import androidx.annotation.DrawableRes
+//import androidx.lifecycle.findViewTreeLifecycleOwner
+//import androidx.lifecycle.lifecycleScope
+//import com.bumptech.glide.Glide
+//import com.bumptech.glide.load.DataSource
+//import com.bumptech.glide.load.engine.GlideException
+//import com.bumptech.glide.request.FutureTarget
+//import com.bumptech.glide.request.RequestFutureTarget
+//import com.bumptech.glide.request.RequestListener
+//import com.bumptech.glide.request.RequestOptions
+//import com.bumptech.glide.request.target.Target
+//import com.kelly.dawi.dp
+//import com.kelly.dawi.getOrNull
+//import com.kelly.dawi.simpleImpl.SimpleSvgaCallback
+//import com.kelly.dawi.suspendGetOrNull
+//import com.opensource.svgaplayer.SVGAImageView
+//import com.opensource.svgaplayer.glideplugin.asSVGADrawable
+//import com.tencent.qgame.animplayer.AnimView
+//import com.tencent.qgame.animplayer.inter.IFetchResource
+//import com.tencent.qgame.animplayer.mix.Resource
+//import com.tencent.qgame.animplayer.util.ScaleType
+//import com.kelly.dawi.simpleImpl.SimpleVapCallback
+//import kotlinx.coroutines.*
+//import java.io.File
+//import java.lang.RuntimeException
+//import java.util.concurrent.CancellationException
+//
+///**
+// * @Author Vance
+// * @Date 2022/6/17 0017 13:44
+// */
+//
+//object AnimEffectUtil {
+//
+// @JvmStatic
+// fun newBuilder(): ExtBuilder {
+// return ExtBuilder()
+// }
+//
+// @JvmStatic
+// fun load(url: String?): ExtBuilder {
+// return ExtBuilder().load(url)
+// }
+//
+// class ExtBuilder : IFetchResource, View.OnAttachStateChangeListener {
+// private val defTextPaint = TextPaint().apply { textAlign = Paint.Align.CENTER }
+//
+// private var job: Job? = null
+// private var extMap = mutableMapOf()
+// private var glideRequests = mutableListOf?>()
+//
+// private var tempExtMap = mutableMapOf()
+// private var listener: Listener? = null
+// private var repeatCount: Int? = null
+// private var clearsAfterDetached: Boolean? = null
+// private var scaleType: ImageView.ScaleType? = null
+//
+// private var url: String? = null
+//
+// private var skipMemoryCache = true
+//
+// private var scope:CoroutineScope? = null
+//
+// fun load(url: String?): ExtBuilder {
+// this.url = url
+// return this
+// }
+//
+// fun setCoroutineScope(scope:CoroutineScope): ExtBuilder {
+// this.scope = scope
+// return this
+// }
+//
+// fun skipMemoryCache(skipMemoryCache: Boolean): ExtBuilder {
+// this.skipMemoryCache = skipMemoryCache
+// return this
+// }
+//
+// fun scaleType(scaleType: ImageView.ScaleType): ExtBuilder {
+// this.scaleType = scaleType
+// return this
+// }
+//
+// fun clearsAfterDetached(clearsAfterDetached: Boolean): ExtBuilder {
+// this.clearsAfterDetached = clearsAfterDetached
+// return this
+// }
+//
+// fun listener(listener: Listener?): ExtBuilder {
+// this.listener = listener
+// return this
+// }
+//
+// fun repeatCount(repeatCount: Int): ExtBuilder {
+// this.repeatCount = repeatCount
+// return this
+// }
+//
+// /**
+// * textPain是SVGA用的
+// */
+// @JvmOverloads
+// fun putText(key: String, text: String?, textPaint: TextPaint = defTextPaint): ExtBuilder {
+// tempExtMap[key] = Ext(text, textPaint)
+// return this
+// }
+//
+// @JvmOverloads
+// fun putImg(
+// key: String,
+// imgUrl: Any?,
+// widthDp: Float = 0f,
+// heightDp: Float = 0f,
+// isCircle: Boolean = true,
+// @DrawableRes default: Int = 0
+// ): ExtBuilder {
+// tempExtMap[key] = Ext(
+// imgGetter = {
+// val option = RequestOptions()
+// if (isCircle) {
+// option.circleCrop()
+// }
+// if (widthDp > 0 && heightDp > 0) {
+// option.override(widthDp.dp, heightDp.dp)
+// }
+//
+// val futureTarget = RequestFutureTarget(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
+// glideRequests.add(futureTarget)
+// var bitmap: Bitmap? = null
+// try {
+// bitmap = Glide.with(MyUtils.application)
+// .asBitmap()
+// .load(imgUrl)
+// .apply(option)
+// .addListener(futureTarget)
+// .into(futureTarget)
+// .get()
+// }catch (e: InterruptedException){
+// glideRequests.remove(futureTarget)
+// return@Ext null //取消掉的直接返回不去加载默认图了
+// }catch (e: CancellationException){
+// glideRequests.remove(futureTarget)
+// return@Ext null //取消掉的直接返回不去加载默认图了
+// }catch (e: Exception){
+// glideRequests.remove(futureTarget)
+// }
+//
+// if (bitmap == null && default != 0) {
+// val defFutureTarget = RequestFutureTarget(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
+// glideRequests.add(defFutureTarget)
+// bitmap = Glide.with(MyUtils.application)
+// .asBitmap()
+// .load(default)
+// .apply(option)
+// .addListener(defFutureTarget)
+// .into(defFutureTarget)
+// .getOrNull()
+// }
+// bitmap
+// })
+// return this
+// }
+//
+// fun into(svgaImageView: SVGAImageView){
+// setup(svgaImageView)
+// val animUrl = url
+// if(animUrl.isNullOrBlank()){
+// listener?.onAnimError(RuntimeException("url is empty"))
+// return
+// }
+//
+// var svgaUrl = animUrl
+// if(!animUrl.startsWith("http")){//没有http前缀就当成asset文件加载
+// svgaUrl = "file:///android_asset/$animUrl"
+// }
+//
+// if(scope == null){
+// scope = svgaImageView.findViewTreeLifecycleOwner()?.lifecycleScope
+// }
+//
+// job = scope?.launch(Dispatchers.IO) {
+// val svgaJob = async {
+// Glide.with(svgaImageView.context)
+// .asSVGADrawable()
+// .load(svgaUrl.trim())
+// .skipMemoryCache(skipMemoryCache)
+// .submit()
+// .suspendGetOrNull()
+// }
+//
+// val bitmapJobMap = mutableMapOf>()
+// val textMap = mutableMapOf()
+// val paramsMap = mutableMapOf()
+// try {
+// paramsMap.putAll(extMap)
+// paramsMap.forEach {
+// ensureActive()
+// if (it.value.isImg()) {
+// val job = async { it.value.getBitMap() }
+// bitmapJobMap[it.key] = job
+// } else {
+// textMap[it.key] = it.value
+// }
+// }
+// } catch (_: Exception) { }
+//
+// val drawable = svgaJob.await()
+// if (drawable == null) {
+// bitmapJobMap.forEach {
+// it.value.cancelAndJoin()
+// }
+// val imgRequests = glideRequests
+// imgRequests.forEach {
+// it?.cancel(true)
+// }
+// withContext(Dispatchers.Main) {
+// onAnimError("svga loading error ")
+// }
+// } else {
+// bitmapJobMap.forEach { entry ->
+// ensureActive()
+// entry.value.await()?.let {
+// drawable.dynamicItem.setDynamicImage(it, entry.key)
+// }
+// }
+// textMap.forEach { entry ->
+// entry.value.text?.let {
+// drawable.dynamicItem.setDynamicText(it, entry.value.textPaint, entry.key)
+// }
+// }
+//
+// withContext(Dispatchers.Main) {
+// onAnimStart()
+// svgaImageView.setImageDrawable(drawable)
+// svgaImageView.startAnimation()
+// extMap = mutableMapOf()
+// glideRequests = mutableListOf()
+// }
+// }
+// }
+// }
+//
+// fun into(animView: AnimView){
+// setup(animView)
+// val mp4Url = url
+// if(mp4Url.isNullOrBlank()){
+// listener?.onAnimError(RuntimeException("url is empty"))
+// return
+// }
+//
+// animView.setFetchResource(this)
+//
+// if(!mp4Url.startsWith("http")){//没有http前缀就当成asset文件加载
+// onAnimStart()
+// animView.startPlay(animView.context.assets, mp4Url)
+// return
+// }
+//
+// if(scope == null){
+// scope = animView.findViewTreeLifecycleOwner()?.lifecycleScope
+// }
+// job = scope?.launch(Dispatchers.IO) {
+// Glide.with(animView.context)
+// .asFile()
+// .skipMemoryCache(skipMemoryCache)
+// .load(mp4Url)
+// .addListener(object : RequestListener {
+// override fun onLoadFailed(e: GlideException?, model: Any?, target: Target, isFirstResource: Boolean): Boolean {
+// e?.logRootCauses("vap_loading_error")
+// animView.post {
+// onAnimError("vap loading error msg:${e?.message ?: "empty"}")
+// }
+// return true
+// }
+//
+// override fun onResourceReady(resource: File, model: Any, target: Target?, dataSource: DataSource, isFirstResource: Boolean): Boolean {
+// return false
+// }
+// })
+// .submit()
+// .suspendGetOrNull()
+// ?.let {
+// withContext(Dispatchers.Main){
+// onAnimStart()
+// animView.startPlay(it)
+// }
+// }
+// }
+// }
+//
+// private fun setup(view: View){
+// if(Looper.myLooper() != Looper.getMainLooper()){
+// throw Exception("must run on MAIN Thread current Thread ${Thread.currentThread().name}")
+// }
+// cancelJob()
+// extMap = mutableMapOf()
+// extMap.putAll(tempExtMap)
+// view.addOnAttachStateChangeListener(this)
+//
+// if(view is SVGAImageView){
+// if(!skipMemoryCache){
+// view.clearsAfterDetached = false
+// } else {
+// clearsAfterDetached?.let { view.clearsAfterDetached = it }
+// }
+// repeatCount?.let { view.loops = if(it <= 0) Int.MAX_VALUE else it }
+// scaleType?.let { view.scaleType = it }
+// view.callback = object: SimpleSvgaCallback(){
+// override fun onStep(frame: Int, percentage: Double) {
+// if (percentage == 1.0) {
+// view.post { onAnimComplete() }
+// }
+// }
+// }
+// }else if (view is AnimView){
+// repeatCount?.let { view.setLoop(if(it <= 0) Int.MAX_VALUE else it) }
+// scaleType?.let {
+// when (it) {
+// ImageView.ScaleType.FIT_XY -> {
+// view.setScaleType(ScaleType.FIT_XY)
+// }
+// ImageView.ScaleType.CENTER_CROP -> {
+// view.setScaleType(ScaleType.CENTER_CROP)
+// }
+// else -> {
+// view.setScaleType(ScaleType.FIT_CENTER)
+// }
+// }
+// }
+// view.setAnimListener(object : SimpleVapCallback(){
+// override fun onFailed(errorType: Int, errorMsg: String?) {
+// view.post { onAnimError("vap errorType:${errorMsg} errorMsg:${errorMsg ?: "empty"}") }
+// }
+//
+// override fun onVideoComplete() {
+// view.post { onAnimComplete() }
+// }
+// })
+// }
+// }
+//
+// fun clear(){
+// tempExtMap = mutableMapOf()
+// extMap = mutableMapOf()
+// cancelJob()
+// }
+//
+// private fun cancelJob(){
+// try {
+// job?.cancel()
+// val imgRequests = glideRequests
+// glideRequests = mutableListOf()
+// imgRequests.forEach {
+// it?.cancel(true)
+// }
+// } catch (_: Exception) { }
+// }
+//
+// private fun onAnimStart() {
+// listener?.onAnimStart()
+// }
+//
+// private fun onAnimComplete() {
+// extMap = mutableMapOf()
+// glideRequests = mutableListOf()
+// listener?.onAnimComplete()
+// }
+//
+// private fun onAnimError(msg: String) {
+// extMap = mutableMapOf()
+// cancelJob()
+// listener?.onAnimError(Exception(msg))
+// }
+//
+// override fun fetchImage(resource: Resource, result: (Bitmap?) -> Unit) {
+// val ext = extMap[resource.tag]
+// result(ext?.getBitMap())
+// }
+//
+// override fun fetchText(resource: Resource, result: (String?) -> Unit) {
+// val ext = extMap[resource.tag]
+// result(ext?.text)
+// }
+//
+// override fun releaseResource(resources: List) {
+// }
+//
+// private inner class Ext(
+// val text: String? = null,
+// val textPaint: TextPaint = defTextPaint,
+// val imgGetter: (() -> Bitmap?)? = null) {
+// fun getBitMap(): Bitmap? {
+// return try {
+// val bitmap = imgGetter?.invoke()
+// bitmap
+// } catch (t: Throwable) {
+// null
+// }
+// }
+//
+// fun isImg(): Boolean {
+// return text.isNullOrBlank()
+// }
+//
+// fun isText(): Boolean {
+// return !text.isNullOrBlank()
+// }
+// }
+//
+// override fun onViewAttachedToWindow(v: View) {
+// }
+//
+// override fun onViewDetachedFromWindow(v: View) {
+// v.removeOnAttachStateChangeListener(this)
+// cancelJob()
+// }
+// }
+//
+// interface Listener {
+// fun onAnimStart() {}
+// fun onAnimComplete()
+// fun onAnimError(e: Exception?) {
+// onAnimComplete()
+// }
+// }
+//}
\ No newline at end of file
diff --git a/library/src/module_common/java/com/chwl/library/common/glide/GlideUtils.kt b/library/src/module_common/java/com/chwl/library/common/glide/GlideUtils.kt
index f8d38edcc..c4409d8f6 100644
--- a/library/src/module_common/java/com/chwl/library/common/glide/GlideUtils.kt
+++ b/library/src/module_common/java/com/chwl/library/common/glide/GlideUtils.kt
@@ -1376,6 +1376,28 @@ class GlideUtils {
glideConfig?.downloadOnly()?.load(url)?.listener(listener)?.preload()
}
+ /**
+ * 使用Glide下载图片,返回File
+ */
+ fun downloadFromUrl2(
+ context: Context?,
+ url: String?,
+ listener: RequestListener?
+ ) {
+ if (context == null) {
+ LibLogger.error(TAG, "load context is null")
+ return
+ }
+
+ val glideConfig = getGlideConfig(context)
+ glideConfig
+ ?.asFile()
+ ?.skipMemoryCache(true)
+ ?.load(url)
+ ?.addListener(listener)
+ ?.submit()
+ }
+
/**
* 加载图片,并添加RequestListener ,无占位图 ,listener需使用addListener方法添加
*/
@@ -1422,6 +1444,17 @@ class GlideUtils {
.into(imageView)
}
}
+ //加载图片,无默认图片
+ fun loadAsBitmap(url: String?, imageView: ImageView?) {
+ if (imageView == null || TextUtils.isEmpty(url)) {
+ LibLogger.error(TAG, "load url is invalid or imageViw is null")
+ return
+ }
+ getGlideConfig(imageView.context)?.apply {
+ this.asDrawable().load(url)
+ .into(imageView)
+ }
+ }
//加载图片,无默认图片
fun loadWithError(url: String?, errorDrawable: Int, imageView: ImageView?) {
diff --git a/library/src/module_common/java/com/chwl/library/common/util/OtherExt.kt b/library/src/module_common/java/com/chwl/library/common/util/OtherExt.kt
index 8e5dc8db9..f2f90cc7e 100644
--- a/library/src/module_common/java/com/chwl/library/common/util/OtherExt.kt
+++ b/library/src/module_common/java/com/chwl/library/common/util/OtherExt.kt
@@ -8,6 +8,8 @@ import androidx.core.view.isVisible
import com.chwl.library.utils.ResUtil
import com.chwl.library.utils.SizeUtils
import com.example.lib_utils.UiUtils.isRtl
+import com.example.lib_utils.ktx.getString
+import com.hjq.toast.ToastUtils
fun View.setMargin(start:Int?=null,top:Int?=null,end:Int?=null,bottom:Int?=null,isDP:Boolean = true) {
@@ -70,6 +72,32 @@ fun String?.isVerify() : Boolean {
return this?.isBlank() == false
}
+fun String?.isSvgaUrl() : Boolean {
+ if (this.isVerify()) {
+ return this?.endsWith(".svga") == true || this?.endsWith(".SVGA") == true
+ }
+ return false
+}
+fun String?.isMp4() : Boolean {
+ if (this.isVerify()) {
+ return this?.endsWith(".mp4") == true
+ }
+ return false
+}
+
+fun String?.doToast() {
+ if (this.isVerify()) {
+ ToastUtils.show(this)
+ }
+}
+
+fun Int.doToast() {
+ val string = this.getString()
+ if (string.isVerify()) {
+ ToastUtils.show(this)
+ }
+}
+
fun List?.isVerify() : Boolean{
return this?.isEmpty() == false
}
diff --git a/libs/lib_utils/src/main/java/com/example/lib_utils/spannable/SpannableTextBuilder.kt b/libs/lib_utils/src/main/java/com/example/lib_utils/spannable/SpannableTextBuilder.kt
index 1de51695d..096a04b81 100644
--- a/libs/lib_utils/src/main/java/com/example/lib_utils/spannable/SpannableTextBuilder.kt
+++ b/libs/lib_utils/src/main/java/com/example/lib_utils/spannable/SpannableTextBuilder.kt
@@ -74,11 +74,74 @@ class SpannableTextBuilder(private val textView: TextView) {
textSize,
textStyle,
underline,
+ null,
clickListener
)
return this
}
+ fun setTextStyle(
+ text: String,
+ @ColorInt textColor: Int? = null,
+ @ColorInt backgroundColor: Int? = null,
+ textSize: Int? = null,
+ textStyle: Int? = null,
+ underline: Boolean? = null,
+ clickListener: ((String) -> Unit)? = null
+ ): SpannableTextBuilder {
+ if (text.isEmpty()) {
+ return this
+ }
+ val start = spannableBuilder.indexOf(text)
+ if (start == -1) {
+ return this
+ }
+ val end = start + text.length
+ return setTextStyle(
+ text,
+ start,
+ end,
+ textColor,
+ backgroundColor,
+ textSize,
+ textStyle,
+ underline,
+ null,
+ clickListener
+ )
+ }
+ fun setTextStyle(
+ text: String,
+ @ColorInt textColor: Int? = null,
+ @ColorInt backgroundColor: Int? = null,
+ textSize: Int? = null,
+ textStyle: Int? = null,
+ underline: Boolean? = null,
+ delLine: Boolean? = null,
+ clickListener: ((String) -> Unit)? = null
+ ): SpannableTextBuilder {
+ if (text.isEmpty()) {
+ return this
+ }
+ val start = spannableBuilder.indexOf(text)
+ if (start == -1) {
+ return this
+ }
+ val end = start + text.length
+ return setTextStyle(
+ text,
+ start,
+ end,
+ textColor,
+ backgroundColor,
+ textSize,
+ textStyle,
+ underline,
+ delLine,
+ clickListener
+ )
+ }
+
/**
* 添加图片
* @param drawable 图片
@@ -187,6 +250,7 @@ class SpannableTextBuilder(private val textView: TextView) {
textSize: Int? = null,
textStyle: Int? = null,
underline: Boolean? = null,
+ delLine: Boolean? = null,
clickListener: ((String) -> Unit)? = null
): SpannableTextBuilder {
if (start < 0 || end > spannableBuilder.length) {
@@ -236,6 +300,10 @@ class SpannableTextBuilder(private val textView: TextView) {
if (underline == true) {
spannableBuilder.setSpan(UnderlineSpan(), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
}
+ // 删除线
+ if (delLine == true) {
+ spannableBuilder.setSpan(StrikethroughSpan(), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
+ }
// 点击事件
if (clickListener != null) {
@@ -251,35 +319,7 @@ class SpannableTextBuilder(private val textView: TextView) {
return this
}
- fun setTextStyle(
- text: String,
- @ColorInt textColor: Int? = null,
- @ColorInt backgroundColor: Int? = null,
- textSize: Int? = null,
- textStyle: Int? = null,
- underline: Boolean? = null,
- clickListener: ((String) -> Unit)? = null
- ): SpannableTextBuilder {
- if (text.isEmpty()) {
- return this
- }
- val start = spannableBuilder.indexOf(text)
- if (start == -1) {
- return this
- }
- val end = start + text.length
- return setTextStyle(
- text,
- start,
- end,
- textColor,
- backgroundColor,
- textSize,
- textStyle,
- underline,
- clickListener
- )
- }
+
fun build(): SpannableStringBuilder {
return spannableBuilder
diff --git a/mode.json b/mode.json
index a364a26d5..b202e578a 100644
--- a/mode.json
+++ b/mode.json
@@ -1,98 +1,181 @@
-[
- {
- "id": 359,
- "uid": 3224,
- "nameplateId": 101,
- "isCustomWord": false,
- "word": " ",
- "remark": " ",
- "expireTime": 1731998395000,
- "createTime": 1731047995000,
- "updateTime": 1731318342000,
- "nameplateName": "schoolgirl-Advanced",
- "nameplateImage": "https://image.pekolive.com/gonghuizhangmingpaikaobei.png",
- "expireDays": 0,
- "iconPic": "https://image.pekolive.com/gonghuizhangmingpaikaobei.png",
- "fixedWord": " ",
- "nameplateType": "1"
- },
- {
- "id": 371,
- "uid": 3224,
- "nameplateId": 96,
- "isCustomWord": false,
- "remark": " ",
- "expireTime": 1731143136000,
- "createTime": 1731056736000,
- "updateTime": 1731056736000,
- "nameplateName": "king",
- "nameplateImage": "https://image.pekolive.com/zu689(11).png",
- "expireDays": 0,
- "iconPic": "https://image.pekolive.com/zu689(11).png",
- "nameplateType": "1"
- },
- {
- "id": 369,
- "uid": 3224,
- "nameplateId": 100,
- "isCustomWord": false,
- "remark": " ",
- "expireTime": 1731143131000,
- "createTime": 1731056731000,
- "updateTime": 1731056731000,
- "nameplateName": "schoolgirl-Advanced",
- "nameplateImage": "https://image.pekolive.com/huayunu:shen.png",
- "expireDays": 0,
- "iconPic": "https://image.pekolive.com/guanfangzhuli-bajisitan.png",
- "nameplateType": "1"
- },
- {
- "id": 367,
- "uid": 3224,
- "nameplateId": 93,
- "isCustomWord": false,
- "remark": " ",
- "expireTime": 1731143124000,
- "createTime": 1731056724000,
- "updateTime": 1731056724000,
- "nameplateName": "queen",
- "nameplateImage": "https://image.pekolive.com/zu688(3).png",
- "expireDays": 0,
- "iconPic": "https://image.pekolive.com/zu688(3).png",
- "nameplateType": "1"
- },
- {
- "id": 365,
- "uid": 3224,
- "nameplateId": 92,
- "isCustomWord": true,
- "word": " العناوين",
- "remark": " العناوين",
- "expireTime": 1731143086000,
- "createTime": 1731056686000,
- "updateTime": 1731056686000,
- "nameplateName": "給糖不搗蛋",
- "nameplateImage": "https://image.pekolive.com/8350643695e74ec9bb78b9944fc9e842.png",
- "expireDays": 0,
- "iconPic": "https://image.pekolive.com/zu689(5).png",
- "fixedWord": "العناوين",
- "nameplateType": "1"
- },
- {
- "id": 124,
- "uid": 3224,
- "nameplateId": 101,
- "isCustomWord": false,
- "word": " ",
- "remark": " ",
- "expireTime": 1729340700000,
- "createTime": 1728476700000,
- "updateTime": 1731318342000,
- "nameplateName": "schoolgirl-Advanced",
- "nameplateImage": "https://image.pekolive.com/gonghuizhangmingpaikaobei.png",
- "expireDays": 0,
- "iconPic": "https://image.pekolive.com/gonghuizhangmingpaikaobei.png",
- "fixedWord": " ",
- "nameplateType": "1"
- }
-]
\ No newline at end of file
+{
+ "success": true,
+ "code": 200,
+ "message": "success",
+ "data": [
+ {
+ "dressId": 195,
+ "dressType": 0,
+ "obtainWay": 1,
+ "pic": "https://image.pekolive.com/Vip5headdress.png",
+ "effectType": 2,
+ "effect": "https://image.pekolive.com/Vip5headdress.svga",
+ "name": "VIP5頭飾",
+ "used": true,
+ "expireDays": 22,
+ "hasExpired": false,
+ "expireTime": 1733976000000
+ },
+ {
+ "dressId": 196,
+ "dressType": 0,
+ "obtainWay": 1,
+ "pic": "https://image.pekolive.com/Vip6headdress.png",
+ "effectType": 2,
+ "effect": "https://image.pekolive.com/Vip6headdress.svga",
+ "name": "VIP6頭飾",
+ "used": false,
+ "expireDays": 25,
+ "hasExpired": false,
+ "expireTime": 1734235200000
+ },
+ {
+ "dressId": 193,
+ "dressType": 0,
+ "obtainWay": 1,
+ "pic": "https://image.pekolive.com/Vip3headdress.png",
+ "effectType": 2,
+ "effect": "https://image.pekolive.com/Vip3headdress.svga",
+ "name": "VIP3頭飾",
+ "used": false,
+ "expireDays": 23,
+ "hasExpired": false,
+ "expireTime": 1734062400000
+ },
+ {
+ "dressId": 26,
+ "dressType": 0,
+ "obtainWay": 1,
+ "pic": "https://image.hfighting.com/1df2071a-610d-41be-b763-8437ef9f3524",
+ "effectType": 2,
+ "effect": "https://image.hfighting.com/6d9ff134-80c1-44d5-97b0-981817e03bd4",
+ "name": "幸運星人",
+ "used": false,
+ "expireDays": 22,
+ "hasExpired": false,
+ "expireTime": 1733919509000
+ },
+ {
+ "dressId": 31,
+ "dressType": 0,
+ "obtainWay": 1,
+ "pic": "https://image.hfighting.com/2ec2f8cd-e660-4af2-bd49-b9eed8de10a2",
+ "effectType": 2,
+ "effect": "https://image.hfighting.com/34369437-e9a3-4bb8-80a2-f310bf8e90fc",
+ "name": "財氣沖天",
+ "used": false,
+ "expireDays": 13,
+ "hasExpired": false,
+ "expireTime": 1733173500000
+ },
+ {
+ "dressId": 27,
+ "dressType": 0,
+ "obtainWay": 1,
+ "pic": "https://image.hfighting.com/06fe0618-cd55-4e5e-84bf-1071f821d608",
+ "effectType": 2,
+ "effect": "https://image.hfighting.com/22f0fbb1-fdb1-46f9-b037-03f0693effeb",
+ "name": "潮舞星迎",
+ "used": false,
+ "expireDays": 13,
+ "hasExpired": false,
+ "expireTime": 1733131248000
+ },
+ {
+ "dressId": 123,
+ "dressType": 0,
+ "obtainWay": 1,
+ "pic": "http://beta.img.pekolive.com/FklHnzcmijfk_0QGRePXuzG3LSdN?imageslim",
+ "effectType": 2,
+ "effect": "http://beta.img.pekolive.com/FmDgjyKd_p0SvpKmC5v0rwhszdH9?imageslim",
+ "name": "花语小兔",
+ "used": false,
+ "expireDays": 9,
+ "hasExpired": false,
+ "expireTime": 1732780728000
+ },
+ {
+ "dressId": 110,
+ "dressType": 0,
+ "obtainWay": 1,
+ "pic": "http://beta.img.pekolive.com/FrTtFcnSI88bITGonp5PJjdbGLLR?imageslim",
+ "effectType": 2,
+ "effect": "http://beta.img.pekolive.com/FrTtFcnSI88bITGonp5PJjdbGLLR?imageslim",
+ "name": "豪氣季軍",
+ "used": false,
+ "expireDays": 8,
+ "hasExpired": false,
+ "expireTime": 1732760886000
+ },
+ {
+ "dressId": 30,
+ "dressType": 0,
+ "obtainWay": 1,
+ "pic": "https://image.hfighting.com/0fcea959-e82a-410e-a3f5-52f751a6c327",
+ "effectType": 2,
+ "effect": "https://image.hfighting.com/efacf269-c628-4940-984f-b817aabf2127",
+ "name": "拉丁之神",
+ "used": false,
+ "expireDays": 6,
+ "hasExpired": false,
+ "expireTime": 1732526621000
+ },
+ {
+ "dressId": 28,
+ "dressType": 0,
+ "obtainWay": 1,
+ "pic": "https://image.hfighting.com/4dd02f23-e30f-4df7-9326-53a1f4ae8ebf",
+ "effectType": 2,
+ "effect": "https://image.hfighting.com/c17f08d6-1854-4d03-a760-e02ad5fdf081",
+ "name": "月魔法帽",
+ "used": false,
+ "expireDays": 6,
+ "hasExpired": false,
+ "expireTime": 1732526452000
+ },
+ {
+ "dressId": 42,
+ "dressType": 0,
+ "obtainWay": 1,
+ "pic": "http://beta.img.pekolive.com/Fq_EzPCxN99nV84CgO3c3z242pEh?imageslim",
+ "effectType": 2,
+ "effect": "http://beta.img.pekolive.com/Fq_EzPCxN99nV84CgO3c3z242pEh?imageslim",
+ "name": "海浪",
+ "used": false,
+ "expireDays": 2,
+ "hasExpired": false,
+ "expireTime": 1732175930000
+ },
+ {
+ "dressId": 29,
+ "dressType": 0,
+ "obtainWay": 1,
+ "pic": "https://image.hfighting.com/a51c4b19-6862-41fa-83cb-2475db2320da",
+ "effectType": 2,
+ "effect": "https://image.hfighting.com/5df51843-1c4c-40c1-b1dd-5420ce093de2",
+ "name": "神囚魔法",
+ "used": false,
+ "expireDays": 1,
+ "hasExpired": false,
+ "expireTime": 1732097432000
+ },
+ {
+ "dressId": 102,
+ "dressType": 0,
+ "obtainWay": 1,
+ "pic": "http://beta.img.pekolive.com/FrQQrQ0yEhTCLxyKHygT76kZLHoy?imageslim",
+ "effectType": 2,
+ "effect": "http://beta.img.pekolive.com/FqJrMr8YmRr6WBR0FOMaYL05HPxy?imageslim",
+ "name": "星河白羽",
+ "used": false,
+ "expireDays": 0,
+ "hasExpired": true,
+ "expireTime": 1731664948000
+ },
+ {
+ "dressId": 44,
+ "dressType": 0,
+ "obtainWay": 1,
+ "pic": "https://image.hfighting.com/bb55be24-3418-4f03-bf46-1bb491b95ba2",
+ "effectType": 2,
+ "effect": "https:/
diff --git a/nim_uikit/src/com/netease/nim/uikit/common/ui/imageview/CircleImageView.java b/nim_uikit/src/com/netease/nim/uikit/common/ui/imageview/CircleImageView.java
index 547115658..367df10ac 100644
--- a/nim_uikit/src/com/netease/nim/uikit/common/ui/imageview/CircleImageView.java
+++ b/nim_uikit/src/com/netease/nim/uikit/common/ui/imageview/CircleImageView.java
@@ -31,11 +31,12 @@ import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.util.AttributeSet;
-import android.widget.ImageView;
+
+import androidx.appcompat.widget.AppCompatImageView;
import com.netease.nim.uikit.R;
-public class CircleImageView extends ImageView {
+public class CircleImageView extends AppCompatImageView {
private static final ScaleType SCALE_TYPE = ScaleType.CENTER_CROP;