diff --git a/FlycoTabLayoutZ_Lib/.gitignore b/FlycoTabLayoutZ_Lib/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/FlycoTabLayoutZ_Lib/.gitignore @@ -0,0 +1 @@ +/build diff --git a/FlycoTabLayoutZ_Lib/build.gradle b/FlycoTabLayoutZ_Lib/build.gradle new file mode 100644 index 0000000..e21b40c --- /dev/null +++ b/FlycoTabLayoutZ_Lib/build.gradle @@ -0,0 +1,38 @@ +apply plugin: 'com.android.library' +//apply plugin: 'com.novoda.bintray-release' + +version = "1.3.3" +android { + compileSdkVersion 28 + buildToolsVersion "28.0.3" + + defaultConfig { + minSdkVersion 17 + targetSdkVersion 28 + versionCode 5 + versionName version + } + buildTypes { + U807Debug {} + U807Release {} + iPlay50SEDebug {} + iPlay50SERelease {} + debug {} + release {} + } +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation 'androidx.legacy:legacy-support-v4:1.0.0' +} + +//// jcenter发布的信息 +//publish { +// userOrg = 'lizp' // 创建repo的位置 +// groupId = 'com.lzp' // 引用的分组名称 +// artifactId = 'FlycoTabLayoutZ'//项目名称 +// publishVersion = version//版本号 +// desc = '在FlycoTabLayout的基础上,扩展出SlidingScaleTabLayout,实现滑动可以改变tab字体的大小的切换效果' +// website = 'https://github.com/li504799868/FlycoTabLayoutZ' +//} \ No newline at end of file diff --git a/FlycoTabLayoutZ_Lib/proguard-rules.pro b/FlycoTabLayoutZ_Lib/proguard-rules.pro new file mode 100644 index 0000000..48100e3 --- /dev/null +++ b/FlycoTabLayoutZ_Lib/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /Users/lihui/work/AndroidStudio/sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/FlycoTabLayoutZ_Lib/src/main/AndroidManifest.xml b/FlycoTabLayoutZ_Lib/src/main/AndroidManifest.xml new file mode 100644 index 0000000..65a3365 --- /dev/null +++ b/FlycoTabLayoutZ_Lib/src/main/AndroidManifest.xml @@ -0,0 +1,3 @@ + + diff --git a/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/CommonTabLayout.java b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/CommonTabLayout.java new file mode 100644 index 0000000..58f5e0b --- /dev/null +++ b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/CommonTabLayout.java @@ -0,0 +1,985 @@ +package com.flyco.tablayout; + +import android.animation.TypeEvaluator; +import android.animation.ValueAnimator; +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.Rect; +import android.graphics.drawable.GradientDrawable; +import android.os.Bundle; +import android.os.Parcelable; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; +import android.util.AttributeSet; +import android.util.SparseArray; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.OvershootInterpolator; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.flyco.tablayout.listener.CustomTabEntity; +import com.flyco.tablayout.listener.OnTabSelectListener; +import com.flyco.tablayout.utils.FragmentChangeManager; +import com.flyco.tablayout.utils.UnreadMsgUtils; +import com.flyco.tablayout.widget.MsgView; + +import java.util.ArrayList; + +/** + * 没有继承HorizontalScrollView不能滑动,对于ViewPager无依赖 + */ +public class CommonTabLayout extends FrameLayout implements ValueAnimator.AnimatorUpdateListener { + private Context mContext; + private ArrayList mTabEntitys = new ArrayList<>(); + private LinearLayout mTabsContainer; + private int mCurrentTab; + private int mLastTab; + private int mTabCount; + /** + * 用于绘制显示器 + */ + private Rect mIndicatorRect = new Rect(); + private GradientDrawable mIndicatorDrawable = new GradientDrawable(); + + private Paint mRectPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private Paint mDividerPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private Paint mTrianglePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private Path mTrianglePath = new Path(); + private static final int STYLE_NORMAL = 0; + private static final int STYLE_TRIANGLE = 1; + private static final int STYLE_BLOCK = 2; + private int mIndicatorStyle = STYLE_NORMAL; + + private float mTabPadding; + private boolean mTabSpaceEqual; + private float mTabWidth; + + /** + * indicator + */ + private int mIndicatorColor; + private float mIndicatorHeight; + private float mIndicatorWidth; + private float mIndicatorCornerRadius; + private float mIndicatorMarginLeft; + private float mIndicatorMarginTop; + private float mIndicatorMarginRight; + private float mIndicatorMarginBottom; + private long mIndicatorAnimDuration; + private boolean mIndicatorAnimEnable; + private boolean mIndicatorBounceEnable; + private int mIndicatorGravity; + + /** + * underline + */ + private int mUnderlineColor; + private float mUnderlineHeight; + private int mUnderlineGravity; + + /** + * divider + */ + private int mDividerColor; + private float mDividerWidth; + private float mDividerPadding; + + /** + * title + */ + private static final int TEXT_BOLD_NONE = 0; + private static final int TEXT_BOLD_WHEN_SELECT = 1; + private static final int TEXT_BOLD_BOTH = 2; + private float mTextsize; + private int mTextSelectColor; + private int mTextUnselectColor; + private int mTextBold; + private boolean mTextAllCaps; + + /** + * icon + */ + private boolean mIconVisible; + private int mIconGravity; + private float mIconWidth; + private float mIconHeight; + private float mIconMargin; + + private int mHeight; + + /** + * anim + */ + private ValueAnimator mValueAnimator; + private OvershootInterpolator mInterpolator = new OvershootInterpolator(1.5f); + + private FragmentChangeManager mFragmentChangeManager; + + public CommonTabLayout(Context context) { + this(context, null, 0); + } + + public CommonTabLayout(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public CommonTabLayout(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + setWillNotDraw(false);//重写onDraw方法,需要调用这个方法来清除flag + setClipChildren(false); + setClipToPadding(false); + + this.mContext = context; + mTabsContainer = new LinearLayout(context); + addView(mTabsContainer); + + obtainAttributes(context, attrs); + + //get layout_height + String height = attrs.getAttributeValue("http://schemas.android.com/apk/res/android", "layout_height"); + + //create ViewPager + if (height.equals(ViewGroup.LayoutParams.MATCH_PARENT + "")) { + } else if (height.equals(ViewGroup.LayoutParams.WRAP_CONTENT + "")) { + } else { + int[] systemAttrs = {android.R.attr.layout_height}; + TypedArray a = context.obtainStyledAttributes(attrs, systemAttrs); + mHeight = a.getDimensionPixelSize(0, ViewGroup.LayoutParams.WRAP_CONTENT); + a.recycle(); + } + + mValueAnimator = ValueAnimator.ofObject(new PointEvaluator(), mLastP, mCurrentP); + mValueAnimator.addUpdateListener(this); + } + + private void obtainAttributes(Context context, AttributeSet attrs) { + TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CommonTabLayout); + + mIndicatorStyle = ta.getInt(R.styleable.CommonTabLayout_tl_indicator_style, 0); + mIndicatorColor = ta.getColor(R.styleable.CommonTabLayout_tl_indicator_color, Color.parseColor(mIndicatorStyle == STYLE_BLOCK ? "#4B6A87" : "#ffffff")); + mIndicatorHeight = ta.getDimension(R.styleable.CommonTabLayout_tl_indicator_height, + dp2px(mIndicatorStyle == STYLE_TRIANGLE ? 4 : (mIndicatorStyle == STYLE_BLOCK ? -1 : 2))); + mIndicatorWidth = ta.getDimension(R.styleable.CommonTabLayout_tl_indicator_width, dp2px(mIndicatorStyle == STYLE_TRIANGLE ? 10 : -1)); + mIndicatorCornerRadius = ta.getDimension(R.styleable.CommonTabLayout_tl_indicator_corner_radius, dp2px(mIndicatorStyle == STYLE_BLOCK ? -1 : 0)); + mIndicatorMarginLeft = ta.getDimension(R.styleable.CommonTabLayout_tl_indicator_margin_left, dp2px(0)); + mIndicatorMarginTop = ta.getDimension(R.styleable.CommonTabLayout_tl_indicator_margin_top, dp2px(mIndicatorStyle == STYLE_BLOCK ? 7 : 0)); + mIndicatorMarginRight = ta.getDimension(R.styleable.CommonTabLayout_tl_indicator_margin_right, dp2px(0)); + mIndicatorMarginBottom = ta.getDimension(R.styleable.CommonTabLayout_tl_indicator_margin_bottom, dp2px(mIndicatorStyle == STYLE_BLOCK ? 7 : 0)); + mIndicatorAnimEnable = ta.getBoolean(R.styleable.CommonTabLayout_tl_indicator_anim_enable, true); + mIndicatorBounceEnable = ta.getBoolean(R.styleable.CommonTabLayout_tl_indicator_bounce_enable, true); + mIndicatorAnimDuration = ta.getInt(R.styleable.CommonTabLayout_tl_indicator_anim_duration, -1); + mIndicatorGravity = ta.getInt(R.styleable.CommonTabLayout_tl_indicator_gravity, Gravity.BOTTOM); + + mUnderlineColor = ta.getColor(R.styleable.CommonTabLayout_tl_underline_color, Color.parseColor("#ffffff")); + mUnderlineHeight = ta.getDimension(R.styleable.CommonTabLayout_tl_underline_height, dp2px(0)); + mUnderlineGravity = ta.getInt(R.styleable.CommonTabLayout_tl_underline_gravity, Gravity.BOTTOM); + + mDividerColor = ta.getColor(R.styleable.CommonTabLayout_tl_divider_color, Color.parseColor("#ffffff")); + mDividerWidth = ta.getDimension(R.styleable.CommonTabLayout_tl_divider_width, dp2px(0)); + mDividerPadding = ta.getDimension(R.styleable.CommonTabLayout_tl_divider_padding, dp2px(12)); + + mTextsize = ta.getDimension(R.styleable.CommonTabLayout_tl_textSize, sp2px(13f)); + mTextSelectColor = ta.getColor(R.styleable.CommonTabLayout_tl_textSelectColor, Color.parseColor("#ffffff")); + mTextUnselectColor = ta.getColor(R.styleable.CommonTabLayout_tl_textUnSelectColor, Color.parseColor("#AAffffff")); + mTextBold = ta.getInt(R.styleable.CommonTabLayout_tl_textBold, TEXT_BOLD_NONE); + mTextAllCaps = ta.getBoolean(R.styleable.CommonTabLayout_tl_textAllCaps, false); + + mIconVisible = ta.getBoolean(R.styleable.CommonTabLayout_tl_iconVisible, true); + mIconGravity = ta.getInt(R.styleable.CommonTabLayout_tl_iconGravity, Gravity.TOP); + mIconWidth = ta.getDimension(R.styleable.CommonTabLayout_tl_iconWidth, dp2px(0)); + mIconHeight = ta.getDimension(R.styleable.CommonTabLayout_tl_iconHeight, dp2px(0)); + mIconMargin = ta.getDimension(R.styleable.CommonTabLayout_tl_iconMargin, dp2px(2.5f)); + + mTabSpaceEqual = ta.getBoolean(R.styleable.CommonTabLayout_tl_tab_space_equal, true); + mTabWidth = ta.getDimension(R.styleable.CommonTabLayout_tl_tab_width, dp2px(-1)); + mTabPadding = ta.getDimension(R.styleable.CommonTabLayout_tl_tab_padding, mTabSpaceEqual || mTabWidth > 0 ? dp2px(0) : dp2px(10)); + + ta.recycle(); + } + + public void setTabData(ArrayList tabEntitys) { + if (tabEntitys == null || tabEntitys.size() == 0) { + throw new IllegalStateException("TabEntitys can not be NULL or EMPTY !"); + } + + this.mTabEntitys.clear(); + this.mTabEntitys.addAll(tabEntitys); + + notifyDataSetChanged(); + } + + /** + * 关联数据支持同时切换fragments + */ + public void setTabData(ArrayList tabEntitys, FragmentActivity fa, int containerViewId, ArrayList fragments) { + mFragmentChangeManager = new FragmentChangeManager(fa.getSupportFragmentManager(), containerViewId, fragments); + setTabData(tabEntitys); + } + + /** + * 更新数据 + */ + public void notifyDataSetChanged() { + mTabsContainer.removeAllViews(); + this.mTabCount = mTabEntitys.size(); + View tabView; + for (int i = 0; i < mTabCount; i++) { + if (mIconGravity == Gravity.LEFT) { + tabView = View.inflate(mContext, R.layout.layout_tab_left, null); + } else if (mIconGravity == Gravity.RIGHT) { + tabView = View.inflate(mContext, R.layout.layout_tab_right, null); + } else if (mIconGravity == Gravity.BOTTOM) { + tabView = View.inflate(mContext, R.layout.layout_tab_bottom, null); + } else { + tabView = View.inflate(mContext, R.layout.layout_tab_top, null); + } + + tabView.setTag(i); + addTab(i, tabView); + } + + updateTabStyles(); + } + + /** + * 创建并添加tab + */ + private void addTab(final int position, View tabView) { + TextView tv_tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title); + tv_tab_title.setText(mTabEntitys.get(position).getTabTitle()); + ImageView iv_tab_icon = (ImageView) tabView.findViewById(R.id.iv_tab_icon); + iv_tab_icon.setImageResource(mTabEntitys.get(position).getTabUnselectedIcon()); + + tabView.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + int position = (Integer) v.getTag(); + if (mCurrentTab != position) { + setCurrentTab(position); + if (mListener != null) { + mListener.onTabSelect(position); + } + } else { + if (mListener != null) { + mListener.onTabReselect(position); + } + } + } + }); + + /** 每一个Tab的布局参数 */ + LinearLayout.LayoutParams lp_tab = mTabSpaceEqual ? + new LinearLayout.LayoutParams(0, LayoutParams.MATCH_PARENT, 1.0f) : + new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT); + if (mTabWidth > 0) { + lp_tab = new LinearLayout.LayoutParams((int) mTabWidth, LayoutParams.MATCH_PARENT); + } + mTabsContainer.addView(tabView, position, lp_tab); + } + + private void updateTabStyles() { + for (int i = 0; i < mTabCount; i++) { + View tabView = mTabsContainer.getChildAt(i); + tabView.setPadding((int) mTabPadding, 0, (int) mTabPadding, 0); + TextView tv_tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title); + tv_tab_title.setTextColor(i == mCurrentTab ? mTextSelectColor : mTextUnselectColor); + tv_tab_title.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextsize); +// tv_tab_title.setPadding((int) mTabPadding, 0, (int) mTabPadding, 0); + if (mTextAllCaps) { + tv_tab_title.setText(tv_tab_title.getText().toString().toUpperCase()); + } + + if (mTextBold == TEXT_BOLD_BOTH) { + tv_tab_title.getPaint().setFakeBoldText(true); + } + // 被选中设置为粗体 + else if (mTextBold == TEXT_BOLD_WHEN_SELECT && i == mCurrentTab) { + tv_tab_title.getPaint().setFakeBoldText(true); + } else if (mTextBold == TEXT_BOLD_NONE) { + tv_tab_title.getPaint().setFakeBoldText(false); + } + + ImageView iv_tab_icon = (ImageView) tabView.findViewById(R.id.iv_tab_icon); + if (mIconVisible) { + iv_tab_icon.setVisibility(View.VISIBLE); + CustomTabEntity tabEntity = mTabEntitys.get(i); + iv_tab_icon.setImageResource(i == mCurrentTab ? tabEntity.getTabSelectedIcon() : tabEntity.getTabUnselectedIcon()); + LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( + mIconWidth <= 0 ? LinearLayout.LayoutParams.WRAP_CONTENT : (int) mIconWidth, + mIconHeight <= 0 ? LinearLayout.LayoutParams.WRAP_CONTENT : (int) mIconHeight); + if (mIconGravity == Gravity.LEFT) { + lp.rightMargin = (int) mIconMargin; + } else if (mIconGravity == Gravity.RIGHT) { + lp.leftMargin = (int) mIconMargin; + } else if (mIconGravity == Gravity.BOTTOM) { + lp.topMargin = (int) mIconMargin; + } else { + lp.bottomMargin = (int) mIconMargin; + } + + iv_tab_icon.setLayoutParams(lp); + } else { + iv_tab_icon.setVisibility(View.GONE); + } + } + } + + private void updateTabSelection(int position) { + for (int i = 0; i < mTabCount; ++i) { + View tabView = mTabsContainer.getChildAt(i); + final boolean isSelect = i == position; + TextView tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title); + tab_title.setTextColor(isSelect ? mTextSelectColor : mTextUnselectColor); + ImageView iv_tab_icon = (ImageView) tabView.findViewById(R.id.iv_tab_icon); + CustomTabEntity tabEntity = mTabEntitys.get(i); + iv_tab_icon.setImageResource(isSelect ? tabEntity.getTabSelectedIcon() : tabEntity.getTabUnselectedIcon()); + if (mTextBold == TEXT_BOLD_WHEN_SELECT) { + tab_title.getPaint().setFakeBoldText(isSelect); + } + } + } + + private void calcOffset() { + final View currentTabView = mTabsContainer.getChildAt(this.mCurrentTab); + mCurrentP.left = currentTabView.getLeft(); + mCurrentP.right = currentTabView.getRight(); + + final View lastTabView = mTabsContainer.getChildAt(this.mLastTab); + mLastP.left = lastTabView.getLeft(); + mLastP.right = lastTabView.getRight(); + +// Log.d("AAA", "mLastP--->" + mLastP.left + "&" + mLastP.right); +// Log.d("AAA", "mCurrentP--->" + mCurrentP.left + "&" + mCurrentP.right); + if (mLastP.left == mCurrentP.left && mLastP.right == mCurrentP.right) { + invalidate(); + } else { + mValueAnimator.setObjectValues(mLastP, mCurrentP); + if (mIndicatorBounceEnable) { + mValueAnimator.setInterpolator(mInterpolator); + } + + if (mIndicatorAnimDuration < 0) { + mIndicatorAnimDuration = mIndicatorBounceEnable ? 500 : 250; + } + mValueAnimator.setDuration(mIndicatorAnimDuration); + mValueAnimator.start(); + } + } + + private void calcIndicatorRect() { + View currentTabView = mTabsContainer.getChildAt(this.mCurrentTab); + float left = currentTabView.getLeft(); + float right = currentTabView.getRight(); + + mIndicatorRect.left = (int) left; + mIndicatorRect.right = (int) right; + + if (mIndicatorWidth < 0) { //indicatorWidth小于0时,原jpardogo's PagerSlidingTabStrip + + } else {//indicatorWidth大于0时,圆角矩形以及三角形 + float indicatorLeft = currentTabView.getLeft() + (currentTabView.getWidth() - mIndicatorWidth) / 2; + + mIndicatorRect.left = (int) indicatorLeft; + mIndicatorRect.right = (int) (mIndicatorRect.left + mIndicatorWidth); + } + } + + @Override + public void onAnimationUpdate(ValueAnimator animation) { + View currentTabView = mTabsContainer.getChildAt(this.mCurrentTab); + IndicatorPoint p = (IndicatorPoint) animation.getAnimatedValue(); + mIndicatorRect.left = (int) p.left; + mIndicatorRect.right = (int) p.right; + + if (mIndicatorWidth < 0) { //indicatorWidth小于0时,原jpardogo's PagerSlidingTabStrip + + } else {//indicatorWidth大于0时,圆角矩形以及三角形 + float indicatorLeft = p.left + (currentTabView.getWidth() - mIndicatorWidth) / 2; + + mIndicatorRect.left = (int) indicatorLeft; + mIndicatorRect.right = (int) (mIndicatorRect.left + mIndicatorWidth); + } + invalidate(); + } + + private boolean mIsFirstDraw = true; + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + if (isInEditMode() || mTabCount <= 0) { + return; + } + + int height = getHeight(); + int paddingLeft = getPaddingLeft(); + // draw divider + if (mDividerWidth > 0) { + mDividerPaint.setStrokeWidth(mDividerWidth); + mDividerPaint.setColor(mDividerColor); + for (int i = 0; i < mTabCount - 1; i++) { + View tab = mTabsContainer.getChildAt(i); + canvas.drawLine(paddingLeft + tab.getRight(), mDividerPadding, paddingLeft + tab.getRight(), height - mDividerPadding, mDividerPaint); + } + } + + // draw underline + if (mUnderlineHeight > 0) { + mRectPaint.setColor(mUnderlineColor); + if (mUnderlineGravity == Gravity.BOTTOM) { + canvas.drawRect(paddingLeft, height - mUnderlineHeight, mTabsContainer.getWidth() + paddingLeft, height, mRectPaint); + } else { + canvas.drawRect(paddingLeft, 0, mTabsContainer.getWidth() + paddingLeft, mUnderlineHeight, mRectPaint); + } + } + + //draw indicator line + if (mIndicatorAnimEnable) { + if (mIsFirstDraw) { + mIsFirstDraw = false; + calcIndicatorRect(); + } + } else { + calcIndicatorRect(); + } + + + if (mIndicatorStyle == STYLE_TRIANGLE) { + if (mIndicatorHeight > 0) { + mTrianglePaint.setColor(mIndicatorColor); + mTrianglePath.reset(); + mTrianglePath.moveTo(paddingLeft + mIndicatorRect.left, height); + mTrianglePath.lineTo(paddingLeft + mIndicatorRect.left / 2 + mIndicatorRect.right / 2, height - mIndicatorHeight); + mTrianglePath.lineTo(paddingLeft + mIndicatorRect.right, height); + mTrianglePath.close(); + canvas.drawPath(mTrianglePath, mTrianglePaint); + } + } else if (mIndicatorStyle == STYLE_BLOCK) { + if (mIndicatorHeight < 0) { + mIndicatorHeight = height - mIndicatorMarginTop - mIndicatorMarginBottom; + } else { + + } + + if (mIndicatorHeight > 0) { + if (mIndicatorCornerRadius < 0 || mIndicatorCornerRadius > mIndicatorHeight / 2) { + mIndicatorCornerRadius = mIndicatorHeight / 2; + } + + mIndicatorDrawable.setColor(mIndicatorColor); + mIndicatorDrawable.setBounds(paddingLeft + (int) mIndicatorMarginLeft + mIndicatorRect.left, + (int) mIndicatorMarginTop, (int) (paddingLeft + mIndicatorRect.right - mIndicatorMarginRight), + (int) (mIndicatorMarginTop + mIndicatorHeight)); + mIndicatorDrawable.setCornerRadius(mIndicatorCornerRadius); + mIndicatorDrawable.draw(canvas); + } + } else { + /* mRectPaint.setColor(mIndicatorColor); + calcIndicatorRect(); + canvas.drawRect(getPaddingLeft() + mIndicatorRect.left, getHeight() - mIndicatorHeight, + mIndicatorRect.right + getPaddingLeft(), getHeight(), mRectPaint);*/ + + if (mIndicatorHeight > 0) { + mIndicatorDrawable.setColor(mIndicatorColor); + if (mIndicatorGravity == Gravity.BOTTOM) { + mIndicatorDrawable.setBounds(paddingLeft + (int) mIndicatorMarginLeft + mIndicatorRect.left, + height - (int) mIndicatorHeight - (int) mIndicatorMarginBottom, + paddingLeft + mIndicatorRect.right - (int) mIndicatorMarginRight, + height - (int) mIndicatorMarginBottom); + } else { + mIndicatorDrawable.setBounds(paddingLeft + (int) mIndicatorMarginLeft + mIndicatorRect.left, + (int) mIndicatorMarginTop, + paddingLeft + mIndicatorRect.right - (int) mIndicatorMarginRight, + (int) mIndicatorHeight + (int) mIndicatorMarginTop); + } + mIndicatorDrawable.setCornerRadius(mIndicatorCornerRadius); + mIndicatorDrawable.draw(canvas); + } + } + } + + //setter and getter + public void setCurrentTab(int currentTab) { + mLastTab = this.mCurrentTab; + this.mCurrentTab = currentTab; + updateTabSelection(currentTab); + if (mFragmentChangeManager != null) { + mFragmentChangeManager.setFragments(currentTab); + } + if (mIndicatorAnimEnable) { + calcOffset(); + } else { + invalidate(); + } + } + + public void setIndicatorStyle(int indicatorStyle) { + this.mIndicatorStyle = indicatorStyle; + invalidate(); + } + + public void setTabPadding(float tabPadding) { + this.mTabPadding = dp2px(tabPadding); + updateTabStyles(); + } + + public void setTabSpaceEqual(boolean tabSpaceEqual) { + this.mTabSpaceEqual = tabSpaceEqual; + updateTabStyles(); + } + + public void setTabWidth(float tabWidth) { + this.mTabWidth = dp2px(tabWidth); + updateTabStyles(); + } + + public void setIndicatorColor(int indicatorColor) { + this.mIndicatorColor = indicatorColor; + invalidate(); + } + + public void setIndicatorHeight(float indicatorHeight) { + this.mIndicatorHeight = dp2px(indicatorHeight); + invalidate(); + } + + public void setIndicatorWidth(float indicatorWidth) { + this.mIndicatorWidth = dp2px(indicatorWidth); + invalidate(); + } + + public void setIndicatorCornerRadius(float indicatorCornerRadius) { + this.mIndicatorCornerRadius = dp2px(indicatorCornerRadius); + invalidate(); + } + + public void setIndicatorGravity(int indicatorGravity) { + this.mIndicatorGravity = indicatorGravity; + invalidate(); + } + + public void setIndicatorMargin(float indicatorMarginLeft, float indicatorMarginTop, + float indicatorMarginRight, float indicatorMarginBottom) { + this.mIndicatorMarginLeft = dp2px(indicatorMarginLeft); + this.mIndicatorMarginTop = dp2px(indicatorMarginTop); + this.mIndicatorMarginRight = dp2px(indicatorMarginRight); + this.mIndicatorMarginBottom = dp2px(indicatorMarginBottom); + invalidate(); + } + + public void setIndicatorAnimDuration(long indicatorAnimDuration) { + this.mIndicatorAnimDuration = indicatorAnimDuration; + } + + public void setIndicatorAnimEnable(boolean indicatorAnimEnable) { + this.mIndicatorAnimEnable = indicatorAnimEnable; + } + + public void setIndicatorBounceEnable(boolean indicatorBounceEnable) { + this.mIndicatorBounceEnable = indicatorBounceEnable; + } + + public void setUnderlineColor(int underlineColor) { + this.mUnderlineColor = underlineColor; + invalidate(); + } + + public void setUnderlineHeight(float underlineHeight) { + this.mUnderlineHeight = dp2px(underlineHeight); + invalidate(); + } + + public void setUnderlineGravity(int underlineGravity) { + this.mUnderlineGravity = underlineGravity; + invalidate(); + } + + public void setDividerColor(int dividerColor) { + this.mDividerColor = dividerColor; + invalidate(); + } + + public void setDividerWidth(float dividerWidth) { + this.mDividerWidth = dp2px(dividerWidth); + invalidate(); + } + + public void setDividerPadding(float dividerPadding) { + this.mDividerPadding = dp2px(dividerPadding); + invalidate(); + } + + public void setTextsize(float textsize) { + this.mTextsize = sp2px(textsize); + updateTabStyles(); + } + + public void setTextSelectColor(int textSelectColor) { + this.mTextSelectColor = textSelectColor; + updateTabStyles(); + } + + public void setTextUnselectColor(int textUnselectColor) { + this.mTextUnselectColor = textUnselectColor; + updateTabStyles(); + } + + public void setTextBold(int textBold) { + this.mTextBold = textBold; + updateTabStyles(); + } + + public void setIconVisible(boolean iconVisible) { + this.mIconVisible = iconVisible; + updateTabStyles(); + } + + public void setIconGravity(int iconGravity) { + this.mIconGravity = iconGravity; + notifyDataSetChanged(); + } + + public void setIconWidth(float iconWidth) { + this.mIconWidth = dp2px(iconWidth); + updateTabStyles(); + } + + public void setIconHeight(float iconHeight) { + this.mIconHeight = dp2px(iconHeight); + updateTabStyles(); + } + + public void setIconMargin(float iconMargin) { + this.mIconMargin = dp2px(iconMargin); + updateTabStyles(); + } + + public void setTextAllCaps(boolean textAllCaps) { + this.mTextAllCaps = textAllCaps; + updateTabStyles(); + } + + + public int getTabCount() { + return mTabCount; + } + + public int getCurrentTab() { + return mCurrentTab; + } + + public int getIndicatorStyle() { + return mIndicatorStyle; + } + + public float getTabPadding() { + return mTabPadding; + } + + public boolean isTabSpaceEqual() { + return mTabSpaceEqual; + } + + public float getTabWidth() { + return mTabWidth; + } + + public int getIndicatorColor() { + return mIndicatorColor; + } + + public float getIndicatorHeight() { + return mIndicatorHeight; + } + + public float getIndicatorWidth() { + return mIndicatorWidth; + } + + public float getIndicatorCornerRadius() { + return mIndicatorCornerRadius; + } + + public float getIndicatorMarginLeft() { + return mIndicatorMarginLeft; + } + + public float getIndicatorMarginTop() { + return mIndicatorMarginTop; + } + + public float getIndicatorMarginRight() { + return mIndicatorMarginRight; + } + + public float getIndicatorMarginBottom() { + return mIndicatorMarginBottom; + } + + public long getIndicatorAnimDuration() { + return mIndicatorAnimDuration; + } + + public boolean isIndicatorAnimEnable() { + return mIndicatorAnimEnable; + } + + public boolean isIndicatorBounceEnable() { + return mIndicatorBounceEnable; + } + + public int getUnderlineColor() { + return mUnderlineColor; + } + + public float getUnderlineHeight() { + return mUnderlineHeight; + } + + public int getDividerColor() { + return mDividerColor; + } + + public float getDividerWidth() { + return mDividerWidth; + } + + public float getDividerPadding() { + return mDividerPadding; + } + + public float getTextsize() { + return mTextsize; + } + + public int getTextSelectColor() { + return mTextSelectColor; + } + + public int getTextUnselectColor() { + return mTextUnselectColor; + } + + public int getTextBold() { + return mTextBold; + } + + public boolean isTextAllCaps() { + return mTextAllCaps; + } + + public int getIconGravity() { + return mIconGravity; + } + + public float getIconWidth() { + return mIconWidth; + } + + public float getIconHeight() { + return mIconHeight; + } + + public float getIconMargin() { + return mIconMargin; + } + + public boolean isIconVisible() { + return mIconVisible; + } + + + public ImageView getIconView(int tab) { + View tabView = mTabsContainer.getChildAt(tab); + ImageView iv_tab_icon = (ImageView) tabView.findViewById(R.id.iv_tab_icon); + return iv_tab_icon; + } + + public TextView getTitleView(int tab) { + View tabView = mTabsContainer.getChildAt(tab); + TextView tv_tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title); + return tv_tab_title; + } + + //setter and getter + + // show MsgTipView + private Paint mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private SparseArray mInitSetMap = new SparseArray<>(); + + /** + * 显示未读消息 + * + * @param position 显示tab位置 + * @param num num小于等于0显示红点,num大于0显示数字 + */ + public void showMsg(int position, int num) { + if (position >= mTabCount) { + position = mTabCount - 1; + } + + View tabView = mTabsContainer.getChildAt(position); + MsgView tipView = (MsgView) tabView.findViewById(R.id.rtv_msg_tip); + if (tipView != null) { + UnreadMsgUtils.show(tipView, num); + + if (mInitSetMap.get(position) != null && mInitSetMap.get(position)) { + return; + } + + if (!mIconVisible) { + setMsgMargin(position, 2, 2); + } else { + setMsgMargin(position, 0, + mIconGravity == Gravity.LEFT || mIconGravity == Gravity.RIGHT ? 4 : 0); + } + + mInitSetMap.put(position, true); + } + } + + /** + * 显示未读红点 + * + * @param position 显示tab位置 + */ + public void showDot(int position) { + if (position >= mTabCount) { + position = mTabCount - 1; + } + showMsg(position, 0); + } + + public void hideMsg(int position) { + if (position >= mTabCount) { + position = mTabCount - 1; + } + + View tabView = mTabsContainer.getChildAt(position); + MsgView tipView = (MsgView) tabView.findViewById(R.id.rtv_msg_tip); + if (tipView != null) { + tipView.setVisibility(View.GONE); + } + } + + /** + * 设置提示红点偏移,注意 + * 1.控件为固定高度:参照点为tab内容的右上角 + * 2.控件高度不固定(WRAP_CONTENT):参照点为tab内容的右上角,此时高度已是红点的最高显示范围,所以这时bottomPadding其实就是topPadding + */ + public void setMsgMargin(int position, float leftPadding, float bottomPadding) { + if (position >= mTabCount) { + position = mTabCount - 1; + } + View tabView = mTabsContainer.getChildAt(position); + MsgView tipView = (MsgView) tabView.findViewById(R.id.rtv_msg_tip); + if (tipView != null) { + TextView tv_tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title); + mTextPaint.setTextSize(mTextsize); + float textWidth = mTextPaint.measureText(tv_tab_title.getText().toString()); + float textHeight = mTextPaint.descent() - mTextPaint.ascent(); + MarginLayoutParams lp = (MarginLayoutParams) tipView.getLayoutParams(); + + float iconH = mIconHeight; + float margin = 0; + if (mIconVisible) { + if (iconH <= 0) { + iconH = mContext.getResources().getDrawable(mTabEntitys.get(position).getTabSelectedIcon()).getIntrinsicHeight(); + } + margin = mIconMargin; + } + + if (mIconGravity == Gravity.TOP || mIconGravity == Gravity.BOTTOM) { + lp.leftMargin = dp2px(leftPadding); + lp.topMargin = mHeight > 0 ? (int) (mHeight - textHeight - iconH - margin) / 2 - dp2px(bottomPadding) : dp2px(bottomPadding); + } else { + lp.leftMargin = dp2px(leftPadding); + lp.topMargin = mHeight > 0 ? (int) (mHeight - Math.max(textHeight, iconH)) / 2 - dp2px(bottomPadding) : dp2px(bottomPadding); + } + + tipView.setLayoutParams(lp); + } + } + + /** + * 当前类只提供了少许设置未读消息属性的方法,可以通过该方法获取MsgView对象从而各种设置 + */ + public MsgView getMsgView(int position) { + if (position >= mTabCount) { + position = mTabCount - 1; + } + View tabView = mTabsContainer.getChildAt(position); + MsgView tipView = (MsgView) tabView.findViewById(R.id.rtv_msg_tip); + return tipView; + } + + private OnTabSelectListener mListener; + + public void setOnTabSelectListener(OnTabSelectListener listener) { + this.mListener = listener; + } + + + @Override + protected Parcelable onSaveInstanceState() { + Bundle bundle = new Bundle(); + bundle.putParcelable("instanceState", super.onSaveInstanceState()); + bundle.putInt("mCurrentTab", mCurrentTab); + return bundle; + } + + @Override + protected void onRestoreInstanceState(Parcelable state) { + if (state instanceof Bundle) { + Bundle bundle = (Bundle) state; + mCurrentTab = bundle.getInt("mCurrentTab"); + state = bundle.getParcelable("instanceState"); + if (mCurrentTab != 0 && mTabsContainer.getChildCount() > 0) { + updateTabSelection(mCurrentTab); + } + } + super.onRestoreInstanceState(state); + } + + class IndicatorPoint { + public float left; + public float right; + } + + private IndicatorPoint mCurrentP = new IndicatorPoint(); + private IndicatorPoint mLastP = new IndicatorPoint(); + + class PointEvaluator implements TypeEvaluator { + @Override + public IndicatorPoint evaluate(float fraction, IndicatorPoint startValue, IndicatorPoint endValue) { + float left = startValue.left + fraction * (endValue.left - startValue.left); + float right = startValue.right + fraction * (endValue.right - startValue.right); + IndicatorPoint point = new IndicatorPoint(); + point.left = left; + point.right = right; + return point; + } + } + + + protected int dp2px(float dp) { + final float scale = mContext.getResources().getDisplayMetrics().density; + return (int) (dp * scale + 0.5f); + } + + protected int sp2px(float sp) { + final float scale = this.mContext.getResources().getDisplayMetrics().scaledDensity; + return (int) (sp * scale + 0.5f); + } + +} diff --git a/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/SegmentTabLayout.java b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/SegmentTabLayout.java new file mode 100644 index 0000000..98ff89a --- /dev/null +++ b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/SegmentTabLayout.java @@ -0,0 +1,775 @@ +package com.flyco.tablayout; + +import android.animation.TypeEvaluator; +import android.animation.ValueAnimator; +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.drawable.GradientDrawable; +import android.os.Bundle; +import android.os.Parcelable; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; +import android.util.AttributeSet; +import android.util.SparseArray; +import android.util.TypedValue; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.OvershootInterpolator; +import android.widget.FrameLayout; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.flyco.tablayout.listener.OnTabSelectListener; +import com.flyco.tablayout.utils.FragmentChangeManager; +import com.flyco.tablayout.utils.UnreadMsgUtils; +import com.flyco.tablayout.widget.MsgView; + +import java.util.ArrayList; + +public class SegmentTabLayout extends FrameLayout implements ValueAnimator.AnimatorUpdateListener { + private Context mContext; + private String[] mTitles; + private LinearLayout mTabsContainer; + private int mCurrentTab; + private int mLastTab; + private int mTabCount; + /** + * 用于绘制显示器 + */ + private Rect mIndicatorRect = new Rect(); + private GradientDrawable mIndicatorDrawable = new GradientDrawable(); + private GradientDrawable mRectDrawable = new GradientDrawable(); + + private Paint mDividerPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + + private float mTabPadding; + private boolean mTabSpaceEqual; + private float mTabWidth; + + /** + * indicator + */ + private int mIndicatorColor; + private float mIndicatorHeight; + private float mIndicatorCornerRadius; + private float mIndicatorMarginLeft; + private float mIndicatorMarginTop; + private float mIndicatorMarginRight; + private float mIndicatorMarginBottom; + private long mIndicatorAnimDuration; + private boolean mIndicatorAnimEnable; + private boolean mIndicatorBounceEnable; + + /** + * divider + */ + private int mDividerColor; + private float mDividerWidth; + private float mDividerPadding; + + /** + * title + */ + private static final int TEXT_BOLD_NONE = 0; + private static final int TEXT_BOLD_WHEN_SELECT = 1; + private static final int TEXT_BOLD_BOTH = 2; + private float mTextsize; + private int mTextSelectColor; + private int mTextUnselectColor; + private int mTextBold; + private boolean mTextAllCaps; + + private int mBarColor; + private int mBarStrokeColor; + private float mBarStrokeWidth; + + private int mHeight; + + /** + * anim + */ + private ValueAnimator mValueAnimator; + private OvershootInterpolator mInterpolator = new OvershootInterpolator(0.8f); + + private FragmentChangeManager mFragmentChangeManager; + private float[] mRadiusArr = new float[8]; + + public SegmentTabLayout(Context context) { + this(context, null, 0); + } + + public SegmentTabLayout(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public SegmentTabLayout(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + setWillNotDraw(false);//重写onDraw方法,需要调用这个方法来清除flag + setClipChildren(false); + setClipToPadding(false); + + this.mContext = context; + mTabsContainer = new LinearLayout(context); + addView(mTabsContainer); + + obtainAttributes(context, attrs); + + //get layout_height + String height = attrs.getAttributeValue("http://schemas.android.com/apk/res/android", "layout_height"); + + //create ViewPager + if (height.equals(ViewGroup.LayoutParams.MATCH_PARENT + "")) { + } else if (height.equals(ViewGroup.LayoutParams.WRAP_CONTENT + "")) { + } else { + int[] systemAttrs = {android.R.attr.layout_height}; + TypedArray a = context.obtainStyledAttributes(attrs, systemAttrs); + mHeight = a.getDimensionPixelSize(0, ViewGroup.LayoutParams.WRAP_CONTENT); + a.recycle(); + } + + mValueAnimator = ValueAnimator.ofObject(new PointEvaluator(), mLastP, mCurrentP); + mValueAnimator.addUpdateListener(this); + } + + private void obtainAttributes(Context context, AttributeSet attrs) { + TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.SegmentTabLayout); + + mIndicatorColor = ta.getColor(R.styleable.SegmentTabLayout_tl_indicator_color, Color.parseColor("#222831")); + mIndicatorHeight = ta.getDimension(R.styleable.SegmentTabLayout_tl_indicator_height, -1); + mIndicatorCornerRadius = ta.getDimension(R.styleable.SegmentTabLayout_tl_indicator_corner_radius, -1); + mIndicatorMarginLeft = ta.getDimension(R.styleable.SegmentTabLayout_tl_indicator_margin_left, dp2px(0)); + mIndicatorMarginTop = ta.getDimension(R.styleable.SegmentTabLayout_tl_indicator_margin_top, 0); + mIndicatorMarginRight = ta.getDimension(R.styleable.SegmentTabLayout_tl_indicator_margin_right, dp2px(0)); + mIndicatorMarginBottom = ta.getDimension(R.styleable.SegmentTabLayout_tl_indicator_margin_bottom, 0); + mIndicatorAnimEnable = ta.getBoolean(R.styleable.SegmentTabLayout_tl_indicator_anim_enable, false); + mIndicatorBounceEnable = ta.getBoolean(R.styleable.SegmentTabLayout_tl_indicator_bounce_enable, true); + mIndicatorAnimDuration = ta.getInt(R.styleable.SegmentTabLayout_tl_indicator_anim_duration, -1); + + mDividerColor = ta.getColor(R.styleable.SegmentTabLayout_tl_divider_color, mIndicatorColor); + mDividerWidth = ta.getDimension(R.styleable.SegmentTabLayout_tl_divider_width, dp2px(1)); + mDividerPadding = ta.getDimension(R.styleable.SegmentTabLayout_tl_divider_padding, 0); + + mTextsize = ta.getDimension(R.styleable.SegmentTabLayout_tl_textSize, sp2px(13f)); + mTextSelectColor = ta.getColor(R.styleable.SegmentTabLayout_tl_textSelectColor, Color.parseColor("#ffffff")); + mTextUnselectColor = ta.getColor(R.styleable.SegmentTabLayout_tl_textUnSelectColor, mIndicatorColor); + mTextBold = ta.getInt(R.styleable.SegmentTabLayout_tl_textBold, TEXT_BOLD_NONE); + mTextAllCaps = ta.getBoolean(R.styleable.SegmentTabLayout_tl_textAllCaps, false); + + mTabSpaceEqual = ta.getBoolean(R.styleable.SegmentTabLayout_tl_tab_space_equal, true); + mTabWidth = ta.getDimension(R.styleable.SegmentTabLayout_tl_tab_width, dp2px(-1)); + mTabPadding = ta.getDimension(R.styleable.SegmentTabLayout_tl_tab_padding, mTabSpaceEqual || mTabWidth > 0 ? dp2px(0) : dp2px(10)); + + mBarColor = ta.getColor(R.styleable.SegmentTabLayout_tl_bar_color, Color.TRANSPARENT); + mBarStrokeColor = ta.getColor(R.styleable.SegmentTabLayout_tl_bar_stroke_color, mIndicatorColor); + mBarStrokeWidth = ta.getDimension(R.styleable.SegmentTabLayout_tl_bar_stroke_width, dp2px(1)); + + ta.recycle(); + } + + public void setTabData(String[] titles) { + if (titles == null || titles.length == 0) { + throw new IllegalStateException("Titles can not be NULL or EMPTY !"); + } + + this.mTitles = titles; + + notifyDataSetChanged(); + } + + /** + * 关联数据支持同时切换fragments + */ + public void setTabData(String[] titles, FragmentActivity fa, int containerViewId, ArrayList fragments) { + mFragmentChangeManager = new FragmentChangeManager(fa.getSupportFragmentManager(), containerViewId, fragments); + setTabData(titles); + } + + /** + * 更新数据 + */ + public void notifyDataSetChanged() { + mTabsContainer.removeAllViews(); + this.mTabCount = mTitles.length; + View tabView; + for (int i = 0; i < mTabCount; i++) { + tabView = View.inflate(mContext, R.layout.layout_tab_segment, null); + tabView.setTag(i); + addTab(i, tabView); + } + + updateTabStyles(); + } + + /** + * 创建并添加tab + */ + private void addTab(final int position, View tabView) { + TextView tv_tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title); + tv_tab_title.setText(mTitles[position]); + + tabView.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + int position = (Integer) v.getTag(); + if (mCurrentTab != position) { + setCurrentTab(position); + if (mListener != null) { + mListener.onTabSelect(position); + } + } else { + if (mListener != null) { + mListener.onTabReselect(position); + } + } + } + }); + + /** 每一个Tab的布局参数 */ + LinearLayout.LayoutParams lp_tab = mTabSpaceEqual ? + new LinearLayout.LayoutParams(0, LayoutParams.MATCH_PARENT, 1.0f) : + new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT); + if (mTabWidth > 0) { + lp_tab = new LinearLayout.LayoutParams((int) mTabWidth, LayoutParams.MATCH_PARENT); + } + mTabsContainer.addView(tabView, position, lp_tab); + } + + private void updateTabStyles() { + for (int i = 0; i < mTabCount; i++) { + View tabView = mTabsContainer.getChildAt(i); + tabView.setPadding((int) mTabPadding, 0, (int) mTabPadding, 0); + TextView tv_tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title); + tv_tab_title.setTextColor(i == mCurrentTab ? mTextSelectColor : mTextUnselectColor); + tv_tab_title.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextsize); +// tv_tab_title.setPadding((int) mTabPadding, 0, (int) mTabPadding, 0); + if (mTextAllCaps) { + tv_tab_title.setText(tv_tab_title.getText().toString().toUpperCase()); + } + + if (mTextBold == TEXT_BOLD_BOTH) { + tv_tab_title.getPaint().setFakeBoldText(true); + } + // 被选中设置为粗体 + else if (mTextBold == TEXT_BOLD_WHEN_SELECT && i == mCurrentTab) { + tv_tab_title.getPaint().setFakeBoldText(true); + } else if (mTextBold == TEXT_BOLD_NONE) { + tv_tab_title.getPaint().setFakeBoldText(false); + } + } + } + + private void updateTabSelection(int position) { + for (int i = 0; i < mTabCount; ++i) { + View tabView = mTabsContainer.getChildAt(i); + final boolean isSelect = i == position; + TextView tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title); + tab_title.setTextColor(isSelect ? mTextSelectColor : mTextUnselectColor); + if (mTextBold == TEXT_BOLD_WHEN_SELECT) { + tab_title.getPaint().setFakeBoldText(isSelect); + } + } + } + + private void calcOffset() { + final View currentTabView = mTabsContainer.getChildAt(this.mCurrentTab); + mCurrentP.left = currentTabView.getLeft(); + mCurrentP.right = currentTabView.getRight(); + + final View lastTabView = mTabsContainer.getChildAt(this.mLastTab); + mLastP.left = lastTabView.getLeft(); + mLastP.right = lastTabView.getRight(); + +// Log.d("AAA", "mLastP--->" + mLastP.left + "&" + mLastP.right); +// Log.d("AAA", "mCurrentP--->" + mCurrentP.left + "&" + mCurrentP.right); + if (mLastP.left == mCurrentP.left && mLastP.right == mCurrentP.right) { + invalidate(); + } else { + mValueAnimator.setObjectValues(mLastP, mCurrentP); + if (mIndicatorBounceEnable) { + mValueAnimator.setInterpolator(mInterpolator); + } + + if (mIndicatorAnimDuration < 0) { + mIndicatorAnimDuration = mIndicatorBounceEnable ? 500 : 250; + } + mValueAnimator.setDuration(mIndicatorAnimDuration); + mValueAnimator.start(); + } + } + + private void calcIndicatorRect() { + View currentTabView = mTabsContainer.getChildAt(this.mCurrentTab); + float left = currentTabView.getLeft(); + float right = currentTabView.getRight(); + + mIndicatorRect.left = (int) left; + mIndicatorRect.right = (int) right; + + if (!mIndicatorAnimEnable) { + if (mCurrentTab == 0) { + /**The corners are ordered top-left, top-right, bottom-right, bottom-left*/ + mRadiusArr[0] = mIndicatorCornerRadius; + mRadiusArr[1] = mIndicatorCornerRadius; + mRadiusArr[2] = 0; + mRadiusArr[3] = 0; + mRadiusArr[4] = 0; + mRadiusArr[5] = 0; + mRadiusArr[6] = mIndicatorCornerRadius; + mRadiusArr[7] = mIndicatorCornerRadius; + } else if (mCurrentTab == mTabCount - 1) { + /**The corners are ordered top-left, top-right, bottom-right, bottom-left*/ + mRadiusArr[0] = 0; + mRadiusArr[1] = 0; + mRadiusArr[2] = mIndicatorCornerRadius; + mRadiusArr[3] = mIndicatorCornerRadius; + mRadiusArr[4] = mIndicatorCornerRadius; + mRadiusArr[5] = mIndicatorCornerRadius; + mRadiusArr[6] = 0; + mRadiusArr[7] = 0; + } else { + /**The corners are ordered top-left, top-right, bottom-right, bottom-left*/ + mRadiusArr[0] = 0; + mRadiusArr[1] = 0; + mRadiusArr[2] = 0; + mRadiusArr[3] = 0; + mRadiusArr[4] = 0; + mRadiusArr[5] = 0; + mRadiusArr[6] = 0; + mRadiusArr[7] = 0; + } + } else { + /**The corners are ordered top-left, top-right, bottom-right, bottom-left*/ + mRadiusArr[0] = mIndicatorCornerRadius; + mRadiusArr[1] = mIndicatorCornerRadius; + mRadiusArr[2] = mIndicatorCornerRadius; + mRadiusArr[3] = mIndicatorCornerRadius; + mRadiusArr[4] = mIndicatorCornerRadius; + mRadiusArr[5] = mIndicatorCornerRadius; + mRadiusArr[6] = mIndicatorCornerRadius; + mRadiusArr[7] = mIndicatorCornerRadius; + } + } + + @Override + public void onAnimationUpdate(ValueAnimator animation) { + IndicatorPoint p = (IndicatorPoint) animation.getAnimatedValue(); + mIndicatorRect.left = (int) p.left; + mIndicatorRect.right = (int) p.right; + invalidate(); + } + + private boolean mIsFirstDraw = true; + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + if (isInEditMode() || mTabCount <= 0) { + return; + } + + int height = getHeight(); + int paddingLeft = getPaddingLeft(); + + if (mIndicatorHeight < 0) { + mIndicatorHeight = height - mIndicatorMarginTop - mIndicatorMarginBottom; + } + + if (mIndicatorCornerRadius < 0 || mIndicatorCornerRadius > mIndicatorHeight / 2) { + mIndicatorCornerRadius = mIndicatorHeight / 2; + } + + //draw rect + mRectDrawable.setColor(mBarColor); + mRectDrawable.setStroke((int) mBarStrokeWidth, mBarStrokeColor); + mRectDrawable.setCornerRadius(mIndicatorCornerRadius); + mRectDrawable.setBounds(getPaddingLeft(), getPaddingTop(), getWidth() - getPaddingRight(), getHeight() - getPaddingBottom()); + mRectDrawable.draw(canvas); + + // draw divider + if (!mIndicatorAnimEnable && mDividerWidth > 0) { + mDividerPaint.setStrokeWidth(mDividerWidth); + mDividerPaint.setColor(mDividerColor); + for (int i = 0; i < mTabCount - 1; i++) { + View tab = mTabsContainer.getChildAt(i); + canvas.drawLine(paddingLeft + tab.getRight(), mDividerPadding, paddingLeft + tab.getRight(), height - mDividerPadding, mDividerPaint); + } + } + + + //draw indicator line + if (mIndicatorAnimEnable) { + if (mIsFirstDraw) { + mIsFirstDraw = false; + calcIndicatorRect(); + } + } else { + calcIndicatorRect(); + } + + mIndicatorDrawable.setColor(mIndicatorColor); + mIndicatorDrawable.setBounds(paddingLeft + (int) mIndicatorMarginLeft + mIndicatorRect.left, + (int) mIndicatorMarginTop, (int) (paddingLeft + mIndicatorRect.right - mIndicatorMarginRight), + (int) (mIndicatorMarginTop + mIndicatorHeight)); + mIndicatorDrawable.setCornerRadii(mRadiusArr); + mIndicatorDrawable.draw(canvas); + + } + + //setter and getter + public void setCurrentTab(int currentTab) { + mLastTab = this.mCurrentTab; + this.mCurrentTab = currentTab; + updateTabSelection(currentTab); + if (mFragmentChangeManager != null) { + mFragmentChangeManager.setFragments(currentTab); + } + if (mIndicatorAnimEnable) { + calcOffset(); + } else { + invalidate(); + } + } + + public void setTabPadding(float tabPadding) { + this.mTabPadding = dp2px(tabPadding); + updateTabStyles(); + } + + public void setTabSpaceEqual(boolean tabSpaceEqual) { + this.mTabSpaceEqual = tabSpaceEqual; + updateTabStyles(); + } + + public void setTabWidth(float tabWidth) { + this.mTabWidth = dp2px(tabWidth); + updateTabStyles(); + } + + public void setIndicatorColor(int indicatorColor) { + this.mIndicatorColor = indicatorColor; + invalidate(); + } + + public void setIndicatorHeight(float indicatorHeight) { + this.mIndicatorHeight = dp2px(indicatorHeight); + invalidate(); + } + + public void setIndicatorCornerRadius(float indicatorCornerRadius) { + this.mIndicatorCornerRadius = dp2px(indicatorCornerRadius); + invalidate(); + } + + public void setIndicatorMargin(float indicatorMarginLeft, float indicatorMarginTop, + float indicatorMarginRight, float indicatorMarginBottom) { + this.mIndicatorMarginLeft = dp2px(indicatorMarginLeft); + this.mIndicatorMarginTop = dp2px(indicatorMarginTop); + this.mIndicatorMarginRight = dp2px(indicatorMarginRight); + this.mIndicatorMarginBottom = dp2px(indicatorMarginBottom); + invalidate(); + } + + public void setIndicatorAnimDuration(long indicatorAnimDuration) { + this.mIndicatorAnimDuration = indicatorAnimDuration; + } + + public void setIndicatorAnimEnable(boolean indicatorAnimEnable) { + this.mIndicatorAnimEnable = indicatorAnimEnable; + } + + public void setIndicatorBounceEnable(boolean indicatorBounceEnable) { + this.mIndicatorBounceEnable = indicatorBounceEnable; + } + + public void setDividerColor(int dividerColor) { + this.mDividerColor = dividerColor; + invalidate(); + } + + public void setDividerWidth(float dividerWidth) { + this.mDividerWidth = dp2px(dividerWidth); + invalidate(); + } + + public void setDividerPadding(float dividerPadding) { + this.mDividerPadding = dp2px(dividerPadding); + invalidate(); + } + + public void setTextsize(float textsize) { + this.mTextsize = sp2px(textsize); + updateTabStyles(); + } + + public void setTextSelectColor(int textSelectColor) { + this.mTextSelectColor = textSelectColor; + updateTabStyles(); + } + + public void setTextUnselectColor(int textUnselectColor) { + this.mTextUnselectColor = textUnselectColor; + updateTabStyles(); + } + + public void setTextBold(int textBold) { + this.mTextBold = textBold; + updateTabStyles(); + } + + public void setTextAllCaps(boolean textAllCaps) { + this.mTextAllCaps = textAllCaps; + updateTabStyles(); + } + + public int getTabCount() { + return mTabCount; + } + + public int getCurrentTab() { + return mCurrentTab; + } + + public float getTabPadding() { + return mTabPadding; + } + + public boolean isTabSpaceEqual() { + return mTabSpaceEqual; + } + + public float getTabWidth() { + return mTabWidth; + } + + public int getIndicatorColor() { + return mIndicatorColor; + } + + public float getIndicatorHeight() { + return mIndicatorHeight; + } + + public float getIndicatorCornerRadius() { + return mIndicatorCornerRadius; + } + + public float getIndicatorMarginLeft() { + return mIndicatorMarginLeft; + } + + public float getIndicatorMarginTop() { + return mIndicatorMarginTop; + } + + public float getIndicatorMarginRight() { + return mIndicatorMarginRight; + } + + public float getIndicatorMarginBottom() { + return mIndicatorMarginBottom; + } + + public long getIndicatorAnimDuration() { + return mIndicatorAnimDuration; + } + + public boolean isIndicatorAnimEnable() { + return mIndicatorAnimEnable; + } + + public boolean isIndicatorBounceEnable() { + return mIndicatorBounceEnable; + } + + public int getDividerColor() { + return mDividerColor; + } + + public float getDividerWidth() { + return mDividerWidth; + } + + public float getDividerPadding() { + return mDividerPadding; + } + + public float getTextsize() { + return mTextsize; + } + + public int getTextSelectColor() { + return mTextSelectColor; + } + + public int getTextUnselectColor() { + return mTextUnselectColor; + } + + public int getTextBold() { + return mTextBold; + } + + public boolean isTextAllCaps() { + return mTextAllCaps; + } + + public TextView getTitleView(int tab) { + View tabView = mTabsContainer.getChildAt(tab); + TextView tv_tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title); + return tv_tab_title; + } + + //setter and getter + // show MsgTipView + private Paint mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private SparseArray mInitSetMap = new SparseArray<>(); + + /** + * 显示未读消息 + * + * @param position 显示tab位置 + * @param num num小于等于0显示红点,num大于0显示数字 + */ + public void showMsg(int position, int num) { + if (position >= mTabCount) { + position = mTabCount - 1; + } + + View tabView = mTabsContainer.getChildAt(position); + MsgView tipView = (MsgView) tabView.findViewById(R.id.rtv_msg_tip); + if (tipView != null) { + UnreadMsgUtils.show(tipView, num); + + if (mInitSetMap.get(position) != null && mInitSetMap.get(position)) { + return; + } + + setMsgMargin(position, 2, 2); + + mInitSetMap.put(position, true); + } + } + + /** + * 显示未读红点 + * + * @param position 显示tab位置 + */ + public void showDot(int position) { + if (position >= mTabCount) { + position = mTabCount - 1; + } + showMsg(position, 0); + } + + public void hideMsg(int position) { + if (position >= mTabCount) { + position = mTabCount - 1; + } + + View tabView = mTabsContainer.getChildAt(position); + MsgView tipView = (MsgView) tabView.findViewById(R.id.rtv_msg_tip); + if (tipView != null) { + tipView.setVisibility(View.GONE); + } + } + + /** + * 设置提示红点偏移,注意 + * 1.控件为固定高度:参照点为tab内容的右上角 + * 2.控件高度不固定(WRAP_CONTENT):参照点为tab内容的右上角,此时高度已是红点的最高显示范围,所以这时bottomPadding其实就是topPadding + */ + public void setMsgMargin(int position, float leftPadding, float bottomPadding) { + if (position >= mTabCount) { + position = mTabCount - 1; + } + View tabView = mTabsContainer.getChildAt(position); + MsgView tipView = (MsgView) tabView.findViewById(R.id.rtv_msg_tip); + if (tipView != null) { + TextView tv_tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title); + mTextPaint.setTextSize(mTextsize); + float textWidth = mTextPaint.measureText(tv_tab_title.getText().toString()); + float textHeight = mTextPaint.descent() - mTextPaint.ascent(); + MarginLayoutParams lp = (MarginLayoutParams) tipView.getLayoutParams(); + + lp.leftMargin = dp2px(leftPadding); + lp.topMargin = mHeight > 0 ? (int) (mHeight - textHeight) / 2 - dp2px(bottomPadding) : dp2px(bottomPadding); + + tipView.setLayoutParams(lp); + } + } + + /** + * 当前类只提供了少许设置未读消息属性的方法,可以通过该方法获取MsgView对象从而各种设置 + */ + public MsgView getMsgView(int position) { + if (position >= mTabCount) { + position = mTabCount - 1; + } + View tabView = mTabsContainer.getChildAt(position); + MsgView tipView = (MsgView) tabView.findViewById(R.id.rtv_msg_tip); + return tipView; + } + + private OnTabSelectListener mListener; + + public void setOnTabSelectListener(OnTabSelectListener listener) { + this.mListener = listener; + } + + @Override + protected Parcelable onSaveInstanceState() { + Bundle bundle = new Bundle(); + bundle.putParcelable("instanceState", super.onSaveInstanceState()); + bundle.putInt("mCurrentTab", mCurrentTab); + return bundle; + } + + @Override + protected void onRestoreInstanceState(Parcelable state) { + if (state instanceof Bundle) { + Bundle bundle = (Bundle) state; + mCurrentTab = bundle.getInt("mCurrentTab"); + state = bundle.getParcelable("instanceState"); + if (mCurrentTab != 0 && mTabsContainer.getChildCount() > 0) { + updateTabSelection(mCurrentTab); + } + } + super.onRestoreInstanceState(state); + } + + class IndicatorPoint { + public float left; + public float right; + } + + private IndicatorPoint mCurrentP = new IndicatorPoint(); + private IndicatorPoint mLastP = new IndicatorPoint(); + + class PointEvaluator implements TypeEvaluator { + @Override + public IndicatorPoint evaluate(float fraction, IndicatorPoint startValue, IndicatorPoint endValue) { + float left = startValue.left + fraction * (endValue.left - startValue.left); + float right = startValue.right + fraction * (endValue.right - startValue.right); + IndicatorPoint point = new IndicatorPoint(); + point.left = left; + point.right = right; + return point; + } + } + + protected int dp2px(float dp) { + final float scale = mContext.getResources().getDisplayMetrics().density; + return (int) (dp * scale + 0.5f); + } + + protected int sp2px(float sp) { + final float scale = this.mContext.getResources().getDisplayMetrics().scaledDensity; + return (int) (sp * scale + 0.5f); + } +} diff --git a/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/SlidingScaleTabLayout.java b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/SlidingScaleTabLayout.java new file mode 100644 index 0000000..dd437b7 --- /dev/null +++ b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/SlidingScaleTabLayout.java @@ -0,0 +1,1216 @@ +package com.flyco.tablayout; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.Rect; +import android.graphics.drawable.GradientDrawable; +import android.os.Bundle; +import android.os.Parcelable; +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentPagerAdapter; +import androidx.viewpager.widget.PagerAdapter; +import androidx.viewpager.widget.ViewPager; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.util.SparseBooleanArray; +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.ImageView; +import android.widget.LinearLayout; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import com.flyco.tablayout.listener.OnTabSelectListener; +import com.flyco.tablayout.transformer.ExtendTransformer; +import com.flyco.tablayout.transformer.ITabScaleTransformer; +import com.flyco.tablayout.transformer.IViewPagerTransformer; +import com.flyco.tablayout.transformer.TabScaleTransformer; +import com.flyco.tablayout.utils.UnreadMsgUtils; +import com.flyco.tablayout.utils.ViewUtils; +import com.flyco.tablayout.widget.MsgView; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * 滑动切换TabLayout,tab的文字大小会发生变化 + */ +public class SlidingScaleTabLayout extends HorizontalScrollView implements ViewPager.OnPageChangeListener { + + private static final int TOP = 0; + private static final int BOTTOM = 1; + private static final int CENTER = 2; + private static final int LEFT = 0; + private static final int RIGHT = 1; + + private Context mContext; + private ViewPager mViewPager; + private ArrayList mTitles; + private LinearLayout mTabsContainer; + private int mCurrentTab; + private float mCurrentPositionOffset; + private int mTabCount; + /** + * 用于绘制显示器 + */ + private Rect mIndicatorRect = new Rect(); + /** + * 用于实现滚动居中 + */ + private Rect mTabRect = new Rect(); + private GradientDrawable mIndicatorDrawable = new GradientDrawable(); + + private Paint mRectPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private Paint mDividerPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private Paint mTrianglePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private Path mTrianglePath = new Path(); + private static final int STYLE_NORMAL = 0; + private static final int STYLE_TRIANGLE = 1; + private static final int STYLE_BLOCK = 2; + private int mIndicatorStyle = STYLE_NORMAL; + + private float mTabPadding; + private boolean mTabSpaceEqual; + private float mTabWidth; + + /** + * indicator + */ + private int mIndicatorColor; + private float mIndicatorHeight; + private float mIndicatorWidth; + private float mIndicatorCornerRadius; + private float mIndicatorMarginLeft; + private float mIndicatorMarginTop; + private float mIndicatorMarginRight; + private float mIndicatorMarginBottom; + private int mIndicatorGravity; + private boolean mIndicatorWidthEqualTitle; + + /** + * underline + */ + private int mUnderlineColor; + private float mUnderlineHeight; + private int mUnderlineGravity; + + /** + * divider + */ + private int mDividerColor; + private float mDividerWidth; + private float mDividerPadding; + + /** + * title + */ + private static final int TEXT_BOLD_NONE = 0; + private static final int TEXT_BOLD_WHEN_SELECT = 1; + private static final int TEXT_BOLD_BOTH = 2; + private float mTextSelectSize; + private float mTextUnSelectSize; + private int mTextSelectColor; + private int mTextUnSelectColor; + private int mTextBold; + private boolean mTextAllCaps; + + private int mLastScrollX; + private int mHeight; + private boolean mSnapOnTabClick; + + /** + * tab的上下间距 + */ + private int mTabMarginTop; + private int mTabMarginBottom; + + private int mTabMsgMarginTop; + private int mTabMsgMarginRight; + private int mTabDotMarginTop; + private int mTabDotMarginRight; + private int mTabBackgroundId; + + private boolean openDmg = true; + + /** + * tab中的内容的位置 + */ + private int mTabHorizontalGravity; + + private int mTabVerticalGravity; + + private ITabScaleTransformer iTabScaleTransformer; + + private ExtendTransformer extendTransformer; + + public SlidingScaleTabLayout(Context context) { + this(context, null, 0); + } + + public SlidingScaleTabLayout(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public SlidingScaleTabLayout(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + setFillViewport(true);//设置滚动视图是否可以伸缩其内容以填充视口 + setWillNotDraw(false);//重写onDraw方法,需要调用这个方法来清除flag + setClipChildren(false); + setClipToPadding(false); + + this.mContext = context; + mTabsContainer = new LinearLayout(context); + addView(mTabsContainer); + + obtainAttributes(context, attrs); + + //get layout_height + String height = attrs.getAttributeValue("http://schemas.android.com/apk/res/android", "layout_height"); + + if (height.equals(ViewGroup.LayoutParams.MATCH_PARENT + "")) { + } else if (height.equals(ViewGroup.LayoutParams.WRAP_CONTENT + "")) { + } else { + int[] systemAttrs = {android.R.attr.layout_height}; + TypedArray a = context.obtainStyledAttributes(attrs, systemAttrs); + mHeight = a.getDimensionPixelSize(0, ViewGroup.LayoutParams.WRAP_CONTENT); + a.recycle(); + } + } + + private void obtainAttributes(Context context, AttributeSet attrs) { + TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.SlidingScaleTabLayout); + + mIndicatorStyle = ta.getInt(R.styleable.SlidingScaleTabLayout_tl_indicator_style, STYLE_NORMAL); + mIndicatorColor = ta.getColor(R.styleable.SlidingScaleTabLayout_tl_indicator_color, Color.parseColor(mIndicatorStyle == STYLE_BLOCK ? "#4B6A87" : "#ffffff")); + mIndicatorHeight = ta.getDimension(R.styleable.SlidingScaleTabLayout_tl_indicator_height, + dp2px(mIndicatorStyle == STYLE_TRIANGLE ? 4 : (mIndicatorStyle == STYLE_BLOCK ? -1 : 2))); + mIndicatorWidth = ta.getDimension(R.styleable.SlidingScaleTabLayout_tl_indicator_width, dp2px(mIndicatorStyle == STYLE_TRIANGLE ? 10 : -1)); + mIndicatorCornerRadius = ta.getDimension(R.styleable.SlidingScaleTabLayout_tl_indicator_corner_radius, dp2px(mIndicatorStyle == STYLE_BLOCK ? -1 : 0)); + mIndicatorMarginLeft = ta.getDimension(R.styleable.SlidingScaleTabLayout_tl_indicator_margin_left, dp2px(0)); + mIndicatorMarginTop = ta.getDimension(R.styleable.SlidingScaleTabLayout_tl_indicator_margin_top, dp2px(mIndicatorStyle == STYLE_BLOCK ? 7 : 0)); + mIndicatorMarginRight = ta.getDimension(R.styleable.SlidingScaleTabLayout_tl_indicator_margin_right, dp2px(0)); + mIndicatorMarginBottom = ta.getDimension(R.styleable.SlidingScaleTabLayout_tl_indicator_margin_bottom, dp2px(mIndicatorStyle == STYLE_BLOCK ? 7 : 0)); + mIndicatorGravity = ta.getInt(R.styleable.SlidingScaleTabLayout_tl_indicator_gravity, Gravity.BOTTOM); + mIndicatorWidthEqualTitle = ta.getBoolean(R.styleable.SlidingScaleTabLayout_tl_indicator_width_equal_title, false); + + mUnderlineColor = ta.getColor(R.styleable.SlidingScaleTabLayout_tl_underline_color, Color.parseColor("#ffffff")); + mUnderlineHeight = ta.getDimension(R.styleable.SlidingScaleTabLayout_tl_underline_height, dp2px(0)); + mUnderlineGravity = ta.getInt(R.styleable.SlidingScaleTabLayout_tl_underline_gravity, Gravity.BOTTOM); + + mDividerColor = ta.getColor(R.styleable.SlidingScaleTabLayout_tl_divider_color, Color.parseColor("#ffffff")); + mDividerWidth = ta.getDimension(R.styleable.SlidingScaleTabLayout_tl_divider_width, dp2px(0)); + mDividerPadding = ta.getDimension(R.styleable.SlidingScaleTabLayout_tl_divider_padding, dp2px(12)); + + mTextUnSelectSize = ta.getDimension(R.styleable.SlidingScaleTabLayout_tl_textUnSelectSize, sp2px(14)); + // 被选中的文字大小,默认额未选中的大小一样 + mTextSelectSize = ta.getDimension(R.styleable.SlidingScaleTabLayout_tl_textSelectSize, mTextUnSelectSize); + + mTextSelectColor = ta.getColor(R.styleable.SlidingScaleTabLayout_tl_textSelectColor, Color.parseColor("#ffffff")); + mTextUnSelectColor = ta.getColor(R.styleable.SlidingScaleTabLayout_tl_textUnSelectColor, Color.parseColor("#AAffffff")); + mTextBold = ta.getInt(R.styleable.SlidingScaleTabLayout_tl_textBold, TEXT_BOLD_NONE); + mTextAllCaps = ta.getBoolean(R.styleable.SlidingScaleTabLayout_tl_textAllCaps, false); + + mTabSpaceEqual = ta.getBoolean(R.styleable.SlidingScaleTabLayout_tl_tab_space_equal, false); + mTabWidth = ta.getDimension(R.styleable.SlidingScaleTabLayout_tl_tab_width, dp2px(-1)); + mTabPadding = ta.getDimension(R.styleable.SlidingScaleTabLayout_tl_tab_padding, mTabSpaceEqual || mTabWidth > 0 ? dp2px(0) : dp2px(20)); + // 得到设置的上下间距和gravity + mTabMarginTop = ta.getDimensionPixelSize(R.styleable.SlidingScaleTabLayout_tl_tab_marginTop, 0); + mTabMarginBottom = ta.getDimensionPixelSize(R.styleable.SlidingScaleTabLayout_tl_tab_marginBottom, 0); + + mTabHorizontalGravity = ta.getInt(R.styleable.SlidingScaleTabLayout_tl_tab_horizontal_gravity, CENTER); + mTabVerticalGravity = ta.getInt(R.styleable.SlidingScaleTabLayout_tl_tab_vertical_gravity, CENTER); + + mTabMsgMarginTop = (int) ta.getDimension(R.styleable.SlidingScaleTabLayout_tl_tab_msg_marginTop, 0f); + mTabMsgMarginRight = (int) ta.getDimension(R.styleable.SlidingScaleTabLayout_tl_tab_msg_marginRight, 0f); + + mTabDotMarginTop = (int) ta.getDimension(R.styleable.SlidingScaleTabLayout_tl_tab_dot_marginTop, 0f); + mTabDotMarginRight = (int) ta.getDimension(R.styleable.SlidingScaleTabLayout_tl_tab_dot_marginRight, 0f); + mTabBackgroundId = ta.getResourceId(R.styleable.SlidingScaleTabLayout_tl_tab_background, 0); + openDmg = ta.getBoolean(R.styleable.SlidingScaleTabLayout_tl_openTextDmg, false); + ta.recycle(); + + iTabScaleTransformer = new TabScaleTransformer(this, mTextSelectSize, mTextUnSelectSize, openDmg); + } + + /** + * 关联ViewPager + */ + public void setViewPager(ViewPager vp) { + if (vp == null || vp.getAdapter() == null) { + throw new IllegalStateException("ViewPager or ViewPager adapter can not be NULL !"); + } + + this.mViewPager = vp; + + initViewPagerListener(); + } + + /** + * 设置标题,不关联ViewPager + */ + public void setTitle(String[] titles) { + mTitles = new ArrayList<>(); + Collections.addAll(mTitles, titles); + initViewPagerListener(); + } + + + /** + * 关联ViewPager,用于不想在ViewPager适配器中设置titles数据的情况 + */ + public void setViewPager(ViewPager vp, String[] titles) { + if (vp == null || vp.getAdapter() == null) { + throw new IllegalStateException("ViewPager or ViewPager adapter can not be NULL !"); + } + + if (titles == null || titles.length == 0) { + throw new IllegalStateException("Titles can not be EMPTY !"); + } + + if (titles.length != vp.getAdapter().getCount()) { + throw new IllegalStateException("Titles length must be the same as the page count !"); + } + + this.mViewPager = vp; + mTitles = new ArrayList<>(); + Collections.addAll(mTitles, titles); + + initViewPagerListener(); + } + + /** + * 关联ViewPager,用于连适配器都不想自己实例化的情况 + */ + public void setViewPager(ViewPager vp, String[] titles, FragmentActivity fa, ArrayList fragments) { + if (vp == null) { + throw new IllegalStateException("ViewPager can not be NULL !"); + } + + if (titles == null || titles.length == 0) { + throw new IllegalStateException("Titles can not be EMPTY !"); + } + + this.mViewPager = vp; + this.mViewPager.setAdapter(new InnerPagerAdapter(fa.getSupportFragmentManager(), fragments, titles)); + initViewPagerListener(); + } + + private void initViewPagerListener() { + if (this.mViewPager != null) { + this.mViewPager.removeOnPageChangeListener(this); + this.mViewPager.addOnPageChangeListener(this); + initTransformer(); + } + notifyDataSetChanged(); + } + + private void initTransformer() { + // 如果选中状态的文字大小和未选中状态的文字大小是不同的,开启缩放 + if (mTextUnSelectSize != mTextSelectSize) { + extendTransformer = new ExtendTransformer(); + this.mViewPager.setPageTransformer(true, extendTransformer); + } + } + + /** + * 更新数据 + */ + public void notifyDataSetChanged() { + mTabsContainer.removeAllViews(); + this.mTabCount = mTitles == null ? mViewPager.getAdapter().getCount() : mTitles.size(); + View tabView; + for (int i = 0; i < mTabCount; i++) { + tabView = LayoutInflater.from(mContext).inflate(R.layout.layout_scale_tab, mTabsContainer, false); + TextView title = tabView.findViewById(R.id.tv_tab_title); + // 设置tab的位置信息 + setTabLayoutParams(title); + CharSequence pageTitle = mTitles == null ? mViewPager.getAdapter().getPageTitle(i) : mTitles.get(i); + addTab(i, pageTitle.toString(), tabView); + } + + updateTabStyles(); + } + + private void setTabLayoutParams(TextView title) { + RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) title.getLayoutParams(); + params.topMargin = mTabMarginTop; + params.bottomMargin = mTabMarginBottom; + + if (mTabVerticalGravity == TOP) { + params.addRule(RelativeLayout.ALIGN_PARENT_TOP); + } else if (mTabVerticalGravity == BOTTOM) { + params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM); + } else { + params.addRule(RelativeLayout.CENTER_VERTICAL); + } + + if (mTabHorizontalGravity == LEFT) { + params.addRule(RelativeLayout.ALIGN_PARENT_LEFT); + } else if (mTabHorizontalGravity == RIGHT) { + params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT); + } else { + params.addRule(RelativeLayout.CENTER_HORIZONTAL); + } + + + title.setLayoutParams(params); + + if (isDmgOpen()) { + ImageView imageView = (ImageView) ViewUtils.findBrotherView(title, R.id.tv_tab_title_dmg, 3); + if (imageView == null) return; + params = (RelativeLayout.LayoutParams) imageView.getLayoutParams(); + params.topMargin = mTabMarginTop; + params.bottomMargin = mTabMarginBottom; + // 调整镜像的问题 + if (mTabVerticalGravity == TOP) { + params.addRule(RelativeLayout.ALIGN_PARENT_TOP); + imageView.setScaleType(ImageView.ScaleType.FIT_START); + } else if (mTabVerticalGravity == BOTTOM) { + params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM); + imageView.setScaleType(ImageView.ScaleType.FIT_END); + } else { + params.addRule(RelativeLayout.CENTER_VERTICAL); + imageView.setScaleType(ImageView.ScaleType.FIT_CENTER); + } + + if (mTabHorizontalGravity == LEFT) { + params.addRule(RelativeLayout.ALIGN_PARENT_LEFT); + } else if (mTabHorizontalGravity == RIGHT) { + params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT); + } else { + params.addRule(RelativeLayout.CENTER_HORIZONTAL); + } + + imageView.setLayoutParams(params); + } + + } + + /** + * 如果文字的大小没有变化,不需要开启镜像,请注意 + */ + private boolean isDmgOpen() { + return openDmg && mTextSelectSize != mTextUnSelectSize; + } + + /** + * 创建并添加tab + */ + private void addTab(final int position, String title, View tabView) { + TextView tv_tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title); + if (tv_tab_title != null) { +// tv_tab_title.setTextSize(TypedValue.COMPLEX_UNIT_PX, position == mCurrentTab ? mTextSelectSize : mTextUnSelectSize); + tv_tab_title.setText(title); + // 设置tab背景 + if (mTabBackgroundId != 0){ + tv_tab_title.setBackgroundResource(mTabBackgroundId); + } +// if (TextUtils.isEmpty(title)) { +// tabView.setVisibility(View.GONE); +// } else { +// tabView.setVisibility(View.VISIBLE); +// } + } + + tabView.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + int position = mTabsContainer.indexOfChild(v); + if (position != -1) { + setCurrentTab(position); + } + } + }); + + /** 每一个Tab的布局参数 */ + LinearLayout.LayoutParams lp_tab = mTabSpaceEqual ? + new LinearLayout.LayoutParams(0, LayoutParams.MATCH_PARENT, 1.0f) : + new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT); + if (mTabWidth > 0) { + lp_tab = new LinearLayout.LayoutParams((int) mTabWidth, LayoutParams.MATCH_PARENT); + } + mTabsContainer.addView(tabView, position, lp_tab); + } + + private void updateTabStyles() { + for (int i = 0; i < mTabCount; i++) { + View v = mTabsContainer.getChildAt(i); +// v.setPadding((int) mTabPadding, v.getPaddingTop(), (int) mTabPadding, v.getPaddingBottom()); + TextView tv_tab_title = (TextView) v.findViewById(R.id.tv_tab_title); + if (tv_tab_title != null) { + v.setPadding((int) mTabPadding, 0, (int) mTabPadding, 0); + tv_tab_title.setTextSize(TypedValue.COMPLEX_UNIT_PX, i == mCurrentTab ? mTextSelectSize : mTextUnSelectSize); + tv_tab_title.setTextColor(i == mCurrentTab ? mTextSelectColor : mTextUnSelectColor); + // 设置选中状态 + tv_tab_title.setSelected(i == mCurrentTab); + + if (mTextAllCaps) { + tv_tab_title.setText(tv_tab_title.getText().toString().toUpperCase()); + } + + if (mTextBold == TEXT_BOLD_BOTH) { + tv_tab_title.getPaint().setFakeBoldText(true); + } + // 被选中设置为粗体 + else if (mTextBold == TEXT_BOLD_WHEN_SELECT) { + tv_tab_title.getPaint().setFakeBoldText(i == mCurrentTab); + } else if (mTextBold == TEXT_BOLD_NONE) { + tv_tab_title.getPaint().setFakeBoldText(false); + } + + if (isDmgOpen()) { + generateTitleDmg(v, tv_tab_title, i); + } + } + } + + } + + private void generateTitleDmg(View tabView, TextView textView, int position) { + // 空字符串不能做镜像,否则会引发空指针 + if (TextUtils.isEmpty(textView.getText())) { + return; + } + + // 如果需要开启镜像,需要把所有的字设置为选中的字体 +// textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextUnSelectSize); +// ImageView imageView = tabView.findViewById(R.id.tv_tab_title_dmg); +// imageView.setImageBitmap(ViewUtils.generateViewCacheBitmap(textView)); +// imageView.setMaxWidth(imageView.getDrawable().getIntrinsicWidth()); + + + ImageView imageView = tabView.findViewById(R.id.tv_tab_title_dmg); + // 如果需要开启镜像,需要把所有的字设置为选中的字体 + if (mTextSelectSize >= mTextUnSelectSize){ + textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextSelectSize); + imageView.setImageBitmap(ViewUtils.generateViewCacheBitmap(textView)); + int drawableWidth = imageView.getDrawable().getIntrinsicWidth(); + imageView.setMinimumWidth((int) (drawableWidth * mTextUnSelectSize / mTextSelectSize)); + imageView.setMaxWidth(drawableWidth); + } + else{ + textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextUnSelectSize); + imageView.setImageBitmap(ViewUtils.generateViewCacheBitmap(textView)); + int drawableWidth = imageView.getDrawable().getIntrinsicWidth(); + imageView.setMinimumWidth((int) (drawableWidth * mTextSelectSize / mTextUnSelectSize)); + imageView.setMaxWidth(drawableWidth); + } + +// iTabScaleTransformer.setNormalWidth(position, imageView.getDrawable().getIntrinsicWidth(), position == mViewPager.getCurrentItem()); + textView.setVisibility(View.GONE); + } + + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + /** + * position:当前View的位置 + * mCurrentPositionOffset:当前View的偏移量比例.[0,1) + */ + this.mCurrentTab = position; + this.mCurrentPositionOffset = positionOffset; + iTabScaleTransformer.onPageScrolled(position, positionOffset, positionOffsetPixels); + scrollToCurrentTab(); + invalidate(); +// Log.i("onPageScrolled", "mCurrentTab:" + mCurrentTab + " positionOffset:" + positionOffset); + if (this.mCurrentPositionOffset == 0) { + updateTabSelection(mCurrentTab); + } + } + + @Override + public void onPageSelected(int position) { + + } + + @Override + public void onPageScrollStateChanged(int state) { +// if (state == ViewPager.SCROLL_STATE_IDLE) { +// updateTabSelection(mCurrentTab); +// } + } + + /** + * HorizontalScrollView滚到当前tab,并且居中显示 + */ + private void scrollToCurrentTab() { + if (mTabCount <= 0) { + return; + } + + int offset = (int) (mCurrentPositionOffset * mTabsContainer.getChildAt(mCurrentTab).getWidth()); + /**当前Tab的left+当前Tab的Width乘以positionOffset*/ + int newScrollX = mTabsContainer.getChildAt(mCurrentTab).getLeft() + offset; + + if (mCurrentTab > 0 || offset > 0) { + /**HorizontalScrollView移动到当前tab,并居中*/ + newScrollX -= getWidth() / 2 - getPaddingLeft(); + calcIndicatorRect(); + newScrollX += ((mTabRect.right - mTabRect.left) / 2); + } + + if (newScrollX != mLastScrollX) { + mLastScrollX = newScrollX; + /** scrollTo(int x,int y):x,y代表的不是坐标点,而是偏移量 + * x:表示离起始位置的x水平方向的偏移量 + * y:表示离起始位置的y垂直方向的偏移量 + */ + scrollTo(newScrollX, 0); + } + } + + private void updateTabSelection(int position) { + for (int i = 0; i < mTabCount; ++i) { + View tabView = mTabsContainer.getChildAt(i); + final boolean isSelect = i == position; + final TextView tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title); + + if (tab_title != null) { + tab_title.setTextColor(isSelect ? mTextSelectColor : mTextUnSelectColor); + // 设置选中状态 + tab_title.setSelected(isSelect); + + if (mTextBold == TEXT_BOLD_BOTH) { + tab_title.getPaint().setFakeBoldText(true); + } + // 被选中设置为粗体 + else if (mTextBold == TEXT_BOLD_WHEN_SELECT && i == position) { + tab_title.getPaint().setFakeBoldText(true); + } else { + tab_title.getPaint().setFakeBoldText(false); + } + if (isDmgOpen() && (mTextSelectColor != mTextUnSelectColor || mTextBold == TEXT_BOLD_WHEN_SELECT)) { + tab_title.setVisibility(View.VISIBLE); + generateTitleDmg(tabView, tab_title, i); + } else { + final int finalI = i; + tab_title.post(new Runnable() { + @Override + public void run() { + tab_title.setTextSize(TypedValue.COMPLEX_UNIT_PX, finalI == mCurrentTab ? mTextSelectSize : mTextUnSelectSize); + tab_title.requestLayout(); + } + }); + } + } + } + } + + private float margin; + + private void calcIndicatorRect() { + View currentTabView = mTabsContainer.getChildAt(this.mCurrentTab); + float left = currentTabView.getLeft(); + float right = currentTabView.getRight(); + + //for mIndicatorWidthEqualTitle + if (mIndicatorStyle == STYLE_NORMAL && mIndicatorWidthEqualTitle) { + TextView tab_title = currentTabView.findViewById(R.id.tv_tab_title); + float textWidth = mTextPaint.measureText(tab_title.getText().toString()); + margin = (right - left - textWidth) / 2; + } + + if (this.mCurrentTab < mTabCount - 1) { + View nextTabView = mTabsContainer.getChildAt(this.mCurrentTab + 1); + float nextTabLeft = nextTabView.getLeft(); + float nextTabRight = nextTabView.getRight(); + + left = left + mCurrentPositionOffset * (nextTabLeft - left); + right = right + mCurrentPositionOffset * (nextTabRight - right); + + //for mIndicatorWidthEqualTitle + if (mIndicatorStyle == STYLE_NORMAL && mIndicatorWidthEqualTitle) { + TextView next_tab_title = nextTabView.findViewById(R.id.tv_tab_title); + float nextTextWidth = mTextPaint.measureText(next_tab_title.getText().toString()); + float nextMargin = (nextTabRight - nextTabLeft - nextTextWidth) / 2; + margin = margin + mCurrentPositionOffset * (nextMargin - margin); + } + } + + mIndicatorRect.left = (int) left; + mIndicatorRect.right = (int) right; + //for mIndicatorWidthEqualTitle + if (mIndicatorStyle == STYLE_NORMAL && mIndicatorWidthEqualTitle) { + mIndicatorRect.left = (int) (left + margin - 1); + mIndicatorRect.right = (int) (right - margin - 1); + } + + mTabRect.left = (int) left; + mTabRect.right = (int) right; + + if (mIndicatorWidth < 0) { //indicatorWidth小于0时,原jpardogo's PagerSlidingTabStrip + + } else {//indicatorWidth大于0时,圆角矩形以及三角形 + float indicatorLeft = currentTabView.getLeft() + (currentTabView.getWidth() - mIndicatorWidth) / 2; + + if (this.mCurrentTab < mTabCount - 1) { + View nextTab = mTabsContainer.getChildAt(this.mCurrentTab + 1); + indicatorLeft = indicatorLeft + mCurrentPositionOffset * (currentTabView.getWidth() / 2 + nextTab.getWidth() / 2); + } + + mIndicatorRect.left = (int) indicatorLeft; + mIndicatorRect.right = (int) (mIndicatorRect.left + mIndicatorWidth); + } + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + if (isInEditMode() || mTabCount <= 0) { + return; + } + + int height = getHeight(); + int paddingLeft = getPaddingLeft(); + // draw divider + if (mDividerWidth > 0) { + mDividerPaint.setStrokeWidth(mDividerWidth); + mDividerPaint.setColor(mDividerColor); + for (int i = 0; i < mTabCount - 1; i++) { + View tab = mTabsContainer.getChildAt(i); + canvas.drawLine(paddingLeft + tab.getRight(), mDividerPadding, paddingLeft + tab.getRight(), height - mDividerPadding, mDividerPaint); + } + } + + // draw underline + if (mUnderlineHeight > 0) { + mRectPaint.setColor(mUnderlineColor); + if (mUnderlineGravity == Gravity.BOTTOM) { + canvas.drawRect(paddingLeft, height - mUnderlineHeight, mTabsContainer.getWidth() + paddingLeft, height, mRectPaint); + } else { + canvas.drawRect(paddingLeft, 0, mTabsContainer.getWidth() + paddingLeft, mUnderlineHeight, mRectPaint); + } + } + + //draw indicator line + + calcIndicatorRect(); + if (mIndicatorStyle == STYLE_TRIANGLE) { + if (mIndicatorHeight > 0) { + mTrianglePaint.setColor(mIndicatorColor); + mTrianglePath.reset(); + mTrianglePath.moveTo(paddingLeft + mIndicatorRect.left, height); + mTrianglePath.lineTo(paddingLeft + mIndicatorRect.left / 2 + mIndicatorRect.right / 2, height - mIndicatorHeight); + mTrianglePath.lineTo(paddingLeft + mIndicatorRect.right, height); + mTrianglePath.close(); + canvas.drawPath(mTrianglePath, mTrianglePaint); + } + } else if (mIndicatorStyle == STYLE_BLOCK) { + if (mIndicatorHeight < 0) { + mIndicatorHeight = height - mIndicatorMarginTop - mIndicatorMarginBottom; + } else { + + } + + if (mIndicatorHeight > 0) { + if (mIndicatorCornerRadius < 0 || mIndicatorCornerRadius > mIndicatorHeight / 2) { + mIndicatorCornerRadius = mIndicatorHeight / 2; + } + + mIndicatorDrawable.setColor(mIndicatorColor); + mIndicatorDrawable.setBounds(paddingLeft + (int) mIndicatorMarginLeft + mIndicatorRect.left, + (int) mIndicatorMarginTop, (int) (paddingLeft + mIndicatorRect.right - mIndicatorMarginRight), + (int) (mIndicatorMarginTop + mIndicatorHeight)); + mIndicatorDrawable.setCornerRadius(mIndicatorCornerRadius); + mIndicatorDrawable.draw(canvas); + } + } else { + /* mRectPaint.setColor(mIndicatorColor); + calcIndicatorRect(); + canvas.drawRect(getPaddingLeft() + mIndicatorRect.left, getHeight() - mIndicatorHeight, + mIndicatorRect.right + getPaddingLeft(), getHeight(), mRectPaint);*/ + + if (mIndicatorHeight > 0) { + mIndicatorDrawable.setColor(mIndicatorColor); + + if (mIndicatorGravity == Gravity.BOTTOM) { + mIndicatorDrawable.setBounds(paddingLeft + (int) mIndicatorMarginLeft + mIndicatorRect.left, + height - (int) mIndicatorHeight - (int) mIndicatorMarginBottom, + paddingLeft + mIndicatorRect.right - (int) mIndicatorMarginRight, + height - (int) mIndicatorMarginBottom); + } else { + mIndicatorDrawable.setBounds(paddingLeft + (int) mIndicatorMarginLeft + mIndicatorRect.left, + (int) mIndicatorMarginTop, + paddingLeft + mIndicatorRect.right - (int) mIndicatorMarginRight, + (int) mIndicatorHeight + (int) mIndicatorMarginTop); + } + mIndicatorDrawable.setCornerRadius(mIndicatorCornerRadius); + mIndicatorDrawable.draw(canvas); + } + } + } + + //setter and getter + public void setCurrentTab(int currentTab) { + setCurrentTab(currentTab, !mSnapOnTabClick); + } + + public void setCurrentTab(int currentTab, boolean smoothScroll) { + if (mCurrentTab != currentTab) { + this.mCurrentTab = currentTab; + if (mViewPager != null) { + mViewPager.setCurrentItem(currentTab, smoothScroll); + } + + if (mListener != null) { + mListener.onTabSelect(currentTab); + } + } else { + if (mListener != null) { + mListener.onTabReselect(currentTab); + } + } + } + + public void setIndicatorStyle(int indicatorStyle) { + this.mIndicatorStyle = indicatorStyle; + invalidate(); + } + + public void setTabPadding(float tabPadding) { + this.mTabPadding = dp2px(tabPadding); + updateTabStyles(); + } + + public void setTabSpaceEqual(boolean tabSpaceEqual) { + this.mTabSpaceEqual = tabSpaceEqual; + updateTabStyles(); + } + + public void setTabWidth(float tabWidth) { + this.mTabWidth = dp2px(tabWidth); + updateTabStyles(); + } + + public void setIndicatorColor(int indicatorColor) { + this.mIndicatorColor = indicatorColor; + invalidate(); + } + + public void setIndicatorHeight(float indicatorHeight) { + this.mIndicatorHeight = dp2px(indicatorHeight); + invalidate(); + } + + public void setIndicatorWidth(float indicatorWidth) { + this.mIndicatorWidth = dp2px(indicatorWidth); + invalidate(); + } + + public void setIndicatorCornerRadius(float indicatorCornerRadius) { + this.mIndicatorCornerRadius = dp2px(indicatorCornerRadius); + invalidate(); + } + + public void setIndicatorGravity(int indicatorGravity) { + this.mIndicatorGravity = indicatorGravity; + invalidate(); + } + + public void setIndicatorMargin(float indicatorMarginLeft, float indicatorMarginTop, + float indicatorMarginRight, float indicatorMarginBottom) { + this.mIndicatorMarginLeft = dp2px(indicatorMarginLeft); + this.mIndicatorMarginTop = dp2px(indicatorMarginTop); + this.mIndicatorMarginRight = dp2px(indicatorMarginRight); + this.mIndicatorMarginBottom = dp2px(indicatorMarginBottom); + invalidate(); + } + + public void setIndicatorWidthEqualTitle(boolean indicatorWidthEqualTitle) { + this.mIndicatorWidthEqualTitle = indicatorWidthEqualTitle; + invalidate(); + } + + public void setUnderlineColor(int underlineColor) { + this.mUnderlineColor = underlineColor; + invalidate(); + } + + public void setUnderlineHeight(float underlineHeight) { + this.mUnderlineHeight = dp2px(underlineHeight); + invalidate(); + } + + public void setUnderlineGravity(int underlineGravity) { + this.mUnderlineGravity = underlineGravity; + invalidate(); + } + + public void setDividerColor(int dividerColor) { + this.mDividerColor = dividerColor; + invalidate(); + } + + public void setDividerWidth(float dividerWidth) { + this.mDividerWidth = dp2px(dividerWidth); + invalidate(); + } + + public void setDividerPadding(float dividerPadding) { + this.mDividerPadding = dp2px(dividerPadding); + invalidate(); + } + + public void setTextSelectsize(float textsize) { + this.mTextSelectSize = sp2px(textsize); + initTransformer(); + updateTabStyles(); + } + + public void setTextUnselectSize(int textSize) { + this.mTextUnSelectSize = textSize; + initTransformer(); + updateTabStyles(); + } + + public void setTextSelectColor(int textSelectColor) { + this.mTextSelectColor = textSelectColor; + updateTabStyles(); + } + + public void setTextUnselectColor(int textUnselectColor) { + this.mTextUnSelectColor = textUnselectColor; + updateTabStyles(); + } + + public void setTextBold(int textBold) { + this.mTextBold = textBold; + updateTabStyles(); + } + + public void setTextAllCaps(boolean textAllCaps) { + this.mTextAllCaps = textAllCaps; + updateTabStyles(); + } + + public void setSnapOnTabClick(boolean snapOnTabClick) { + mSnapOnTabClick = snapOnTabClick; + } + + + public int getTabCount() { + return mTabCount; + } + + public int getCurrentTab() { + return mCurrentTab; + } + + public int getIndicatorStyle() { + return mIndicatorStyle; + } + + public float getTabPadding() { + return mTabPadding; + } + + public boolean isTabSpaceEqual() { + return mTabSpaceEqual; + } + + public float getTabWidth() { + return mTabWidth; + } + + public int getIndicatorColor() { + return mIndicatorColor; + } + + public float getIndicatorHeight() { + return mIndicatorHeight; + } + + public float getIndicatorWidth() { + return mIndicatorWidth; + } + + public float getIndicatorCornerRadius() { + return mIndicatorCornerRadius; + } + + public float getIndicatorMarginLeft() { + return mIndicatorMarginLeft; + } + + public float getIndicatorMarginTop() { + return mIndicatorMarginTop; + } + + public float getIndicatorMarginRight() { + return mIndicatorMarginRight; + } + + public float getIndicatorMarginBottom() { + return mIndicatorMarginBottom; + } + + public int getUnderlineColor() { + return mUnderlineColor; + } + + public float getUnderlineHeight() { + return mUnderlineHeight; + } + + public int getDividerColor() { + return mDividerColor; + } + + public float getDividerWidth() { + return mDividerWidth; + } + + public float getDividerPadding() { + return mDividerPadding; + } + + public float getTextSelectSize() { + return mTextSelectSize; + } + + public float getTextUnselectSize() { + return mTextUnSelectSize; + } + + public int getTextSelectColor() { + return mTextSelectColor; + } + + public int getTextUnselectColor() { + return mTextUnSelectColor; + } + + public int getTextBold() { + return mTextBold; + } + + public boolean isTextAllCaps() { + return mTextAllCaps; + } + + public void addViewPagerTransformer(IViewPagerTransformer transformer) { + this.extendTransformer.addViewPagerTransformer(transformer); + } + + public void removeViewPagerTransformer(IViewPagerTransformer transformer) { + this.extendTransformer.removeViewPagerTransformer(transformer); + } + + public List getTransformers() { + return extendTransformer.getTransformers(); + } + + public void setTransformers(List transformers) { + this.extendTransformer.setTransformers(transformers); + } + + public TextView getTitleView(int tab) { + View tabView = mTabsContainer.getChildAt(tab); + return (TextView) tabView.findViewById(R.id.tv_tab_title); + } + + //setter and getter + + // show MsgTipView + private Paint mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private SparseBooleanArray mInitSetMap = new SparseBooleanArray(); + + /** + * 显示未读消息 + * + * @param position 显示tab位置 + * @param num num小于等于0显示红点,num大于0显示数字 + */ + public void showMsg(int position, int num) { + if (position >= mTabCount) { + position = mTabCount - 1; + } + + View tabView = mTabsContainer.getChildAt(position); + MsgView tipView = (MsgView) tabView.findViewById(R.id.rtv_msg_tip); + if (tipView != null) { + UnreadMsgUtils.show(tipView, num); + + RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) tipView.getLayoutParams(); + if (openDmg) { + params.addRule(RelativeLayout.ALIGN_END, R.id.tv_tab_title_dmg); + params.addRule(RelativeLayout.ALIGN_TOP, R.id.tv_tab_title_dmg); + } else { + params.addRule(RelativeLayout.ALIGN_END, R.id.tv_tab_title); + params.addRule(RelativeLayout.ALIGN_TOP, R.id.tv_tab_title); + } + + // 红点的位置 + if (num <= 0) { + params.topMargin = mTabDotMarginTop; + params.rightMargin = mTabDotMarginRight; + } + // 未读数的位置 + else { + params.topMargin = mTabMsgMarginTop; + params.rightMargin = mTabMsgMarginRight; + } + + tipView.setLayoutParams(params); + if (mInitSetMap.get(position)) { + return; + } + mInitSetMap.put(position, true); + } + } + + /** + * 显示未读红点 + * + * @param position 显示tab位置 + */ + public void showDot(int position) { + if (position >= mTabCount) { + position = mTabCount - 1; + } + showMsg(position, 0); + } + + /** + * 隐藏未读消息 + */ + public void hideMsg(int position) { + if (position >= mTabCount) { + position = mTabCount - 1; + } + + View tabView = mTabsContainer.getChildAt(position); + MsgView tipView = (MsgView) tabView.findViewById(R.id.rtv_msg_tip); + if (tipView != null) { + tipView.setVisibility(View.GONE); + } + } + + /** + * 当前类只提供了少许设置未读消息属性的方法,可以通过该方法获取MsgView对象从而各种设置 + */ + public MsgView getMsgView(int position) { + if (position >= mTabCount) { + position = mTabCount - 1; + } + View tabView = mTabsContainer.getChildAt(position); + return (MsgView) tabView.findViewById(R.id.rtv_msg_tip); + } + + /** + * 当前类只提供了少许设置未读消息属性的方法,可以通过该方法获取MsgView对象从而各种设置 + */ + public TextView getTitle(int position) { + if (position >= mTabCount) { + position = mTabCount - 1; + } + View tabView = mTabsContainer.getChildAt(position); + if (tabView == null) { + return null; + } + return (TextView) tabView.findViewById(R.id.tv_tab_title); + } + + public ImageView getDmgView(int position) { + if (position >= mTabCount) { + position = mTabCount - 1; + } + View tabView = mTabsContainer.getChildAt(position); + if (tabView == null) { + return null; + } + +// if (tabView.getVisibility() != View.GONE) { +// return null; +// } + + return (ImageView) tabView.findViewById(R.id.tv_tab_title_dmg); + } + + private OnTabSelectListener mListener; + + public void setOnTabSelectListener(OnTabSelectListener listener) { + this.mListener = listener; + } + + class InnerPagerAdapter extends FragmentPagerAdapter { + private ArrayList fragments; + private String[] titles; + + public InnerPagerAdapter(FragmentManager fm, ArrayList fragments, String[] titles) { + super(fm); + this.fragments = fragments; + this.titles = titles; + } + + @Override + public int getCount() { + return fragments.size(); + } + + @Override + public CharSequence getPageTitle(int position) { + return titles[position]; + } + + @Override + public Fragment getItem(int position) { + return fragments.get(position); + } + + @Override + public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) { + // 覆写destroyItem并且空实现,这样每个Fragment中的视图就不会被销毁 + // super.destroyItem(container, position, object); + } + + @Override + public int getItemPosition(@NonNull Object object) { + return PagerAdapter.POSITION_NONE; + } + } + + @Override + protected Parcelable onSaveInstanceState() { + Bundle bundle = new Bundle(); + bundle.putParcelable("instanceState", super.onSaveInstanceState()); + bundle.putInt("mCurrentTab", mCurrentTab); + return bundle; + } + + @Override + protected void onRestoreInstanceState(Parcelable state) { + if (state instanceof Bundle) { + Bundle bundle = (Bundle) state; + mCurrentTab = bundle.getInt("mCurrentTab"); + state = bundle.getParcelable("instanceState"); + if (mCurrentTab != 0 && mTabsContainer.getChildCount() > 0) { + updateTabSelection(mCurrentTab); + scrollToCurrentTab(); + } + } + super.onRestoreInstanceState(state); + } + + protected int dp2px(float dp) { + final float scale = mContext.getResources().getDisplayMetrics().density; + return (int) (dp * scale + 0.5f); + } + + protected int sp2px(float sp) { + final float scale = this.mContext.getResources().getDisplayMetrics().scaledDensity; + return (int) (sp * scale + 0.5f); + } +} diff --git a/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/SlidingTabLayout.java b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/SlidingTabLayout.java new file mode 100644 index 0000000..d1f9330 --- /dev/null +++ b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/SlidingTabLayout.java @@ -0,0 +1,1011 @@ +package com.flyco.tablayout; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.Rect; +import android.graphics.drawable.GradientDrawable; +import android.os.Bundle; +import android.os.Parcelable; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentPagerAdapter; +import androidx.viewpager.widget.PagerAdapter; +import androidx.viewpager.widget.ViewPager; +import android.util.AttributeSet; +import android.util.SparseBooleanArray; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.HorizontalScrollView; +import android.widget.LinearLayout; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import com.flyco.tablayout.listener.OnTabSelectListener; +import com.flyco.tablayout.utils.UnreadMsgUtils; +import com.flyco.tablayout.widget.MsgView; + +import java.util.ArrayList; +import java.util.Collections; + +/** + * 滑动TabLayout,对于ViewPager的依赖性强 + */ +public class SlidingTabLayout extends HorizontalScrollView implements ViewPager.OnPageChangeListener { + + private static final int TOP = 0; + private static final int BOTTOM = 1; + private static final int CENTER = 2; + + private Context mContext; + private ViewPager mViewPager; + private ArrayList mTitles; + private LinearLayout mTabsContainer; + private int mCurrentTab; + private float mCurrentPositionOffset; + private int mTabCount; + /** + * 用于绘制显示器 + */ + private Rect mIndicatorRect = new Rect(); + /** + * 用于实现滚动居中 + */ + private Rect mTabRect = new Rect(); + private GradientDrawable mIndicatorDrawable = new GradientDrawable(); + + private Paint mRectPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private Paint mDividerPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private Paint mTrianglePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private Path mTrianglePath = new Path(); + private static final int STYLE_NORMAL = 0; + private static final int STYLE_TRIANGLE = 1; + private static final int STYLE_BLOCK = 2; + private int mIndicatorStyle = STYLE_NORMAL; + + private float mTabPadding; + private boolean mTabSpaceEqual; + private float mTabWidth; + + /** + * indicator + */ + private int mIndicatorColor; + private float mIndicatorHeight; + private float mIndicatorWidth; + private float mIndicatorCornerRadius; + private float mIndicatorMarginLeft; + private float mIndicatorMarginTop; + private float mIndicatorMarginRight; + private float mIndicatorMarginBottom; + private int mIndicatorGravity; + private boolean mIndicatorWidthEqualTitle; + + /** + * underline + */ + private int mUnderlineColor; + private float mUnderlineHeight; + private int mUnderlineGravity; + + /** + * divider + */ + private int mDividerColor; + private float mDividerWidth; + private float mDividerPadding; + + /** + * title + */ + private static final int TEXT_BOLD_NONE = 0; + private static final int TEXT_BOLD_WHEN_SELECT = 1; + private static final int TEXT_BOLD_BOTH = 2; + private float mTextSelectSize; + private float mTextUnSelectSize; + private int mTextSelectColor; + private int mTextUnSelectColor; + private int mTextBold; + private boolean mTextAllCaps; + + private int mLastScrollX; + private int mHeight; + private boolean mSnapOnTabClick; + + /** + * tab的上下间距 + */ + private int mTabMarginTop; + private int mTabMarginBottom; + + /** + * tab摆放的位置,目前只支持top和bottom + */ + private int mTabGravity; + + public SlidingTabLayout(Context context) { + this(context, null, 0); + } + + public SlidingTabLayout(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public SlidingTabLayout(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + setFillViewport(true);//设置滚动视图是否可以伸缩其内容以填充视口 + setWillNotDraw(false);//重写onDraw方法,需要调用这个方法来清除flag + setClipChildren(false); + setClipToPadding(false); + + this.mContext = context; + mTabsContainer = new LinearLayout(context); + addView(mTabsContainer); + + obtainAttributes(context, attrs); + + //get layout_height + String height = attrs.getAttributeValue("http://schemas.android.com/apk/res/android", "layout_height"); + + if (height.equals(ViewGroup.LayoutParams.MATCH_PARENT + "")) { + } else if (height.equals(ViewGroup.LayoutParams.WRAP_CONTENT + "")) { + } else { + int[] systemAttrs = {android.R.attr.layout_height}; + TypedArray a = context.obtainStyledAttributes(attrs, systemAttrs); + mHeight = a.getDimensionPixelSize(0, ViewGroup.LayoutParams.WRAP_CONTENT); + a.recycle(); + } + } + + private void obtainAttributes(Context context, AttributeSet attrs) { + TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.SlidingTabLayout); + + mIndicatorStyle = ta.getInt(R.styleable.SlidingTabLayout_tl_indicator_style, STYLE_NORMAL); + mIndicatorColor = ta.getColor(R.styleable.SlidingTabLayout_tl_indicator_color, Color.parseColor(mIndicatorStyle == STYLE_BLOCK ? "#4B6A87" : "#ffffff")); + mIndicatorHeight = ta.getDimension(R.styleable.SlidingTabLayout_tl_indicator_height, + dp2px(mIndicatorStyle == STYLE_TRIANGLE ? 4 : (mIndicatorStyle == STYLE_BLOCK ? -1 : 2))); + mIndicatorWidth = ta.getDimension(R.styleable.SlidingTabLayout_tl_indicator_width, dp2px(mIndicatorStyle == STYLE_TRIANGLE ? 10 : -1)); + mIndicatorCornerRadius = ta.getDimension(R.styleable.SlidingTabLayout_tl_indicator_corner_radius, dp2px(mIndicatorStyle == STYLE_BLOCK ? -1 : 0)); + mIndicatorMarginLeft = ta.getDimension(R.styleable.SlidingTabLayout_tl_indicator_margin_left, dp2px(0)); + mIndicatorMarginTop = ta.getDimension(R.styleable.SlidingTabLayout_tl_indicator_margin_top, dp2px(mIndicatorStyle == STYLE_BLOCK ? 7 : 0)); + mIndicatorMarginRight = ta.getDimension(R.styleable.SlidingTabLayout_tl_indicator_margin_right, dp2px(0)); + mIndicatorMarginBottom = ta.getDimension(R.styleable.SlidingTabLayout_tl_indicator_margin_bottom, dp2px(mIndicatorStyle == STYLE_BLOCK ? 7 : 0)); + mIndicatorGravity = ta.getInt(R.styleable.SlidingTabLayout_tl_indicator_gravity, Gravity.BOTTOM); + mIndicatorWidthEqualTitle = ta.getBoolean(R.styleable.SlidingTabLayout_tl_indicator_width_equal_title, false); + + mUnderlineColor = ta.getColor(R.styleable.SlidingTabLayout_tl_underline_color, Color.parseColor("#ffffff")); + mUnderlineHeight = ta.getDimension(R.styleable.SlidingTabLayout_tl_underline_height, dp2px(0)); + mUnderlineGravity = ta.getInt(R.styleable.SlidingTabLayout_tl_underline_gravity, Gravity.BOTTOM); + + mDividerColor = ta.getColor(R.styleable.SlidingTabLayout_tl_divider_color, Color.parseColor("#ffffff")); + mDividerWidth = ta.getDimension(R.styleable.SlidingTabLayout_tl_divider_width, dp2px(0)); + mDividerPadding = ta.getDimension(R.styleable.SlidingTabLayout_tl_divider_padding, dp2px(12)); + + mTextSelectSize = ta.getDimension(R.styleable.SlidingTabLayout_tl_textSelectSize, sp2px(14)); + mTextUnSelectSize = ta.getDimension(R.styleable.SlidingTabLayout_tl_textUnSelectSize, sp2px(14)); + mTextSelectColor = ta.getColor(R.styleable.SlidingTabLayout_tl_textSelectColor, Color.parseColor("#ffffff")); + mTextUnSelectColor = ta.getColor(R.styleable.SlidingTabLayout_tl_textUnSelectColor, Color.parseColor("#AAffffff")); + mTextBold = ta.getInt(R.styleable.SlidingTabLayout_tl_textBold, TEXT_BOLD_NONE); + mTextAllCaps = ta.getBoolean(R.styleable.SlidingTabLayout_tl_textAllCaps, false); + + mTabSpaceEqual = ta.getBoolean(R.styleable.SlidingTabLayout_tl_tab_space_equal, false); + mTabWidth = ta.getDimension(R.styleable.SlidingTabLayout_tl_tab_width, dp2px(-1)); + mTabPadding = ta.getDimension(R.styleable.SlidingTabLayout_tl_tab_padding, mTabSpaceEqual || mTabWidth > 0 ? dp2px(0) : dp2px(20)); + // 得到设置的上下间距和gravity + mTabMarginTop = ta.getDimensionPixelSize(R.styleable.SlidingTabLayout_tl_tab_marginTop, 0); + mTabMarginBottom = ta.getDimensionPixelSize(R.styleable.SlidingTabLayout_tl_tab_marginBottom, 0); + mTabGravity = ta.getInt(R.styleable.SlidingTabLayout_tl_tab_gravity, CENTER); + + ta.recycle(); + } + + /** + * 关联ViewPager + */ + public void setViewPager(ViewPager vp) { + if (vp == null || vp.getAdapter() == null) { + throw new IllegalStateException("ViewPager or ViewPager adapter can not be NULL !"); + } + + this.mViewPager = vp; + + this.mViewPager.removeOnPageChangeListener(this); + this.mViewPager.addOnPageChangeListener(this); + notifyDataSetChanged(); + } + + /** + * 关联ViewPager,用于不想在ViewPager适配器中设置titles数据的情况 + */ + public void setTitle(String[] titles) { + if (titles == null || titles.length == 0) { + throw new IllegalStateException("Titles can not be EMPTY !"); + } + + mTitles = new ArrayList<>(); + Collections.addAll(mTitles, titles); + notifyDataSetChanged(); + } + + /** + * 关联ViewPager,用于不想在ViewPager适配器中设置titles数据的情况 + */ + public void setViewPager(ViewPager vp, String[] titles) { + if (vp == null || vp.getAdapter() == null) { + throw new IllegalStateException("ViewPager or ViewPager adapter can not be NULL !"); + } + + if (titles == null || titles.length == 0) { + throw new IllegalStateException("Titles can not be EMPTY !"); + } + + if (titles.length != vp.getAdapter().getCount()) { + throw new IllegalStateException("Titles length must be the same as the page count !"); + } + + this.mViewPager = vp; + mTitles = new ArrayList<>(); + Collections.addAll(mTitles, titles); + + this.mViewPager.removeOnPageChangeListener(this); + this.mViewPager.addOnPageChangeListener(this); + notifyDataSetChanged(); + } + + /** + * 关联ViewPager,用于连适配器都不想自己实例化的情况 + */ + public void setViewPager(ViewPager vp, String[] titles, FragmentActivity fa, ArrayList fragments) { + if (vp == null) { + throw new IllegalStateException("ViewPager can not be NULL !"); + } + + if (titles == null || titles.length == 0) { + throw new IllegalStateException("Titles can not be EMPTY !"); + } + + this.mViewPager = vp; + this.mViewPager.setAdapter(new InnerPagerAdapter(fa.getSupportFragmentManager(), fragments, titles)); + + this.mViewPager.removeOnPageChangeListener(this); + this.mViewPager.addOnPageChangeListener(this); + notifyDataSetChanged(); + } + + /** + * 更新数据 + */ + public void notifyDataSetChanged() { + mTabsContainer.removeAllViews(); + this.mTabCount = mTitles == null ? mViewPager.getAdapter().getCount() : mTitles.size(); + View tabView; + for (int i = 0; i < mTabCount; i++) { + tabView = View.inflate(mContext, R.layout.layout_tab, null); + TextView title = tabView.findViewById(R.id.tv_tab_title); + // 设置tab的位置信息 + setTabLayoutParams(title); + CharSequence pageTitle = mTitles == null ? mViewPager.getAdapter().getPageTitle(i) : mTitles.get(i); + addTab(i, pageTitle.toString(), tabView); + } + + updateTabStyles(); + } + + private void setTabLayoutParams(TextView title) { + RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) title.getLayoutParams(); + params.topMargin = mTabMarginTop; + params.bottomMargin = mTabMarginBottom; + if (mTabGravity == TOP) { + params.addRule(RelativeLayout.ALIGN_PARENT_TOP); + } else if (mTabGravity == BOTTOM) { + params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM); + } else { + params.addRule(RelativeLayout.CENTER_VERTICAL); + } + title.setLayoutParams(params); + } + + public void addNewTab(String title) { + View tabView = View.inflate(mContext, R.layout.layout_tab, null); + if (mTitles != null) { + mTitles.add(title); + } + + CharSequence pageTitle = mTitles == null ? mViewPager.getAdapter().getPageTitle(mTabCount) : mTitles.get(mTabCount); + addTab(mTabCount, pageTitle.toString(), tabView); + this.mTabCount = mTitles == null ? mViewPager.getAdapter().getCount() : mTitles.size(); + + updateTabStyles(); + } + + /** + * 创建并添加tab + */ + private void addTab(final int position, String title, View tabView) { + TextView tv_tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title); + if (tv_tab_title != null) { + if (title != null) tv_tab_title.setText(title); + } + + tabView.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + int position = mTabsContainer.indexOfChild(v); + if (position != -1) { + setCurrentTab(position); + } + } + }); + + /** 每一个Tab的布局参数 */ + LinearLayout.LayoutParams lp_tab = mTabSpaceEqual ? + new LinearLayout.LayoutParams(0, LayoutParams.MATCH_PARENT, 1.0f) : + new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT); + if (mTabWidth > 0) { + lp_tab = new LinearLayout.LayoutParams((int) mTabWidth, LayoutParams.MATCH_PARENT); + } + mTabsContainer.addView(tabView, position, lp_tab); + } + + private void updateTabStyles() { + for (int i = 0; i < mTabCount; i++) { + View v = mTabsContainer.getChildAt(i); +// v.setPadding((int) mTabPadding, v.getPaddingTop(), (int) mTabPadding, v.getPaddingBottom()); + TextView tv_tab_title = (TextView) v.findViewById(R.id.tv_tab_title); + if (tv_tab_title != null) { + tv_tab_title.setTextColor(i == mCurrentTab ? mTextSelectColor : mTextUnSelectColor); + tv_tab_title.setTextSize(TypedValue.COMPLEX_UNIT_PX, i == mCurrentTab ? mTextSelectSize : mTextUnSelectSize); + tv_tab_title.setPadding((int) mTabPadding, 0, (int) mTabPadding, 0); + if (mTextAllCaps) { + tv_tab_title.setText(tv_tab_title.getText().toString().toUpperCase()); + } + + if (mTextBold == TEXT_BOLD_BOTH) { + tv_tab_title.getPaint().setFakeBoldText(true); + } + // 被选中设置为粗体 + else if (mTextBold == TEXT_BOLD_WHEN_SELECT && i == mCurrentTab) { + tv_tab_title.getPaint().setFakeBoldText(true); + } else if (mTextBold == TEXT_BOLD_NONE) { + tv_tab_title.getPaint().setFakeBoldText(false); + } + } + } + } + + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + /** + * position:当前View的位置 + * mCurrentPositionOffset:当前View的偏移量比例.[0,1) + */ + this.mCurrentTab = position; + this.mCurrentPositionOffset = positionOffset; + scrollToCurrentTab(); + invalidate(); + } + + @Override + public void onPageSelected(int position) { + updateTabSelection(position); + } + + @Override + public void onPageScrollStateChanged(int state) { + } + + /** + * HorizontalScrollView滚到当前tab,并且居中显示 + */ + private void scrollToCurrentTab() { + if (mTabCount <= 0) { + return; + } + + int offset = (int) (mCurrentPositionOffset * mTabsContainer.getChildAt(mCurrentTab).getWidth()); + /**当前Tab的left+当前Tab的Width乘以positionOffset*/ + int newScrollX = mTabsContainer.getChildAt(mCurrentTab).getLeft() + offset; + + if (mCurrentTab > 0 || offset > 0) { + /**HorizontalScrollView移动到当前tab,并居中*/ + newScrollX -= getWidth() / 2 - getPaddingLeft(); + calcIndicatorRect(); + newScrollX += ((mTabRect.right - mTabRect.left) / 2); + } + + if (newScrollX != mLastScrollX) { + mLastScrollX = newScrollX; + /** scrollTo(int x,int y):x,y代表的不是坐标点,而是偏移量 + * x:表示离起始位置的x水平方向的偏移量 + * y:表示离起始位置的y垂直方向的偏移量 + */ + scrollTo(newScrollX, 0); + } + } + + private void updateTabSelection(int position) { + for (int i = 0; i < mTabCount; ++i) { + View tabView = mTabsContainer.getChildAt(i); + final boolean isSelect = i == position; + TextView tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title); + + if (tab_title != null) { + tab_title.setTextColor(isSelect ? mTextSelectColor : mTextUnSelectColor); + tab_title.setTextSize(TypedValue.COMPLEX_UNIT_PX, isSelect ? mTextSelectSize : mTextUnSelectSize); + if (mTextBold == TEXT_BOLD_WHEN_SELECT) { + tab_title.getPaint().setFakeBoldText(isSelect); + } + } + } + } + + private float margin; + + private void calcIndicatorRect() { + View currentTabView = mTabsContainer.getChildAt(this.mCurrentTab); + float left = currentTabView.getLeft(); + float right = currentTabView.getRight(); + + //for mIndicatorWidthEqualTitle + if (mIndicatorStyle == STYLE_NORMAL && mIndicatorWidthEqualTitle) { + TextView tab_title = (TextView) currentTabView.findViewById(R.id.tv_tab_title); + mTextPaint.setTextSize(mTextSelectSize); + float textWidth = mTextPaint.measureText(tab_title.getText().toString()); + margin = (right - left - textWidth) / 2; + } + + if (this.mCurrentTab < mTabCount - 1) { + View nextTabView = mTabsContainer.getChildAt(this.mCurrentTab + 1); + float nextTabLeft = nextTabView.getLeft(); + float nextTabRight = nextTabView.getRight(); + + left = left + mCurrentPositionOffset * (nextTabLeft - left); + right = right + mCurrentPositionOffset * (nextTabRight - right); + + //for mIndicatorWidthEqualTitle + if (mIndicatorStyle == STYLE_NORMAL && mIndicatorWidthEqualTitle) { + TextView next_tab_title = (TextView) nextTabView.findViewById(R.id.tv_tab_title); + mTextPaint.setTextSize(mTextUnSelectSize); + float nextTextWidth = mTextPaint.measureText(next_tab_title.getText().toString()); + float nextMargin = (nextTabRight - nextTabLeft - nextTextWidth) / 2; + margin = margin + mCurrentPositionOffset * (nextMargin - margin); + } + } + + mIndicatorRect.left = (int) left; + mIndicatorRect.right = (int) right; + //for mIndicatorWidthEqualTitle + if (mIndicatorStyle == STYLE_NORMAL && mIndicatorWidthEqualTitle) { + mIndicatorRect.left = (int) (left + margin - 1); + mIndicatorRect.right = (int) (right - margin - 1); + } + + mTabRect.left = (int) left; + mTabRect.right = (int) right; + + if (mIndicatorWidth < 0) { //indicatorWidth小于0时,原jpardogo's PagerSlidingTabStrip + + } else {//indicatorWidth大于0时,圆角矩形以及三角形 + float indicatorLeft = currentTabView.getLeft() + (currentTabView.getWidth() - mIndicatorWidth) / 2; + + if (this.mCurrentTab < mTabCount - 1) { + View nextTab = mTabsContainer.getChildAt(this.mCurrentTab + 1); + indicatorLeft = indicatorLeft + mCurrentPositionOffset * (currentTabView.getWidth() / 2 + nextTab.getWidth() / 2); + } + + mIndicatorRect.left = (int) indicatorLeft; + mIndicatorRect.right = (int) (mIndicatorRect.left + mIndicatorWidth); + } + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + if (isInEditMode() || mTabCount <= 0) { + return; + } + + int height = getHeight(); + int paddingLeft = getPaddingLeft(); + // draw divider + if (mDividerWidth > 0) { + mDividerPaint.setStrokeWidth(mDividerWidth); + mDividerPaint.setColor(mDividerColor); + for (int i = 0; i < mTabCount - 1; i++) { + View tab = mTabsContainer.getChildAt(i); + canvas.drawLine(paddingLeft + tab.getRight(), mDividerPadding, paddingLeft + tab.getRight(), height - mDividerPadding, mDividerPaint); + } + } + + // draw underline + if (mUnderlineHeight > 0) { + mRectPaint.setColor(mUnderlineColor); + if (mUnderlineGravity == Gravity.BOTTOM) { + canvas.drawRect(paddingLeft, height - mUnderlineHeight, mTabsContainer.getWidth() + paddingLeft, height, mRectPaint); + } else { + canvas.drawRect(paddingLeft, 0, mTabsContainer.getWidth() + paddingLeft, mUnderlineHeight, mRectPaint); + } + } + + //draw indicator line + + calcIndicatorRect(); + if (mIndicatorStyle == STYLE_TRIANGLE) { + if (mIndicatorHeight > 0) { + mTrianglePaint.setColor(mIndicatorColor); + mTrianglePath.reset(); + mTrianglePath.moveTo(paddingLeft + mIndicatorRect.left, height); + mTrianglePath.lineTo(paddingLeft + mIndicatorRect.left / 2 + mIndicatorRect.right / 2, height - mIndicatorHeight); + mTrianglePath.lineTo(paddingLeft + mIndicatorRect.right, height); + mTrianglePath.close(); + canvas.drawPath(mTrianglePath, mTrianglePaint); + } + } else if (mIndicatorStyle == STYLE_BLOCK) { + if (mIndicatorHeight < 0) { + mIndicatorHeight = height - mIndicatorMarginTop - mIndicatorMarginBottom; + } else { + + } + + if (mIndicatorHeight > 0) { + if (mIndicatorCornerRadius < 0 || mIndicatorCornerRadius > mIndicatorHeight / 2) { + mIndicatorCornerRadius = mIndicatorHeight / 2; + } + + mIndicatorDrawable.setColor(mIndicatorColor); + mIndicatorDrawable.setBounds(paddingLeft + (int) mIndicatorMarginLeft + mIndicatorRect.left, + (int) mIndicatorMarginTop, (int) (paddingLeft + mIndicatorRect.right - mIndicatorMarginRight), + (int) (mIndicatorMarginTop + mIndicatorHeight)); + mIndicatorDrawable.setCornerRadius(mIndicatorCornerRadius); + mIndicatorDrawable.draw(canvas); + } + } else { + /* mRectPaint.setColor(mIndicatorColor); + calcIndicatorRect(); + canvas.drawRect(getPaddingLeft() + mIndicatorRect.left, getHeight() - mIndicatorHeight, + mIndicatorRect.right + getPaddingLeft(), getHeight(), mRectPaint);*/ + + if (mIndicatorHeight > 0) { + mIndicatorDrawable.setColor(mIndicatorColor); + + if (mIndicatorGravity == Gravity.BOTTOM) { + mIndicatorDrawable.setBounds(paddingLeft + (int) mIndicatorMarginLeft + mIndicatorRect.left, + height - (int) mIndicatorHeight - (int) mIndicatorMarginBottom, + paddingLeft + mIndicatorRect.right - (int) mIndicatorMarginRight, + height - (int) mIndicatorMarginBottom); + } else { + mIndicatorDrawable.setBounds(paddingLeft + (int) mIndicatorMarginLeft + mIndicatorRect.left, + (int) mIndicatorMarginTop, + paddingLeft + mIndicatorRect.right - (int) mIndicatorMarginRight, + (int) mIndicatorHeight + (int) mIndicatorMarginTop); + } + mIndicatorDrawable.setCornerRadius(mIndicatorCornerRadius); + mIndicatorDrawable.draw(canvas); + } + } + } + + //setter and getter + public void setCurrentTab(int currentTab) { + setCurrentTab(currentTab, !mSnapOnTabClick); + } + + public void setCurrentTab(int currentTab, boolean smoothScroll) { + if (mCurrentTab!= currentTab) { + this.mCurrentTab = currentTab; + if (mViewPager != null){ + mViewPager.setCurrentItem(currentTab, smoothScroll); + } + + if (mListener != null) { + mListener.onTabSelect(currentTab); + } + } else { + if (mListener != null) { + mListener.onTabReselect(currentTab); + } + } + } + + public void setIndicatorStyle(int indicatorStyle) { + this.mIndicatorStyle = indicatorStyle; + invalidate(); + } + + public void setTabPadding(float tabPadding) { + this.mTabPadding = dp2px(tabPadding); + updateTabStyles(); + } + + public void setTabSpaceEqual(boolean tabSpaceEqual) { + this.mTabSpaceEqual = tabSpaceEqual; + updateTabStyles(); + } + + public void setTabWidth(float tabWidth) { + this.mTabWidth = dp2px(tabWidth); + updateTabStyles(); + } + + public void setIndicatorColor(int indicatorColor) { + this.mIndicatorColor = indicatorColor; + invalidate(); + } + + public void setIndicatorHeight(float indicatorHeight) { + this.mIndicatorHeight = dp2px(indicatorHeight); + invalidate(); + } + + public void setIndicatorWidth(float indicatorWidth) { + this.mIndicatorWidth = dp2px(indicatorWidth); + invalidate(); + } + + public void setIndicatorCornerRadius(float indicatorCornerRadius) { + this.mIndicatorCornerRadius = dp2px(indicatorCornerRadius); + invalidate(); + } + + public void setIndicatorGravity(int indicatorGravity) { + this.mIndicatorGravity = indicatorGravity; + invalidate(); + } + + public void setIndicatorMargin(float indicatorMarginLeft, float indicatorMarginTop, + float indicatorMarginRight, float indicatorMarginBottom) { + this.mIndicatorMarginLeft = dp2px(indicatorMarginLeft); + this.mIndicatorMarginTop = dp2px(indicatorMarginTop); + this.mIndicatorMarginRight = dp2px(indicatorMarginRight); + this.mIndicatorMarginBottom = dp2px(indicatorMarginBottom); + invalidate(); + } + + public void setIndicatorWidthEqualTitle(boolean indicatorWidthEqualTitle) { + this.mIndicatorWidthEqualTitle = indicatorWidthEqualTitle; + invalidate(); + } + + public void setUnderlineColor(int underlineColor) { + this.mUnderlineColor = underlineColor; + invalidate(); + } + + public void setUnderlineHeight(float underlineHeight) { + this.mUnderlineHeight = dp2px(underlineHeight); + invalidate(); + } + + public void setUnderlineGravity(int underlineGravity) { + this.mUnderlineGravity = underlineGravity; + invalidate(); + } + + public void setDividerColor(int dividerColor) { + this.mDividerColor = dividerColor; + invalidate(); + } + + public void setDividerWidth(float dividerWidth) { + this.mDividerWidth = dp2px(dividerWidth); + invalidate(); + } + + public void setDividerPadding(float dividerPadding) { + this.mDividerPadding = dp2px(dividerPadding); + invalidate(); + } + + public void setTextSelectsize(float textsize) { + this.mTextSelectSize = sp2px(textsize); + updateTabStyles(); + } + + public void setTextUnselectSize(int textSize) { + this.mTextUnSelectSize = textSize; + updateTabStyles(); + } + + public void setTextSelectColor(int textSelectColor) { + this.mTextSelectColor = textSelectColor; + updateTabStyles(); + } + + public void setTextUnselectColor(int textUnselectColor) { + this.mTextUnSelectColor = textUnselectColor; + updateTabStyles(); + } + + public void setTextBold(int textBold) { + this.mTextBold = textBold; + updateTabStyles(); + } + + public void setTextAllCaps(boolean textAllCaps) { + this.mTextAllCaps = textAllCaps; + updateTabStyles(); + } + + public void setSnapOnTabClick(boolean snapOnTabClick) { + mSnapOnTabClick = snapOnTabClick; + } + + + public int getTabCount() { + return mTabCount; + } + + public int getCurrentTab() { + return mCurrentTab; + } + + public int getIndicatorStyle() { + return mIndicatorStyle; + } + + public float getTabPadding() { + return mTabPadding; + } + + public boolean isTabSpaceEqual() { + return mTabSpaceEqual; + } + + public float getTabWidth() { + return mTabWidth; + } + + public int getIndicatorColor() { + return mIndicatorColor; + } + + public float getIndicatorHeight() { + return mIndicatorHeight; + } + + public float getIndicatorWidth() { + return mIndicatorWidth; + } + + public float getIndicatorCornerRadius() { + return mIndicatorCornerRadius; + } + + public float getIndicatorMarginLeft() { + return mIndicatorMarginLeft; + } + + public float getIndicatorMarginTop() { + return mIndicatorMarginTop; + } + + public float getIndicatorMarginRight() { + return mIndicatorMarginRight; + } + + public float getIndicatorMarginBottom() { + return mIndicatorMarginBottom; + } + + public int getUnderlineColor() { + return mUnderlineColor; + } + + public float getUnderlineHeight() { + return mUnderlineHeight; + } + + public int getDividerColor() { + return mDividerColor; + } + + public float getDividerWidth() { + return mDividerWidth; + } + + public float getDividerPadding() { + return mDividerPadding; + } + + public float getTextSelectSize() { + return mTextSelectSize; + } + + public float getTextUnselectSize() { + return mTextUnSelectSize; + } + + public int getTextSelectColor() { + return mTextSelectColor; + } + + public int getTextUnselectColor() { + return mTextUnSelectColor; + } + + public int getTextBold() { + return mTextBold; + } + + public boolean isTextAllCaps() { + return mTextAllCaps; + } + + public TextView getTitleView(int tab) { + View tabView = mTabsContainer.getChildAt(tab); + return (TextView) tabView.findViewById(R.id.tv_tab_title); + } + + //setter and getter + + // show MsgTipView + private Paint mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private SparseBooleanArray mInitSetMap = new SparseBooleanArray(); + + /** + * 显示未读消息 + * + * @param position 显示tab位置 + * @param num num小于等于0显示红点,num大于0显示数字 + */ + public void showMsg(int position, int num) { + if (position >= mTabCount) { + position = mTabCount - 1; + } + + View tabView = mTabsContainer.getChildAt(position); + MsgView tipView = (MsgView) tabView.findViewById(R.id.rtv_msg_tip); + if (tipView != null) { + UnreadMsgUtils.show(tipView, num); + + if (mInitSetMap.get(position)) { + return; + } + + setMsgMargin(position, 4, 2); + mInitSetMap.put(position, true); + } + } + + /** + * 显示未读红点 + * + * @param position 显示tab位置 + */ + public void showDot(int position) { + if (position >= mTabCount) { + position = mTabCount - 1; + } + showMsg(position, 0); + } + + /** + * 隐藏未读消息 + */ + public void hideMsg(int position) { + if (position >= mTabCount) { + position = mTabCount - 1; + } + + View tabView = mTabsContainer.getChildAt(position); + MsgView tipView = (MsgView) tabView.findViewById(R.id.rtv_msg_tip); + if (tipView != null) { + tipView.setVisibility(View.GONE); + } + } + + /** + * 设置未读消息偏移,原点为文字的右上角.当控件高度固定,消息提示位置易控制,显示效果佳 + */ + public void setMsgMargin(int position, float leftPadding, float bottomPadding) { + if (position >= mTabCount) { + position = mTabCount - 1; + } + View tabView = mTabsContainer.getChildAt(position); + MsgView tipView = (MsgView) tabView.findViewById(R.id.rtv_msg_tip); + if (tipView != null) { + TextView tv_tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title); + mTextPaint.setTextSize(position == mCurrentTab ? mTextSelectSize : mTextUnSelectSize); + float textWidth = mTextPaint.measureText(tv_tab_title.getText().toString()); + float textHeight = mTextPaint.descent() - mTextPaint.ascent(); + MarginLayoutParams lp = (MarginLayoutParams) tipView.getLayoutParams(); + lp.leftMargin = mTabWidth >= 0 ? (int) (mTabWidth / 2 + textWidth / 2 + dp2px(leftPadding)) : (int) (mTabPadding + textWidth + dp2px(leftPadding)); + lp.topMargin = mHeight > 0 ? (int) (mHeight - textHeight) / 2 - dp2px(bottomPadding) : 0; + tipView.setLayoutParams(lp); + } + } + + /** + * 当前类只提供了少许设置未读消息属性的方法,可以通过该方法获取MsgView对象从而各种设置 + */ + public MsgView getMsgView(int position) { + if (position >= mTabCount) { + position = mTabCount - 1; + } + View tabView = mTabsContainer.getChildAt(position); + MsgView tipView = (MsgView) tabView.findViewById(R.id.rtv_msg_tip); + return tipView; + } + + private OnTabSelectListener mListener; + + public void setOnTabSelectListener(OnTabSelectListener listener) { + this.mListener = listener; + } + + class InnerPagerAdapter extends FragmentPagerAdapter { + private ArrayList fragments; + private String[] titles; + + public InnerPagerAdapter(FragmentManager fm, ArrayList fragments, String[] titles) { + super(fm); + this.fragments = fragments; + this.titles = titles; + } + + @Override + public int getCount() { + return fragments.size(); + } + + @Override + public CharSequence getPageTitle(int position) { + return titles[position]; + } + + @Override + public Fragment getItem(int position) { + return fragments.get(position); + } + + @Override + public void destroyItem(ViewGroup container, int position, Object object) { + // 覆写destroyItem并且空实现,这样每个Fragment中的视图就不会被销毁 + // super.destroyItem(container, position, object); + } + + @Override + public int getItemPosition(Object object) { + return PagerAdapter.POSITION_NONE; + } + } + + @Override + protected Parcelable onSaveInstanceState() { + Bundle bundle = new Bundle(); + bundle.putParcelable("instanceState", super.onSaveInstanceState()); + bundle.putInt("mCurrentTab", mCurrentTab); + return bundle; + } + + @Override + protected void onRestoreInstanceState(Parcelable state) { + if (state instanceof Bundle) { + Bundle bundle = (Bundle) state; + mCurrentTab = bundle.getInt("mCurrentTab"); + state = bundle.getParcelable("instanceState"); + if (mCurrentTab != 0 && mTabsContainer.getChildCount() > 0) { + updateTabSelection(mCurrentTab); + scrollToCurrentTab(); + } + } + super.onRestoreInstanceState(state); + } + + protected int dp2px(float dp) { + final float scale = mContext.getResources().getDisplayMetrics().density; + return (int) (dp * scale + 0.5f); + } + + protected int sp2px(float sp) { + final float scale = this.mContext.getResources().getDisplayMetrics().scaledDensity; + return (int) (sp * scale + 0.5f); + } +} diff --git a/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/listener/CustomTabEntity.java b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/listener/CustomTabEntity.java new file mode 100644 index 0000000..ee39fe7 --- /dev/null +++ b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/listener/CustomTabEntity.java @@ -0,0 +1,13 @@ +package com.flyco.tablayout.listener; + +import androidx.annotation.DrawableRes; + +public interface CustomTabEntity { + String getTabTitle(); + + @DrawableRes + int getTabSelectedIcon(); + + @DrawableRes + int getTabUnselectedIcon(); +} \ No newline at end of file diff --git a/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/listener/OnTabSelectListener.java b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/listener/OnTabSelectListener.java new file mode 100644 index 0000000..edf6cdb --- /dev/null +++ b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/listener/OnTabSelectListener.java @@ -0,0 +1,6 @@ +package com.flyco.tablayout.listener; + +public interface OnTabSelectListener { + void onTabSelect(int position); + void onTabReselect(int position); +} \ No newline at end of file diff --git a/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/transformer/ExtendTransformer.java b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/transformer/ExtendTransformer.java new file mode 100644 index 0000000..ce40c95 --- /dev/null +++ b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/transformer/ExtendTransformer.java @@ -0,0 +1,52 @@ +package com.flyco.tablayout.transformer; + +import androidx.annotation.NonNull; +import androidx.viewpager.widget.ViewPager; +import android.view.View; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by li.zhipeng on 2019/1/3. + *

+ * tab切换的 + */ +public class ExtendTransformer implements ViewPager.PageTransformer { + + private ArrayList transformers = new ArrayList<>(); + + + public ExtendTransformer() { + } + + public void addViewPagerTransformer(IViewPagerTransformer transformer) { + if (!transformers.contains(transformer)) { + transformers.add(transformer); + } + } + + public void removeViewPagerTransformer(IViewPagerTransformer transformer) { + transformers.remove(transformer); + } + + public List getTransformers() { + return transformers; + } + + public void setTransformers(List transformers) { + this.transformers.addAll(transformers); + } + + @Override + public void transformPage(@NonNull View view, final float position) { + // 回调设置的页面切换效果设置 + if (transformers != null && transformers.size() > 0) { + for (IViewPagerTransformer transformer : transformers) { + transformer.transformPage(view, position); + } + } + } + + +} diff --git a/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/transformer/ITabScaleTransformer.java b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/transformer/ITabScaleTransformer.java new file mode 100644 index 0000000..5a989a9 --- /dev/null +++ b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/transformer/ITabScaleTransformer.java @@ -0,0 +1,6 @@ +package com.flyco.tablayout.transformer; + +public interface ITabScaleTransformer { + void setNormalWidth(int position, int width, boolean isSelect); + void onPageScrolled(int position, float positionOffset, int positionOffsetPixels); +} diff --git a/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/transformer/IViewPagerTransformer.java b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/transformer/IViewPagerTransformer.java new file mode 100644 index 0000000..93235a5 --- /dev/null +++ b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/transformer/IViewPagerTransformer.java @@ -0,0 +1,12 @@ +package com.flyco.tablayout.transformer; + +import androidx.viewpager.widget.ViewPager; + +/** + * Created by li.zhipeng on 2019/1/3. + * + * ViewPager的扩展Transformer,配合SlidingScaleTabLayout使用 + * 因为字体的切换效果设置了默认的Transformer,所以扩展此接口 + */ +public interface IViewPagerTransformer extends ViewPager.PageTransformer { +} diff --git a/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/transformer/TabScaleTransformer.java b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/transformer/TabScaleTransformer.java new file mode 100644 index 0000000..5757d64 --- /dev/null +++ b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/transformer/TabScaleTransformer.java @@ -0,0 +1,110 @@ +package com.flyco.tablayout.transformer; + +import android.util.Log; +import android.util.TypedValue; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import com.flyco.tablayout.SlidingScaleTabLayout; + +/** + * Created by li.zhipeng on 2019/1/3. + *

+ * tab切换的 + */ +public class TabScaleTransformer implements ITabScaleTransformer { + + private SlidingScaleTabLayout slidingScaleTabLayout; + + private float textSelectSize; + + private float textUnSelectSize; + +// private float maxScale; + + private boolean openDmg; + + public TabScaleTransformer(SlidingScaleTabLayout slidingScaleTabLayout, + float textSelectSize, float textUnSelectSize, boolean openDmg) { + this.slidingScaleTabLayout = slidingScaleTabLayout; + this.textSelectSize = textSelectSize; + this.textUnSelectSize = textUnSelectSize; +// this.maxScale = (textSelectSize / textUnSelectSize) - 1; + this.openDmg = openDmg; + } + + @Override + public void setNormalWidth(int position, int width, boolean isSelect) { + } + + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + Log.i("TabScaleTransformer", "position:" + position); + // 字体大小相同,不需要切换 + if (textSelectSize == textUnSelectSize) return; + if (openDmg) { + for (int i = 0; i < slidingScaleTabLayout.getTabCount(); i++) { + if (i != position && i != position + 1) { + changTabDmgWidth(i, 0); + } + } + changeDmgSize(position, positionOffset); + } else { + for (int i = 0; i < slidingScaleTabLayout.getTabCount(); i++) { + if (i != position && i != position + 1) { + updateTextSize(i, 1); + } + } + changeTextSize(position, positionOffset); + } + } + + private void changeTextSize(final int position, final float positionOffset) { + updateTextSize(position, positionOffset); + if (position + 1 < slidingScaleTabLayout.getTabCount()) { + updateTextSize(position + 1, 1 - positionOffset); + } + } + + private void updateTextSize(final int position, final float positionOffset) { + final TextView currentTab = slidingScaleTabLayout.getTitle(position); + // 必须要在View调用post更新样式,否则可能无效 + currentTab.post(new Runnable() { + @Override + public void run() { + int textSize = (int) (textSelectSize - Math.abs((textSelectSize - textUnSelectSize) * positionOffset)); + if (currentTab.getTextSize() != textSize) { + currentTab.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize); + currentTab.requestLayout(); + } + } + }); + } + + private void changeDmgSize(final int position, final float positionOffset) { + slidingScaleTabLayout.post(new Runnable() { + @Override + public void run() { +// Log.i("lzp", "position:" + position + " positionOffset:" + positionOffset); + float scale = 1 - positionOffset; + changTabDmgWidth(position, scale); + if (position + 1 < slidingScaleTabLayout.getTabCount()) { + changTabDmgWidth(position + 1, positionOffset); + } + } + }); + } + + private void changTabDmgWidth(int position, float scale) { + final ImageView currentTabDmg = slidingScaleTabLayout.getDmgView(position); + if (currentTabDmg == null) return; + if (currentTabDmg.getDrawable() == null) return; + ViewGroup.LayoutParams params = currentTabDmg.getLayoutParams(); + int width = (int) (currentTabDmg.getMinimumWidth() + (currentTabDmg.getMaxWidth() - currentTabDmg.getMinimumWidth()) * scale); + if (params.width != width) { + params.width = width; + currentTabDmg.setLayoutParams(params); + } +// Log.i("lzp", "position:" + position + " scale:" + scale + " width:" + params.width); + } +} \ No newline at end of file diff --git a/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/utils/FragmentChangeManager.java b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/utils/FragmentChangeManager.java new file mode 100644 index 0000000..f47b315 --- /dev/null +++ b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/utils/FragmentChangeManager.java @@ -0,0 +1,55 @@ +package com.flyco.tablayout.utils; + +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentTransaction; + +import java.util.ArrayList; + +public class FragmentChangeManager { + private FragmentManager mFragmentManager; + private int mContainerViewId; + /** Fragment切换数组 */ + private ArrayList mFragments; + /** 当前选中的Tab */ + private int mCurrentTab; + + public FragmentChangeManager(FragmentManager fm, int containerViewId, ArrayList fragments) { + this.mFragmentManager = fm; + this.mContainerViewId = containerViewId; + this.mFragments = fragments; + initFragments(); + } + + /** 初始化fragments */ + private void initFragments() { + for (Fragment fragment : mFragments) { + mFragmentManager.beginTransaction().add(mContainerViewId, fragment).hide(fragment).commit(); + } + + setFragments(0); + } + + /** 界面切换控制 */ + public void setFragments(int index) { + for (int i = 0; i < mFragments.size(); i++) { + FragmentTransaction ft = mFragmentManager.beginTransaction(); + Fragment fragment = mFragments.get(i); + if (i == index) { + ft.show(fragment); + } else { + ft.hide(fragment); + } + ft.commit(); + } + mCurrentTab = index; + } + + public int getCurrentTab() { + return mCurrentTab; + } + + public Fragment getCurrentFragment() { + return mFragments.get(mCurrentTab); + } +} \ No newline at end of file diff --git a/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/utils/UnreadMsgUtils.java b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/utils/UnreadMsgUtils.java new file mode 100644 index 0000000..0446bfa --- /dev/null +++ b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/utils/UnreadMsgUtils.java @@ -0,0 +1,58 @@ +package com.flyco.tablayout.utils; + + +import android.util.DisplayMetrics; +import android.view.View; +import android.widget.RelativeLayout; + +import com.flyco.tablayout.widget.MsgView; + +/** + * 未读消息提示View,显示小红点或者带有数字的红点: + * 数字一位,圆 + * 数字两位,圆角矩形,圆角是高度的一半 + * 数字超过两位,显示99+ + */ +public class UnreadMsgUtils { + public static void show(MsgView msgView, int num) { + if (msgView == null) { + return; + } + RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) msgView.getLayoutParams(); + DisplayMetrics dm = msgView.getResources().getDisplayMetrics(); + msgView.setVisibility(View.VISIBLE); + if (num <= 0) {//圆点,设置默认宽高 + msgView.setStrokeWidth(0); + msgView.setText(""); + + lp.width = (int) (5 * dm.density); + lp.height = (int) (5 * dm.density); + msgView.setLayoutParams(lp); + } else { + lp.height = (int) (18 * dm.density); + if (num < 10) {//圆 + lp.width = (int) (18 * dm.density); + msgView.setText(num + ""); + } else if (num < 100) {//圆角矩形,圆角是高度的一半,设置默认padding + lp.width = RelativeLayout.LayoutParams.WRAP_CONTENT; + msgView.setPadding((int) (6 * dm.density), 0, (int) (6 * dm.density), 0); + msgView.setText(num + ""); + } else {//数字超过两位,显示99+ + lp.width = RelativeLayout.LayoutParams.WRAP_CONTENT; + msgView.setPadding((int) (6 * dm.density), 0, (int) (6 * dm.density), 0); + msgView.setText("99+"); + } + msgView.setLayoutParams(lp); + } + } + + public static void setSize(MsgView rtv, int size) { + if (rtv == null) { + return; + } + RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) rtv.getLayoutParams(); + lp.width = size; + lp.height = size; + rtv.setLayoutParams(lp); + } +} diff --git a/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/utils/ViewUtils.java b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/utils/ViewUtils.java new file mode 100644 index 0000000..2f54c6b --- /dev/null +++ b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/utils/ViewUtils.java @@ -0,0 +1,39 @@ +package com.flyco.tablayout.utils; + +import android.graphics.Bitmap; +import androidx.annotation.IdRes; +import android.view.View; + +public class ViewUtils { + + public static Bitmap generateViewCacheBitmap(View view) { + view.destroyDrawingCache(); + int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); + int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); + view.measure(widthMeasureSpec, heightMeasureSpec); + int width = view.getMeasuredWidth(); + int height = view.getMeasuredHeight(); + view.layout(0, 0, width, height); + view.setDrawingCacheEnabled(true); + view.buildDrawingCache(); + return Bitmap.createBitmap(view.getDrawingCache()); + } + + public static View findBrotherView(View view, @IdRes int id, int level) { + int count = 0; + View temp = view; + while (count < level) { + View target = temp.findViewById(id); + if (target != null) { + return target; + } + count += 1; + if (temp.getParent() instanceof View) { + temp = (View) temp.getParent(); + } else { + break; + } + } + return null; + } +} diff --git a/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/widget/MsgView.java b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/widget/MsgView.java new file mode 100644 index 0000000..59dd2b6 --- /dev/null +++ b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/widget/MsgView.java @@ -0,0 +1,157 @@ +package com.flyco.tablayout.widget; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Color; +import android.graphics.drawable.GradientDrawable; +import android.graphics.drawable.StateListDrawable; +import android.os.Build; +import android.util.AttributeSet; +import android.widget.TextView; + +import com.flyco.tablayout.R; + +/** 用于需要圆角矩形框背景的TextView的情况,减少直接使用TextView时引入的shape资源文件 */ +public class MsgView extends TextView { + private Context context; + private GradientDrawable gd_background = new GradientDrawable(); + private int backgroundColor; + private int cornerRadius; + private int strokeWidth; + private int strokeColor; + private boolean isRadiusHalfHeight; + private boolean isWidthHeightEqual; + + public MsgView(Context context) { + this(context, null); + } + + public MsgView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public MsgView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + this.context = context; + obtainAttributes(context, attrs); + } + + private void obtainAttributes(Context context, AttributeSet attrs) { + TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.MsgView); + backgroundColor = ta.getColor(R.styleable.MsgView_mv_backgroundColor, Color.TRANSPARENT); + cornerRadius = ta.getDimensionPixelSize(R.styleable.MsgView_mv_cornerRadius, 0); + strokeWidth = ta.getDimensionPixelSize(R.styleable.MsgView_mv_strokeWidth, 0); + strokeColor = ta.getColor(R.styleable.MsgView_mv_strokeColor, Color.TRANSPARENT); + isRadiusHalfHeight = ta.getBoolean(R.styleable.MsgView_mv_isRadiusHalfHeight, false); + isWidthHeightEqual = ta.getBoolean(R.styleable.MsgView_mv_isWidthHeightEqual, false); + + ta.recycle(); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + if (isWidthHeightEqual() && getWidth() > 0 && getHeight() > 0) { + int max = Math.max(getWidth(), getHeight()); + int measureSpec = MeasureSpec.makeMeasureSpec(max, MeasureSpec.EXACTLY); + super.onMeasure(measureSpec, measureSpec); + return; + } + + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + if (isRadiusHalfHeight()) { + setCornerRadius(getHeight() / 2); + } else { + setBgSelector(); + } + } + + + public void setBackgroundColor(int backgroundColor) { + this.backgroundColor = backgroundColor; + setBgSelector(); + } + + public void setCornerRadius(int cornerRadius) { + this.cornerRadius = dp2px(cornerRadius); + setBgSelector(); + } + + public void setStrokeWidth(int strokeWidth) { + this.strokeWidth = dp2px(strokeWidth); + setBgSelector(); + } + + public void setStrokeColor(int strokeColor) { + this.strokeColor = strokeColor; + setBgSelector(); + } + + public void setIsRadiusHalfHeight(boolean isRadiusHalfHeight) { + this.isRadiusHalfHeight = isRadiusHalfHeight; + setBgSelector(); + } + + public void setIsWidthHeightEqual(boolean isWidthHeightEqual) { + this.isWidthHeightEqual = isWidthHeightEqual; + setBgSelector(); + } + + public int getBackgroundColor() { + return backgroundColor; + } + + public int getCornerRadius() { + return cornerRadius; + } + + public int getStrokeWidth() { + return strokeWidth; + } + + public int getStrokeColor() { + return strokeColor; + } + + public boolean isRadiusHalfHeight() { + return isRadiusHalfHeight; + } + + public boolean isWidthHeightEqual() { + return isWidthHeightEqual; + } + + protected int dp2px(float dp) { + final float scale = context.getResources().getDisplayMetrics().density; + return (int) (dp * scale + 0.5f); + } + + protected int sp2px(float sp) { + final float scale = this.context.getResources().getDisplayMetrics().scaledDensity; + return (int) (sp * scale + 0.5f); + } + + private void setDrawable(GradientDrawable gd, int color, int strokeColor) { + gd.setColor(color); + gd.setCornerRadius(cornerRadius); + gd.setStroke(strokeWidth, strokeColor); + } + + public void setBgSelector() { + StateListDrawable bg = new StateListDrawable(); + + setDrawable(gd_background, backgroundColor, strokeColor); + bg.addState(new int[]{-android.R.attr.state_pressed}, gd_background); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {//16 + setBackground(bg); + } else { + //noinspection deprecation + setBackgroundDrawable(bg); + } + } +} diff --git a/FlycoTabLayoutZ_Lib/src/main/res/layout/layout_scale_tab.xml b/FlycoTabLayoutZ_Lib/src/main/res/layout/layout_scale_tab.xml new file mode 100644 index 0000000..1533d51 --- /dev/null +++ b/FlycoTabLayoutZ_Lib/src/main/res/layout/layout_scale_tab.xml @@ -0,0 +1,38 @@ + + + + + + + + + + \ No newline at end of file diff --git a/FlycoTabLayoutZ_Lib/src/main/res/layout/layout_tab.xml b/FlycoTabLayoutZ_Lib/src/main/res/layout/layout_tab.xml new file mode 100644 index 0000000..9a46415 --- /dev/null +++ b/FlycoTabLayoutZ_Lib/src/main/res/layout/layout_tab.xml @@ -0,0 +1,31 @@ + + + + + + + + \ No newline at end of file diff --git a/FlycoTabLayoutZ_Lib/src/main/res/layout/layout_tab_bottom.xml b/FlycoTabLayoutZ_Lib/src/main/res/layout/layout_tab_bottom.xml new file mode 100644 index 0000000..229e640 --- /dev/null +++ b/FlycoTabLayoutZ_Lib/src/main/res/layout/layout_tab_bottom.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/FlycoTabLayoutZ_Lib/src/main/res/layout/layout_tab_left.xml b/FlycoTabLayoutZ_Lib/src/main/res/layout/layout_tab_left.xml new file mode 100644 index 0000000..dd9c729 --- /dev/null +++ b/FlycoTabLayoutZ_Lib/src/main/res/layout/layout_tab_left.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/FlycoTabLayoutZ_Lib/src/main/res/layout/layout_tab_right.xml b/FlycoTabLayoutZ_Lib/src/main/res/layout/layout_tab_right.xml new file mode 100644 index 0000000..0d65d85 --- /dev/null +++ b/FlycoTabLayoutZ_Lib/src/main/res/layout/layout_tab_right.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/FlycoTabLayoutZ_Lib/src/main/res/layout/layout_tab_segment.xml b/FlycoTabLayoutZ_Lib/src/main/res/layout/layout_tab_segment.xml new file mode 100644 index 0000000..6d36a01 --- /dev/null +++ b/FlycoTabLayoutZ_Lib/src/main/res/layout/layout_tab_segment.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/FlycoTabLayoutZ_Lib/src/main/res/layout/layout_tab_top.xml b/FlycoTabLayoutZ_Lib/src/main/res/layout/layout_tab_top.xml new file mode 100644 index 0000000..68478b6 --- /dev/null +++ b/FlycoTabLayoutZ_Lib/src/main/res/layout/layout_tab_top.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/FlycoTabLayoutZ_Lib/src/main/res/values/attrs.xml b/FlycoTabLayoutZ_Lib/src/main/res/values/attrs.xml new file mode 100644 index 0000000..324c0ca --- /dev/null +++ b/FlycoTabLayoutZ_Lib/src/main/res/values/attrs.xml @@ -0,0 +1,319 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 850823b..f12deca 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -16,8 +16,8 @@ android { applicationId "com.uiui.videoplayer" minSdkVersion 24 targetSdkVersion 28 - versionCode 114 - versionName "1.1.3" + versionCode 115 + versionName "1.1.4" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -32,6 +32,14 @@ android { checkReleaseBuilds false abortOnError false } + + viewBinding{ + enabled = true + } + + dataBinding { + enabled true + } } compileOptions { @@ -123,6 +131,7 @@ android { dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation project(path: ':FlycoTabLayoutZ_Lib') implementation project(path: ':JZVideo') implementation project(path: ':niceimageview') @@ -130,6 +139,7 @@ dependencies { implementation 'androidx.constraintlayout:constraintlayout:2.0.4' implementation 'androidx.recyclerview:recyclerview:1.1.0' implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' + implementation "androidx.viewpager2:viewpager2:1.0.0" implementation 'androidx.legacy:legacy-support-v4:1.0.0' testImplementation 'junit:junit:4.12' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b20ee4e..1862ce1 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -15,7 +15,7 @@ + android:screenOrientation="portrait" /> + + \ No newline at end of file diff --git a/app/src/main/java/com/uiui/videoplayer/activity/main/MainActivity.java b/app/src/main/java/com/uiui/videoplayer/activity/main/MainActivity.java index 8ffeed2..2620723 100644 --- a/app/src/main/java/com/uiui/videoplayer/activity/main/MainActivity.java +++ b/app/src/main/java/com/uiui/videoplayer/activity/main/MainActivity.java @@ -1,12 +1,5 @@ package com.uiui.videoplayer.activity.main; -import androidx.constraintlayout.widget.ConstraintLayout; -import androidx.core.app.ActivityCompat; -import androidx.core.content.ContextCompat; -import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentManager; -import androidx.fragment.app.FragmentTransaction; - import android.Manifest; import android.content.Intent; import android.content.pm.PackageManager; @@ -17,23 +10,24 @@ import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Build; import android.util.Log; +import android.view.KeyEvent; import android.view.View; -import android.widget.ImageView; -import android.widget.TextView; + +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; import com.uiui.videoplayer.BuildConfig; import com.uiui.videoplayer.R; -import com.uiui.videoplayer.base.BaseActivity; -import com.uiui.videoplayer.base.BaseLightActivity; -import com.uiui.videoplayer.bean.BaseResponse; -import com.uiui.videoplayer.bean.SpaceInfo; -import com.uiui.videoplayer.fragment.doc.DocFragment; +import com.uiui.videoplayer.activity.vip.VipActivity; +import com.uiui.videoplayer.base.BaseFragmentPagerAdapter; +import com.uiui.videoplayer.base.mvvm.BaseMvvmActivity; +import com.uiui.videoplayer.databinding.ActivityMainBinding; import com.uiui.videoplayer.fragment.pic.PictureFragment; import com.uiui.videoplayer.fragment.video.VideoFragment; -import com.uiui.videoplayer.network.NetInterfaceManager; import com.uiui.videoplayer.utils.JGYUtils; import com.uiui.videoplayer.utils.ToastUtil; -import com.uiui.videoplayer.utils.Utils; import com.uiui.videoplayer.utils.VideoUtils; import java.io.File; @@ -43,41 +37,18 @@ import java.util.ArrayList; import java.util.LinkedList; import java.util.List; -import butterknife.BindView; -import butterknife.ButterKnife; -import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; import io.reactivex.rxjava3.annotations.NonNull; -import io.reactivex.rxjava3.core.Observer; -import io.reactivex.rxjava3.disposables.Disposable; -import io.reactivex.rxjava3.schedulers.Schedulers; -public class MainActivity extends BaseActivity { +public class MainActivity extends BaseMvvmActivity { private static final int REQUEST_PERMISSION_CODE = 200; - @BindView(R.id.iv_back) - ImageView iv_back; - @BindView(R.id.cl_pic) - ConstraintLayout cl_pic; - @BindView(R.id.cl_video) - ConstraintLayout cl_video; - @BindView(R.id.cl_doc) - ConstraintLayout cl_doc; - @BindView(R.id.iv_pic) - ImageView iv_pic; - @BindView(R.id.iv_video) - ImageView iv_video; - @BindView(R.id.iv_doc) - ImageView iv_doc; - @BindView(R.id.tv_space) - TextView tv_space; - @BindView(R.id.tv_rank) - TextView tv_rank; - - @BindView(R.id.tv_version) - TextView tv_version; + private String[] title = new String[]{"视频", "照片"}; + private BaseFragmentPagerAdapter mPagerAdapter; private FragmentManager mFragmentManager; - private Fragment[] mFragments; + private List mFragments; + private PictureFragment mPictureFragment; + private VideoFragment mVideoFragment; String[] permissions = new String[]{ Manifest.permission.READ_EXTERNAL_STORAGE, @@ -89,46 +60,41 @@ public class MainActivity extends BaseActivity { return R.layout.activity_main; } + @Override + protected boolean setNightMode() { + return true; + } + + @Override + protected void initDataBinding() { + mViewModel.setCtx(this); + mViewModel.setVDBinding(mViewDataBinding); + mViewModel.setLifecycle(getLifecycleSubject()); + mViewDataBinding.setClick(new Click()); + } + @Override public void initView() { -// getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); -// //注意要清除 FLAG_TRANSLUCENT_STATUS flag -// getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); -// getWindow().setStatusBarColor(getResources().getColor(R.color.colorPrimaryDark)); - ButterKnife.bind(this); - tv_version.setText("版本号:V" + BuildConfig.VERSION_NAME); - iv_back.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - finish(); - } - }); - cl_pic.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - switchContent(0); - } - }); - cl_video.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - switchContent(1); - } - }); - cl_doc.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - switchContent(2); - } - }); + mViewDataBinding.tvVersion.setText("V" + BuildConfig.VERSION_NAME); + mFragments = new ArrayList<>(); + if (mVideoFragment == null) { + mVideoFragment = new VideoFragment(); + } + if (mPictureFragment == null) { + mPictureFragment = new PictureFragment(); + } + mFragments.add(mVideoFragment); + mFragments.add(mPictureFragment); mFragmentManager = getSupportFragmentManager(); - mFragments = new Fragment[3]; - switchContent(0); + mPagerAdapter = new BaseFragmentPagerAdapter(mFragmentManager, mFragments); + mViewDataBinding.viewPager.setAdapter(mPagerAdapter); + mViewDataBinding.mainSlidingTabLayout.setViewPager(mViewDataBinding.viewPager, title); + } @Override public void initData() { - getHomeSpaceInfo(); + } @Override @@ -177,124 +143,6 @@ public class MainActivity extends BaseActivity { } } - private void getHomeSpaceInfo() { - NetInterfaceManager.getInstance().getHomeSpaceInfoControl() - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(new Observer>() { - @Override - public void onSubscribe(@NonNull Disposable d) { - Log.e("getHomeSpaceInfo", "onSubscribe: "); - } - - @Override - public void onNext(@NonNull BaseResponse spaceInfoBaseResponse) { - Log.e("getHomeSpaceInfo", "onNext: " + spaceInfoBaseResponse); - if (spaceInfoBaseResponse.code == 200) { - SpaceInfo spaceInfo = spaceInfoBaseResponse.data; - String home_video_grade = spaceInfo.getHome_video_grade(); - long quota = spaceInfo.getQuota(); - long use_quota = spaceInfo.getUse_quota(); - tv_rank.setText(home_video_grade); - tv_space.setText(Utils.formatFileSize(use_quota) + "/" + Utils.formatFileSize(quota)); - } else { - tv_rank.setText("普通"); - tv_space.setText("0GB/0GB"); - } - } - - @Override - public void onError(@NonNull Throwable e) { - Log.e("getHomeSpaceInfo", "onError: " + e.getMessage()); - onComplete(); - } - - @Override - public void onComplete() { - Log.e("getHomeSpaceInfo", "onComplete: "); - } - }); - } - - // 切换显示内容 - public void switchContent(int index) { - switchPic(index); - FragmentTransaction transaction = mFragmentManager.beginTransaction(); - hideFragments(transaction); - try { - switch (index) { - case 0: - if (mFragments[0] == null) { - mFragments[0] = new PictureFragment(); - transaction.add(R.id.content, mFragments[0], 0 + ""); - } else { - transaction.show(mFragments[0]); - } - break; - case 1: - if (mFragments[1] == null) { - mFragments[1] = new VideoFragment(); - transaction.add(R.id.content, mFragments[1], 1 + ""); - } else { - transaction.show(mFragments[1]); - } - break; - case 2: - if (mFragments[2] == null) { - mFragments[2] = new DocFragment(); - transaction.add(R.id.content, mFragments[2], 2 + ""); - } else { - transaction.show(mFragments[2]); - } - break; - default: - } - transaction.commit(); - } catch (Exception e) { - e.printStackTrace(); - } - } - - private void switchPic(int index) { -// iv_pic.setImageDrawable(getDrawable(R.drawable.home_icon_picture_normal)); -// iv_video.setImageDrawable(getDrawable(R.drawable.home_icon_video_normal)); -// iv_doc.setImageDrawable(getDrawable(R.drawable.home_icon_doc_normal)); -// Animation animation = AnimationUtils.loadAnimation(MainActivity.this, R.anim.anim_small); - cl_pic.setBackground(null); - cl_video.setBackground(null); - cl_doc.setBackground(null); - switch (index) { - case 0: -// iv_pic.startAnimation(animation); - iv_pic.setImageDrawable(getDrawable(R.drawable.home_icon_picture_pressed)); - iv_video.setImageDrawable(getDrawable(R.drawable.home_icon_video_normal)); - cl_pic.setBackground(getDrawable(R.drawable.alarm_pressed_background)); - break; - case 1: -// iv_video.startAnimation(animation); - iv_pic.setImageDrawable(getDrawable(R.drawable.home_icon_picture_normal)); - iv_video.setImageDrawable(getDrawable(R.drawable.home_icon_video_pressed)); - cl_video.setBackground(getDrawable(R.drawable.alarm_pressed_background)); - break; - case 2: -// iv_doc.startAnimation(animation); -// iv_doc.setImageDrawable(getDrawable(R.drawable.home_icon_doc_checked)); - cl_doc.setBackground(getDrawable(R.drawable.alarm_pressed_background)); - break; - default: - } - } - - // 将所有的Fragment都置为隐藏状态。 - private void hideFragments(FragmentTransaction transaction) { - if (mFragments != null) { - for (Fragment fragment : mFragments) { - if (fragment != null) { - transaction.hide(fragment); - } - } - } - } private void getThumbnail() { long s1 = System.currentTimeMillis(); @@ -346,92 +194,8 @@ public class MainActivity extends BaseActivity { Log.e("getThumbnail", "videoFileList: " + videoFileList); Log.e("getThumbnail", "picFileList size = " + picFileList.size()); Log.e("getThumbnail", "videoFileList size = " + videoFileList.size()); -// if (picFileList.size() == 0) { -// nv_pic.setImageDrawable(getDrawable(R.drawable.icon_pic)); -// } else { -// nv_pic.setImageDrawable(path2Drawable(picFileList.get(0))); -// } -// if (videoFileList.size() == 0) { -// nv_video.setImageDrawable(getDrawable(R.drawable.icon_video)); -// } else { -// Observable.create(new ObservableOnSubscribe() { -// @Override -// public void subscribe(ObservableEmitter emitter) throws Exception { -// FFmpegMediaMetadataRetriever mmr = new FFmpegMediaMetadataRetriever(); -// mmr.setDataSource(videoFileList.get(0)); -// Bitmap bitmap = mmr.getFrameAtTime();//获得视频第一帧的Bitmap对象. -// mmr.release(); -// emitter.onNext(bitmap); -// } -// }).subscribeOn(Schedulers.newThread()) -// .observeOn(AndroidSchedulers.mainThread()) -// .subscribe(new Observer() { -// @Override -// public void onSubscribe(Disposable d) { -// Log.e("VideoResult", "onSubscribe: "); -// } -// -// @Override -// public void onNext(Bitmap result) { -// Log.e("VideoResult", "onNext: " + result); -// nv_video.setImageBitmap(result); -//// Glide.with(nv_video).load(result).error(R.drawable.icon_video).into(nv_video); -// } -// -// @Override -// public void onError(Throwable e) { -// Log.e("VideoResult", "onError: " + e.getMessage()); -// } -// -// @Override -// public void onComplete() { -// Log.e("VideoResult", "onComplete: "); -// } -// }); -// } - Log.e("getThumbnail", "videoFileList size = " + videoFileList.size()); -// CombineBitmap.init(this) -// .setLayoutManager(new DingLayoutManager()) // 必选, 设置图片的组合形式,支持WechatLayoutManager、DingLayoutManager -// .setSize(100) // 必选,组合后Bitmap的尺寸,单位dp -// .setGap(1) // 单个图片之间的距离,单位dp,默认0dp -//// .setGapColor() // 单个图片间距的颜色,默认白色 -//// .setPlaceholder() // 单个图片加载失败的默认显示图片 -// .setUrls(picFileList.toArray(new String[picFileList.size()])) // 要加载的图片url数组 -// .setBitmaps() // 要加载的图片bitmap数组 -// .setResourceIds() // 要加载的图片资源id数组 -// .setImageView(nv_pic) // 直接设置要显示图片的ImageView -// // 设置“子图片”的点击事件,需使用setImageView(),index和图片资源数组的索引对应 -//// .setOnSubItemClickListener(new OnSubItemClickListener() { -//// @Override -//// public void onSubItemClick(int index) { -//// -//// } -//// }) -//// // 加载进度的回调函数,如果不使用setImageView()方法,可在onComplete()完成最终图片的显示 -//// .setProgressListener(new ProgressListener() { -//// @Override -//// public void onStart() { -//// -//// } -//// -//// @Override -//// public void onComplete(Bitmap bitmap) { -//// -//// } -//// }) -// .build(); -// CombineBitmap.init(this) -// .setLayoutManager(new DingLayoutManager()) // 必选, 设置图片的组合形式,支持WechatLayoutManager、DingLayoutManager -// .setSize(100) // 必选,组合后Bitmap的尺寸,单位dp -// .setGap(1) // 单个图片之间的距离,单位dp,默认0dp -//// .setGapColor() // 单个图片间距的颜色,默认白色 -//// .setPlaceholder() // 单个图片加载失败的默认显示图片 -// .setUrls(videoFileList.toArray(new String[videoFileList.size()])) // 要加载的图片url数组 -// .setBitmaps() // 要加载的图片bitmap数组 -// .setResourceIds() // 要加载的图片资源id数组 -// .setImageView(nv_video) // 直接设置要显示图片的ImageView -// .build(); + Log.e("getThumbnail", "videoFileList size = " + videoFileList.size()); } @@ -456,4 +220,34 @@ public class MainActivity extends BaseActivity { return drawable; } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == KeyEvent.ACTION_DOWN) { + lazyExit(); + return true; + } + return super.onKeyDown(keyCode, event); + } + + private long mPreClickTime; + + private void lazyExit() { + if (System.currentTimeMillis() - mPreClickTime > 3000) { + ToastUtil.show("再按一次,退出"); + mPreClickTime = System.currentTimeMillis(); + } else { + finish(); + } + } + + public class Click { + public void exit(View view) { + lazyExit(); + } + + public void toVip(View view) { + startActivity(new Intent(MainActivity.this, VipActivity.class)); + } + } } diff --git a/app/src/main/java/com/uiui/videoplayer/activity/main/MainViewModel.java b/app/src/main/java/com/uiui/videoplayer/activity/main/MainViewModel.java new file mode 100644 index 0000000..67137fe --- /dev/null +++ b/app/src/main/java/com/uiui/videoplayer/activity/main/MainViewModel.java @@ -0,0 +1,22 @@ +package com.uiui.videoplayer.activity.main; + +import androidx.lifecycle.MutableLiveData; + +import com.uiui.videoplayer.base.mvvm.BaseViewModel; +import com.uiui.videoplayer.bean.SpaceInfo; +import com.uiui.videoplayer.databinding.ActivityMainBinding; + +public class MainViewModel extends BaseViewModel { + @Override + public ActivityMainBinding getVDBinding() { + return binding; + } + + @Override + public void onDestroy() { + + } + + + +} diff --git a/app/src/main/java/com/uiui/videoplayer/activity/main/land/LandMainActivity.java b/app/src/main/java/com/uiui/videoplayer/activity/main/land/LandMainActivity.java new file mode 100644 index 0000000..f3325d9 --- /dev/null +++ b/app/src/main/java/com/uiui/videoplayer/activity/main/land/LandMainActivity.java @@ -0,0 +1,463 @@ +package com.uiui.videoplayer.activity.main.land; + +import android.Manifest; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.net.Uri; +import android.os.Build; +import android.util.Log; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.constraintlayout.widget.ConstraintLayout; +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentTransaction; + +import com.uiui.videoplayer.BuildConfig; +import com.uiui.videoplayer.R; +import com.uiui.videoplayer.base.BaseActivity; +import com.uiui.videoplayer.bean.BaseResponse; +import com.uiui.videoplayer.bean.SpaceInfo; +import com.uiui.videoplayer.fragment.doc.DocFragment; +import com.uiui.videoplayer.fragment.pic.PictureFragment; +import com.uiui.videoplayer.fragment.video.VideoFragment; +import com.uiui.videoplayer.network.NetInterfaceManager; +import com.uiui.videoplayer.utils.JGYUtils; +import com.uiui.videoplayer.utils.ToastUtil; +import com.uiui.videoplayer.utils.Utils; +import com.uiui.videoplayer.utils.VideoUtils; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +import butterknife.BindView; +import butterknife.ButterKnife; +import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; +import io.reactivex.rxjava3.annotations.NonNull; +import io.reactivex.rxjava3.core.Observer; +import io.reactivex.rxjava3.disposables.Disposable; +import io.reactivex.rxjava3.schedulers.Schedulers; + +public class LandMainActivity extends BaseActivity { + private static final int REQUEST_PERMISSION_CODE = 200; + + @BindView(R.id.iv_back) + ImageView iv_back; + @BindView(R.id.cl_pic) + ConstraintLayout cl_pic; + @BindView(R.id.cl_video) + ConstraintLayout cl_video; + @BindView(R.id.cl_doc) + ConstraintLayout cl_doc; + @BindView(R.id.iv_pic) + ImageView iv_pic; + @BindView(R.id.iv_video) + ImageView iv_video; + @BindView(R.id.iv_doc) + ImageView iv_doc; + @BindView(R.id.tv_space) + TextView tv_space; + @BindView(R.id.tv_rank) + TextView tv_rank; + + @BindView(R.id.tv_version) + TextView tv_version; + + private FragmentManager mFragmentManager; + private Fragment[] mFragments; + + String[] permissions = new String[]{ + Manifest.permission.READ_EXTERNAL_STORAGE, + Manifest.permission.WRITE_EXTERNAL_STORAGE + }; + + @Override + public int getLayoutId() { + return R.layout.activity_main; + } + + @Override + protected boolean setNightMode() { + return true; + } + + @Override + public void initView() { +// getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); +// //注意要清除 FLAG_TRANSLUCENT_STATUS flag +// getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); +// getWindow().setStatusBarColor(getResources().getColor(R.color.colorPrimaryDark)); + ButterKnife.bind(this); + tv_version.setText("版本号:V" + BuildConfig.VERSION_NAME); + iv_back.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + finish(); + } + }); + cl_pic.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + switchContent(0); + } + }); + cl_video.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + switchContent(1); + } + }); + cl_doc.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + switchContent(2); + } + }); + mFragmentManager = getSupportFragmentManager(); + mFragments = new Fragment[3]; + switchContent(0); + } + + @Override + public void initData() { + getHomeSpaceInfo(); + } + + @Override + protected void onResume() { + super.onResume(); + checkSelfPermission(); + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + if (requestCode == REQUEST_PERMISSION_CODE) { + if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { + Log.e("TAG", "onRequestPermissionsResult: "); + getThumbnail(); + } else if (grantResults[0] == PackageManager.PERMISSION_DENIED) { + if (ActivityCompat.shouldShowRequestPermissionRationale(LandMainActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE)) { + ToastUtil.show("需要存储空间权限才能正常使用软件"); + checkSelfPermission(); + } else { + ToastUtil.show("请打开存储空间权限后使用软件"); + Intent intent = new Intent(); + intent.setAction(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + intent.setData(Uri.parse("package:" + this.getPackageName())); + startActivity(intent); + } + } + } + } + + private void checkSelfPermission() { + List mPermissionList = new ArrayList<>(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + for (String s : permissions) { + if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) { + mPermissionList.add(s); + } else { + Log.e("TAG", "checkSelfPermission: "); +// mPresenter.getHomeVideo(); + getThumbnail(); + } + } + if (mPermissionList.size() > 0) {//有权限没有通过,需要申请 + ActivityCompat.requestPermissions(this, permissions, REQUEST_PERMISSION_CODE); + } + } + } + + private void getHomeSpaceInfo() { + NetInterfaceManager.getInstance().getHomeSpaceInfoControl() + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Observer>() { + @Override + public void onSubscribe(@NonNull Disposable d) { + Log.e("getHomeSpaceInfo", "onSubscribe: "); + } + + @Override + public void onNext(@NonNull BaseResponse spaceInfoBaseResponse) { + Log.e("getHomeSpaceInfo", "onNext: " + spaceInfoBaseResponse); + if (spaceInfoBaseResponse.code == 200) { + SpaceInfo spaceInfo = spaceInfoBaseResponse.data; + String home_video_grade = spaceInfo.getHome_video_grade(); + long quota = spaceInfo.getQuota(); + long use_quota = spaceInfo.getUse_quota(); + tv_rank.setText(home_video_grade); + tv_space.setText(Utils.formatFileSize(use_quota) + "/" + Utils.formatFileSize(quota)); + } else { + tv_rank.setText("普通"); + tv_space.setText("0GB/0GB"); + } + } + + @Override + public void onError(@NonNull Throwable e) { + Log.e("getHomeSpaceInfo", "onError: " + e.getMessage()); + onComplete(); + } + + @Override + public void onComplete() { + Log.e("getHomeSpaceInfo", "onComplete: "); + } + }); + } + + // 切换显示内容 + public void switchContent(int index) { + switchPic(index); + FragmentTransaction transaction = mFragmentManager.beginTransaction(); + hideFragments(transaction); + try { + switch (index) { + case 0: + if (mFragments[0] == null) { + mFragments[0] = new PictureFragment(); + transaction.add(R.id.content, mFragments[0], 0 + ""); + } else { + transaction.show(mFragments[0]); + } + break; + case 1: + if (mFragments[1] == null) { + mFragments[1] = new VideoFragment(); + transaction.add(R.id.content, mFragments[1], 1 + ""); + } else { + transaction.show(mFragments[1]); + } + break; + case 2: + if (mFragments[2] == null) { + mFragments[2] = new DocFragment(); + transaction.add(R.id.content, mFragments[2], 2 + ""); + } else { + transaction.show(mFragments[2]); + } + break; + default: + } + transaction.commit(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private void switchPic(int index) { +// iv_pic.setImageDrawable(getDrawable(R.drawable.home_icon_picture_normal)); +// iv_video.setImageDrawable(getDrawable(R.drawable.home_icon_video_normal)); +// iv_doc.setImageDrawable(getDrawable(R.drawable.home_icon_doc_normal)); +// Animation animation = AnimationUtils.loadAnimation(MainActivity.this, R.anim.anim_small); + cl_pic.setBackground(null); + cl_video.setBackground(null); + cl_doc.setBackground(null); + switch (index) { + case 0: +// iv_pic.startAnimation(animation); + iv_pic.setImageDrawable(getDrawable(R.drawable.home_icon_picture_pressed)); + iv_video.setImageDrawable(getDrawable(R.drawable.home_icon_video_normal)); + cl_pic.setBackground(getDrawable(R.drawable.alarm_pressed_background)); + break; + case 1: +// iv_video.startAnimation(animation); + iv_pic.setImageDrawable(getDrawable(R.drawable.home_icon_picture_normal)); + iv_video.setImageDrawable(getDrawable(R.drawable.home_icon_video_pressed)); + cl_video.setBackground(getDrawable(R.drawable.alarm_pressed_background)); + break; + case 2: +// iv_doc.startAnimation(animation); +// iv_doc.setImageDrawable(getDrawable(R.drawable.home_icon_doc_checked)); + cl_doc.setBackground(getDrawable(R.drawable.alarm_pressed_background)); + break; + default: + } + } + + // 将所有的Fragment都置为隐藏状态。 + private void hideFragments(FragmentTransaction transaction) { + if (mFragments != null) { + for (Fragment fragment : mFragments) { + if (fragment != null) { + transaction.hide(fragment); + } + } + } + } + + private void getThumbnail() { + long s1 = System.currentTimeMillis(); + List picFileList = new ArrayList<>(); + List videoFileList = new ArrayList<>(); + String rootPath = JGYUtils.getInstance().getDownLoadPath() + File.separator; + File file = new File(rootPath); + if (file.exists()) { + LinkedList list = new LinkedList(); + File[] files = file.listFiles(); + if (files == null) { + return; + } + for (File file2 : files) { + if (file2.isDirectory()) { + list.add(file2); + } else { + if (VideoUtils.isPicFormat(file2.getAbsolutePath())) { + picFileList.add(file2.getAbsolutePath()); + } else if (VideoUtils.isVideoFormat(file2.getAbsolutePath())) { + videoFileList.add(file2.getAbsolutePath()); + } + } + } + File temp_file; + while (!list.isEmpty()) { + temp_file = list.removeFirst(); + files = temp_file.listFiles(); + if (files == null) { + continue; + } + for (File file2 : files) { + if (file2.isDirectory()) { + list.add(file2); + } else { + if (VideoUtils.isPicFormat(file2.getAbsolutePath())) { + picFileList.add(file2.getAbsolutePath()); + } else if (VideoUtils.isVideoFormat(file2.getAbsolutePath())) { + videoFileList.add(file2.getAbsolutePath()); + } + } + } + } + } else { + Log.e("traverseFolder1", "文件不存在!"); + } + Log.e("ScanTask", "doInBackground: " + "Scan time = " + (System.currentTimeMillis() - s1) + "ms"); + Log.e("getThumbnail", "picFileList: " + picFileList); + Log.e("getThumbnail", "videoFileList: " + videoFileList); + Log.e("getThumbnail", "picFileList size = " + picFileList.size()); + Log.e("getThumbnail", "videoFileList size = " + videoFileList.size()); +// if (picFileList.size() == 0) { +// nv_pic.setImageDrawable(getDrawable(R.drawable.icon_pic)); +// } else { +// nv_pic.setImageDrawable(path2Drawable(picFileList.get(0))); +// } +// if (videoFileList.size() == 0) { +// nv_video.setImageDrawable(getDrawable(R.drawable.icon_video)); +// } else { +// Observable.create(new ObservableOnSubscribe() { +// @Override +// public void subscribe(ObservableEmitter emitter) throws Exception { +// FFmpegMediaMetadataRetriever mmr = new FFmpegMediaMetadataRetriever(); +// mmr.setDataSource(videoFileList.get(0)); +// Bitmap bitmap = mmr.getFrameAtTime();//获得视频第一帧的Bitmap对象. +// mmr.release(); +// emitter.onNext(bitmap); +// } +// }).subscribeOn(Schedulers.newThread()) +// .observeOn(AndroidSchedulers.mainThread()) +// .subscribe(new Observer() { +// @Override +// public void onSubscribe(Disposable d) { +// Log.e("VideoResult", "onSubscribe: "); +// } +// +// @Override +// public void onNext(Bitmap result) { +// Log.e("VideoResult", "onNext: " + result); +// nv_video.setImageBitmap(result); +//// Glide.with(nv_video).load(result).error(R.drawable.icon_video).into(nv_video); +// } +// +// @Override +// public void onError(Throwable e) { +// Log.e("VideoResult", "onError: " + e.getMessage()); +// } +// +// @Override +// public void onComplete() { +// Log.e("VideoResult", "onComplete: "); +// } +// }); +// } + Log.e("getThumbnail", "videoFileList size = " + videoFileList.size()); +// CombineBitmap.init(this) +// .setLayoutManager(new DingLayoutManager()) // 必选, 设置图片的组合形式,支持WechatLayoutManager、DingLayoutManager +// .setSize(100) // 必选,组合后Bitmap的尺寸,单位dp +// .setGap(1) // 单个图片之间的距离,单位dp,默认0dp +//// .setGapColor() // 单个图片间距的颜色,默认白色 +//// .setPlaceholder() // 单个图片加载失败的默认显示图片 +// .setUrls(picFileList.toArray(new String[picFileList.size()])) // 要加载的图片url数组 +// .setBitmaps() // 要加载的图片bitmap数组 +// .setResourceIds() // 要加载的图片资源id数组 +// .setImageView(nv_pic) // 直接设置要显示图片的ImageView +// // 设置“子图片”的点击事件,需使用setImageView(),index和图片资源数组的索引对应 +//// .setOnSubItemClickListener(new OnSubItemClickListener() { +//// @Override +//// public void onSubItemClick(int index) { +//// +//// } +//// }) +//// // 加载进度的回调函数,如果不使用setImageView()方法,可在onComplete()完成最终图片的显示 +//// .setProgressListener(new ProgressListener() { +//// @Override +//// public void onStart() { +//// +//// } +//// +//// @Override +//// public void onComplete(Bitmap bitmap) { +//// +//// } +//// }) +// .build(); + +// CombineBitmap.init(this) +// .setLayoutManager(new DingLayoutManager()) // 必选, 设置图片的组合形式,支持WechatLayoutManager、DingLayoutManager +// .setSize(100) // 必选,组合后Bitmap的尺寸,单位dp +// .setGap(1) // 单个图片之间的距离,单位dp,默认0dp +//// .setGapColor() // 单个图片间距的颜色,默认白色 +//// .setPlaceholder() // 单个图片加载失败的默认显示图片 +// .setUrls(videoFileList.toArray(new String[videoFileList.size()])) // 要加载的图片url数组 +// .setBitmaps() // 要加载的图片bitmap数组 +// .setResourceIds() // 要加载的图片资源id数组 +// .setImageView(nv_video) // 直接设置要显示图片的ImageView +// .build(); + } + + + /** + * 将本地图片转换为 Drawable + * + * @param file 文件路径 + * @return + */ + public Drawable path2Drawable(String file) { + if (file == null || file.isEmpty()) { + return null; + } + Drawable drawable = null; + try { + FileInputStream fis = new FileInputStream(file); + Bitmap bitmap = BitmapFactory.decodeStream(fis); + drawable = new BitmapDrawable(getResources(), bitmap); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + + return drawable; + } +} diff --git a/app/src/main/java/com/uiui/videoplayer/activity/pic/GalleryActivity.java b/app/src/main/java/com/uiui/videoplayer/activity/pic/GalleryActivity.java index fb8e89f..5a39b0b 100644 --- a/app/src/main/java/com/uiui/videoplayer/activity/pic/GalleryActivity.java +++ b/app/src/main/java/com/uiui/videoplayer/activity/pic/GalleryActivity.java @@ -1,31 +1,27 @@ package com.uiui.videoplayer.activity.pic; -import androidx.appcompat.app.AppCompatActivity; import androidx.constraintlayout.widget.ConstraintLayout; import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; -import android.os.Bundle; import android.view.View; import android.widget.ImageView; import com.uiui.videoplayer.R; import com.uiui.videoplayer.adapter.PicAdapter; import com.uiui.videoplayer.base.BGAGridDivider; -import com.uiui.videoplayer.base.BaseLightActivity; -import com.uiui.videoplayer.base.GridSpaceItemDecoration; +import com.uiui.videoplayer.base.BaseActivity; import com.uiui.videoplayer.bean.PhotoInfo; import com.uiui.videoplayer.utils.ToastUtil; import java.util.ArrayList; -import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; -public class GalleryActivity extends BaseLightActivity implements GalleryContact.GalleryView { +public class GalleryActivity extends BaseActivity implements GalleryContact.GalleryView { @BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout swipeRefreshLayout; @@ -47,11 +43,16 @@ public class GalleryActivity extends BaseLightActivity implements GalleryContact return R.layout.activity_gallery; } + @Override + protected boolean setNightMode() { + return false; + } + @Override public void initView() { ButterKnife.bind(this); mPresenter = new GalleryPresenter(this); - mPresenter.setLifecycle(lifecycleSubject); + mPresenter.setLifecycle(getLifecycleSubject()); mPresenter.attachView(this); GridLayoutManager layoutManager = new GridLayoutManager(this, SPAN_COUNT, LinearLayoutManager.VERTICAL, false); diff --git a/app/src/main/java/com/uiui/videoplayer/activity/preview/PreviewActivity.java b/app/src/main/java/com/uiui/videoplayer/activity/preview/PreviewActivity.java index 8c1df4c..3d6ba42 100644 --- a/app/src/main/java/com/uiui/videoplayer/activity/preview/PreviewActivity.java +++ b/app/src/main/java/com/uiui/videoplayer/activity/preview/PreviewActivity.java @@ -10,7 +10,7 @@ import androidx.viewpager.widget.ViewPager; import com.bumptech.glide.Glide; import com.uiui.videoplayer.R; import com.uiui.videoplayer.adapter.PreviewAdapter; -import com.uiui.videoplayer.base.BaseLightActivity; +import com.uiui.videoplayer.base.BaseActivity; import com.uiui.videoplayer.base.ScaleCircleNavigator; import com.uiui.videoplayer.bean.PhotoInfo; import com.zackratos.ultimatebarx.ultimatebarx.java.UltimateBarX; @@ -24,7 +24,7 @@ import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; -public class PreviewActivity extends BaseLightActivity { +public class PreviewActivity extends BaseActivity { @BindView(R.id.viewPager) ViewPager viewPager; @@ -40,6 +40,11 @@ public class PreviewActivity extends BaseLightActivity { return R.layout.activity_preview; } + @Override + protected boolean setNightMode() { + return false; + } + @Override public void initView() { UltimateBarX.statusBar(this) diff --git a/app/src/main/java/com/uiui/videoplayer/activity/video/VideoActivity.java b/app/src/main/java/com/uiui/videoplayer/activity/video/VideoActivity.java index 31535e6..9cc2709 100644 --- a/app/src/main/java/com/uiui/videoplayer/activity/video/VideoActivity.java +++ b/app/src/main/java/com/uiui/videoplayer/activity/video/VideoActivity.java @@ -1,14 +1,9 @@ package com.uiui.videoplayer.activity.video; -import android.Manifest; -import android.content.Intent; -import android.content.pm.PackageManager; import android.content.res.Configuration; import android.graphics.PorterDuff; import android.graphics.drawable.Drawable; -import android.net.Uri; import android.os.AsyncTask; -import android.os.Build; import android.os.Environment; import android.text.SpannableString; import android.text.Spanned; @@ -23,7 +18,6 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.appcompat.app.ActionBar; import androidx.constraintlayout.widget.ConstraintLayout; -import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import androidx.recyclerview.widget.DefaultItemAnimator; import androidx.recyclerview.widget.RecyclerView; @@ -36,10 +30,9 @@ import com.arialyy.aria.core.task.DownloadTask; import com.google.gson.JsonObject; import com.uiui.videoplayer.R; import com.uiui.videoplayer.adapter.VideoAdapter; -import com.uiui.videoplayer.base.BaseLightActivity; +import com.uiui.videoplayer.base.BaseActivity; import com.uiui.videoplayer.base.CustomDialog; import com.uiui.videoplayer.base.RecycleGridLayoutManager; -import com.uiui.videoplayer.base.SpacesItemDecoration; import com.uiui.videoplayer.bean.LocalVideoInfo; import com.uiui.videoplayer.gson.GsonUtils; import com.uiui.videoplayer.utils.SPUtils; @@ -54,7 +47,7 @@ import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; -public class VideoActivity extends BaseLightActivity implements VideoContact.VideoView { +public class VideoActivity extends BaseActivity implements VideoContact.VideoView { private static final String TAG = VideoActivity.class.getSimpleName(); @@ -80,7 +73,7 @@ public class VideoActivity extends BaseLightActivity implements VideoContact.Vid public void initView() { ButterKnife.bind(this); mPresenter = new VideoPresenter(this); - mPresenter.setLifecycle(lifecycleSubject); + mPresenter.setLifecycle(getLifecycleSubject()); mPresenter.attachView(this); Aria.download(this).register(); @@ -101,8 +94,7 @@ public class VideoActivity extends BaseLightActivity implements VideoContact.Vid } recyclerView.setLayoutManager(mManager); recyclerView.setNestedScrollingEnabled(false); - recyclerView.addItemDecoration(new SpacesItemDecoration(getResources().getDimensionPixelSize(R.dimen.PX1x), getResources().getDimensionPixelSize(R.dimen.PX1x), - getResources().getDimensionPixelSize(R.dimen.PX1x), getResources().getDimensionPixelSize(R.dimen.PX1x))); + ((DefaultItemAnimator) recyclerView.getItemAnimator()).setSupportsChangeAnimations(false); adapter = new VideoAdapter(VideoActivity.this); adapter.setOnLongClickListener(new VideoAdapter.onItemLongClickListener() { @@ -141,6 +133,11 @@ public class VideoActivity extends BaseLightActivity implements VideoContact.Vid return R.layout.activity_video; } + @Override + protected boolean setNightMode() { + return true; + } + @Override protected void onResume() { super.onResume(); diff --git a/app/src/main/java/com/uiui/videoplayer/activity/vip/VipActivity.java b/app/src/main/java/com/uiui/videoplayer/activity/vip/VipActivity.java new file mode 100644 index 0000000..5ec0404 --- /dev/null +++ b/app/src/main/java/com/uiui/videoplayer/activity/vip/VipActivity.java @@ -0,0 +1,86 @@ +package com.uiui.videoplayer.activity.vip; + +import android.view.View; + +import androidx.lifecycle.Observer; + +import com.uiui.videoplayer.R; +import com.uiui.videoplayer.base.mvvm.BaseMvvmActivity; +import com.uiui.videoplayer.bean.SpaceInfo; +import com.uiui.videoplayer.databinding.ActivityVipBinding; +import com.uiui.videoplayer.utils.Utils; + +public class VipActivity extends BaseMvvmActivity { + + + /** + * 设置布局 + */ + @Override + protected int getLayoutId() { + return R.layout.activity_vip; + } + + /** + * @return 是否是黑色状态栏 + */ + @Override + protected boolean setNightMode() { + return false; + } + + @Override + protected void initDataBinding() { + mViewModel.setCtx(this); + mViewModel.setVDBinding(mViewDataBinding); + mViewModel.setLifecycle(getLifecycleSubject()); + mViewDataBinding.setClick(new Click()); + } + + /** + * 初始化视图 + */ + @Override + protected void initView() { + + } + + /** + * 初始化数据 + */ + @Override + protected void initData() { + mViewModel.getSpaceInfoData().observe(this, new Observer() { + @Override + public void onChanged(SpaceInfo spaceInfo) { + if (spaceInfo == null) { +// tv_rank.setText("普通"); + mViewDataBinding.tvSpaceFree.setText("0GB/0GB"); + mViewDataBinding.tvSpaceUsed.setText("0%"); + + } else { + String home_video_grade = spaceInfo.getHome_video_grade(); + long quota = spaceInfo.getQuota(); + long use_quota = spaceInfo.getUse_quota(); +// tv_rank.setText(home_video_grade); + mViewDataBinding.tvSpaceFree.setText(String.format(getString(R.string.space_free), Utils.formatFileSize(use_quota), Utils.formatFileSize(quota))); + int percentage = (int) ((quota - use_quota) * 100 / (float) quota); + mViewDataBinding.tvSpaceUsed.setText(String.format(getString(R.string.space_used), (percentage + "%"))); + } + } + }); + mViewModel.getHomeSpaceInfo(); + + } + + public class Click { + public void exit(View view) { + finish(); + } + + public void empty(View view) { + + } + } + +} diff --git a/app/src/main/java/com/uiui/videoplayer/activity/vip/VipViewModel.java b/app/src/main/java/com/uiui/videoplayer/activity/vip/VipViewModel.java new file mode 100644 index 0000000..849896a --- /dev/null +++ b/app/src/main/java/com/uiui/videoplayer/activity/vip/VipViewModel.java @@ -0,0 +1,73 @@ +package com.uiui.videoplayer.activity.vip; + +import android.util.Log; + +import androidx.lifecycle.MutableLiveData; + +import com.trello.rxlifecycle4.RxLifecycle; +import com.trello.rxlifecycle4.android.ActivityEvent; +import com.uiui.videoplayer.base.mvvm.BaseViewModel; +import com.uiui.videoplayer.bean.BaseResponse; +import com.uiui.videoplayer.bean.SpaceInfo; +import com.uiui.videoplayer.databinding.ActivityVipBinding; +import com.uiui.videoplayer.network.NetInterfaceManager; + +import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; +import io.reactivex.rxjava3.annotations.NonNull; +import io.reactivex.rxjava3.core.Observer; +import io.reactivex.rxjava3.disposables.Disposable; +import io.reactivex.rxjava3.schedulers.Schedulers; + +public class VipViewModel extends BaseViewModel { + @Override + public ActivityVipBinding getVDBinding() { + return binding; + } + + @Override + public void onDestroy() { + + } + + private MutableLiveData mSpaceInfoData = new MutableLiveData<>(); + + public MutableLiveData getSpaceInfoData() { + return mSpaceInfoData; + } + + public void getHomeSpaceInfo() { + NetInterfaceManager.getInstance().getHomeSpaceInfoControl() + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY)) + .subscribe(new Observer>() { + @Override + public void onSubscribe(@NonNull Disposable d) { + Log.e("getHomeSpaceInfo", "onSubscribe: "); + } + + @Override + public void onNext(@NonNull BaseResponse spaceInfoBaseResponse) { + Log.e("getHomeSpaceInfo", "onNext: " + spaceInfoBaseResponse); + if (spaceInfoBaseResponse.code == 200) { + SpaceInfo spaceInfo = spaceInfoBaseResponse.data; + mSpaceInfoData.setValue(spaceInfo); + } else { + mSpaceInfoData.setValue(null); + } + } + + @Override + public void onError(@NonNull Throwable e) { + Log.e("getHomeSpaceInfo", "onError: " + e.getMessage()); + onComplete(); + } + + @Override + public void onComplete() { + Log.e("getHomeSpaceInfo", "onComplete: "); + } + }); + } + +} diff --git a/app/src/main/java/com/uiui/videoplayer/adapter/EquallyDividedItemDecoration.java b/app/src/main/java/com/uiui/videoplayer/adapter/EquallyDividedItemDecoration.java new file mode 100644 index 0000000..3e7ca63 --- /dev/null +++ b/app/src/main/java/com/uiui/videoplayer/adapter/EquallyDividedItemDecoration.java @@ -0,0 +1,74 @@ +package com.uiui.videoplayer.adapter; + +import android.graphics.Rect; +import android.util.Log; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +public class EquallyDividedItemDecoration extends RecyclerView.ItemDecoration { + private static final String TAG = EquallyDividedItemDecoration.class.getSimpleName(); + + private int mSpanCount;//横条目数量 + private int mHalfRowSpacing;//行间距的一半 + private int mHalfColumnSpacing;// 列间距的一半 + + + public EquallyDividedItemDecoration(int spanCount, int halfRowSpacing) { + mSpanCount = spanCount; + mHalfRowSpacing = halfRowSpacing; + mHalfColumnSpacing = halfRowSpacing; + } + + public EquallyDividedItemDecoration(int spanCount, int halfRowSpacing, int halfColumnSpacing) { + mSpanCount = spanCount; + mHalfRowSpacing = halfRowSpacing; + mHalfColumnSpacing = halfColumnSpacing; + } + + @Override + public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) { + super.getItemOffsets(outRect, view, parent, state); + int position = parent.getChildAdapterPosition(view); // 获取view 在adapter中的位置。 + Log.d(TAG, "getItemOffsets: position = " + position); + + int itemCount = parent.getAdapter().getItemCount();//item全部数量 + Log.d(TAG, "getItemOffsets: itemCount = " + itemCount); + + int column = position % mSpanCount; // view 所在的列 + Log.d(TAG, "getItemOffsets: column = " + column); + + if (column == 0) { + outRect.left = 2 * mHalfRowSpacing; + outRect.right = mHalfRowSpacing; + } else if (column == mSpanCount - 1) { + outRect.left = mHalfRowSpacing; + outRect.right = 2 * mHalfRowSpacing; + } else { + outRect.left = mHalfRowSpacing; + outRect.right = mHalfRowSpacing; + } + + int row = (position / 3);//所在行 + Log.d(TAG, "getItemOffsets: row = " + row); + int maxRow = (int) Math.ceil((double) itemCount / mSpanCount);//一共多少行 + Log.d(TAG, "getItemOffsets: maxRow = " + maxRow); + + if (row == 0) { + outRect.top = 2 * mHalfColumnSpacing; + outRect.bottom = mHalfColumnSpacing; + } else if (row == maxRow - 1) { + outRect.top = mHalfColumnSpacing; + outRect.bottom = 2 * mHalfColumnSpacing; + } else { + outRect.top = mHalfColumnSpacing; + outRect.bottom = mHalfColumnSpacing; + } + + Log.d(TAG, "getItemOffsets: outRect.left = " + outRect.left); + Log.d(TAG, "getItemOffsets: outRect.right = " + outRect.right); + Log.d(TAG, "getItemOffsets: outRect.top = " + outRect.top); + Log.d(TAG, "getItemOffsets: outRect.bottom = " + outRect.bottom); + } +} diff --git a/app/src/main/java/com/uiui/videoplayer/adapter/RecyclerViewSpacesItemDecoration.java b/app/src/main/java/com/uiui/videoplayer/adapter/RecyclerViewSpacesItemDecoration.java deleted file mode 100644 index 73f883a..0000000 --- a/app/src/main/java/com/uiui/videoplayer/adapter/RecyclerViewSpacesItemDecoration.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.uiui.videoplayer.adapter; - -import android.graphics.Rect; -import android.view.View; - -import androidx.recyclerview.widget.RecyclerView; - -import java.util.HashMap; - -public class RecyclerViewSpacesItemDecoration extends RecyclerView.ItemDecoration { - - private final HashMap mSpaceValueMap; - - public static final String TOP_DECORATION = "top_decoration"; - public static final String BOTTOM_DECORATION = "bottom_decoration"; - public static final String LEFT_DECORATION = "left_decoration"; - public static final String RIGHT_DECORATION = "right_decoration"; - - public RecyclerViewSpacesItemDecoration(final HashMap mSpaceValueMap) { - this.mSpaceValueMap = mSpaceValueMap; - } - - @Override - public void getItemOffsets(final Rect outRect, final View view, final RecyclerView parent, - final RecyclerView.State state) { - if (mSpaceValueMap.get(TOP_DECORATION) != null) { - outRect.top = mSpaceValueMap.get(TOP_DECORATION); - } - if (mSpaceValueMap.get(LEFT_DECORATION) != null) { - outRect.left = mSpaceValueMap.get(LEFT_DECORATION); - } - if (mSpaceValueMap.get(RIGHT_DECORATION) != null) { - outRect.right = mSpaceValueMap.get(RIGHT_DECORATION); - } - if (mSpaceValueMap.get(BOTTOM_DECORATION) != null) { - outRect.bottom = mSpaceValueMap.get(BOTTOM_DECORATION); - } - - } - -} diff --git a/app/src/main/java/com/uiui/videoplayer/base/BaseActivity.java b/app/src/main/java/com/uiui/videoplayer/base/BaseActivity.java index 105fb99..c8f6ea4 100644 --- a/app/src/main/java/com/uiui/videoplayer/base/BaseActivity.java +++ b/app/src/main/java/com/uiui/videoplayer/base/BaseActivity.java @@ -1,134 +1,32 @@ package com.uiui.videoplayer.base; -import android.app.ActivityManager; -import android.os.Build; import android.os.Bundle; import androidx.annotation.CallSuper; -import androidx.annotation.CheckResult; -import androidx.annotation.ContentView; -import androidx.annotation.LayoutRes; -import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.appcompat.app.AppCompatActivity; -import com.trello.rxlifecycle4.LifecycleProvider; -import com.trello.rxlifecycle4.LifecycleTransformer; -import com.trello.rxlifecycle4.RxLifecycle; -import com.trello.rxlifecycle4.android.ActivityEvent; -import com.trello.rxlifecycle4.android.RxLifecycleAndroid; -import com.uiui.videoplayer.R; -import com.zackratos.ultimatebarx.ultimatebarx.java.UltimateBarX; - -import io.reactivex.rxjava3.core.Observable; -import io.reactivex.rxjava3.subjects.BehaviorSubject; - - -public abstract class BaseActivity extends AppCompatActivity implements LifecycleProvider { - public final BehaviorSubject lifecycleSubject = BehaviorSubject.create(); - - @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); -// StatusBarUtil.init(this); - UltimateBarX.statusBar(this) - .transparent() - .colorRes(R.color.colorPrimaryDark) - .light(true) - .apply(); - UltimateBarX.navigationBar(this) - .transparent() - .colorRes(R.color.colorPrimaryDark) - .light(true) - .apply(); - setContentView(this.getLayoutId()); - initView(); - initData(); - //最近任务和应用图标不一样 -// if (Build.VERSION.SDK_INT > 27) { -// ActivityManager.TaskDescription description = new ActivityManager.TaskDescription(getString(R.string.app_name), R.mipmap.ic_launcher, getColor(R.color.colorPrimary)); -// this.setTaskDescription(description); -// } - } - - /** - * 设置布局 - */ - public abstract int getLayoutId(); - - /** - * 初始化视图 - */ - public abstract void initView(); - - - /** - * 初始化数据 - */ - public abstract void initData(); +public abstract class BaseActivity extends BaseTransparentActivity { public BaseActivity() { super(); } - @ContentView - public BaseActivity(@LayoutRes int contentLayoutId) { - super(contentLayoutId); - } - - @Override - @NonNull - @CheckResult - public final Observable lifecycle() { - return lifecycleSubject.hide(); - } - - @Override - @NonNull - @CheckResult - public final LifecycleTransformer bindUntilEvent(@NonNull ActivityEvent event) { - return RxLifecycle.bindUntilEvent(lifecycleSubject, event); - } - - @Override - @NonNull - @CheckResult - public final LifecycleTransformer bindToLifecycle() { - return RxLifecycleAndroid.bindActivity(lifecycleSubject); - } - @Override @CallSuper - protected void onStart() { - super.onStart(); - lifecycleSubject.onNext(ActivityEvent.START); + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(getLayoutId()); + initView(); + initData(); } - @Override - @CallSuper - protected void onResume() { - super.onResume(); - lifecycleSubject.onNext(ActivityEvent.RESUME); - } + /** + * 初始化视图 + */ + protected abstract void initView(); - @Override - @CallSuper - protected void onPause() { - lifecycleSubject.onNext(ActivityEvent.PAUSE); - super.onPause(); - } - - @Override - @CallSuper - protected void onStop() { - lifecycleSubject.onNext(ActivityEvent.STOP); - super.onStop(); - } - - @Override - @CallSuper - protected void onDestroy() { - lifecycleSubject.onNext(ActivityEvent.DESTROY); - super.onDestroy(); - } -} + /** + * 初始化数据 + */ + protected abstract void initData(); +} \ No newline at end of file diff --git a/app/src/main/java/com/uiui/videoplayer/base/BaseDataBindingActivity.java b/app/src/main/java/com/uiui/videoplayer/base/BaseDataBindingActivity.java new file mode 100644 index 0000000..8e6ab03 --- /dev/null +++ b/app/src/main/java/com/uiui/videoplayer/base/BaseDataBindingActivity.java @@ -0,0 +1,31 @@ +package com.uiui.videoplayer.base; + +import android.os.Bundle; + +import androidx.annotation.CallSuper; +import androidx.annotation.Nullable; + +public abstract class BaseDataBindingActivity extends BaseTransparentActivity { + + public BaseDataBindingActivity() { + super(); + } + + @Override + @CallSuper + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + initView(); + initData(); + } + + /** + * 初始化视图 + */ + protected abstract void initView(); + + /** + * 初始化数据 + */ + protected abstract void initData(); +} diff --git a/app/src/main/java/com/uiui/videoplayer/base/BaseFragmentPagerAdapter.java b/app/src/main/java/com/uiui/videoplayer/base/BaseFragmentPagerAdapter.java new file mode 100644 index 0000000..c727384 --- /dev/null +++ b/app/src/main/java/com/uiui/videoplayer/base/BaseFragmentPagerAdapter.java @@ -0,0 +1,204 @@ +package com.uiui.videoplayer.base; + +import android.util.SparseArray; + +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentPagerAdapter; +import androidx.fragment.app.FragmentTransaction; + +import java.util.List; + +/** + * 加载显示Fragment的ViewPagerAdapter基类 + * 提供可以刷新的方法 + * + * @author Fly + * @e-mail 1285760616@qq.com + * @time 2018/3/22 + */ +public class BaseFragmentPagerAdapter extends FragmentPagerAdapter { + private List mFragmentList; + private FragmentManager mFragmentManager; + /**下面两个值用来保存Fragment的位置信息,用以判断该位置是否需要更新*/ + private SparseArray mFragmentPositionMap; + private SparseArray mFragmentPositionMapAfterUpdate; + + public BaseFragmentPagerAdapter(FragmentManager fm, List fragments) { + super(fm); + mFragmentList = fragments; + mFragmentManager = fm; + mFragmentList = fragments; + mFragmentPositionMap = new SparseArray<>(); + mFragmentPositionMapAfterUpdate = new SparseArray<>(); + setFragmentPositionMap(); + setFragmentPositionMapForUpdate(); + } + + /** + * 保存更新之前的位置信息,用的键值对结构来保存 + */ + private void setFragmentPositionMap() { + mFragmentPositionMap.clear(); + for (int i = 0; i < mFragmentList.size(); i++) { + mFragmentPositionMap.put(Long.valueOf(getItemId(i)).intValue(), String.valueOf(i)); + } + } + + /** + * 保存更新之后的位置信息,用的键值对结构来保存 + */ + private void setFragmentPositionMapForUpdate() { + mFragmentPositionMapAfterUpdate.clear(); + for (int i = 0; i < mFragmentList.size(); i++) { + mFragmentPositionMapAfterUpdate.put(Long.valueOf(getItemId(i)).intValue(), String.valueOf(i)); + } + } + + /** + * 在此方法中找到需要更新的位置返回POSITION_NONE,否则返回POSITION_UNCHANGED即可 + */ + @Override + public int getItemPosition(Object object) { + int hashCode = object.hashCode(); + //查找object在更新后的列表中的位置 + String position = mFragmentPositionMapAfterUpdate.get(hashCode); + //更新后的列表中不存在该object的位置了 + if (position == null) { + return POSITION_NONE; + } else { + //如果更新后的列表中存在该object的位置, 查找该object之前的位置并判断位置是否发生了变化 + int size = mFragmentPositionMap.size(); + for (int i = 0; i < size ; i++) { + int key = mFragmentPositionMap.keyAt(i); + if (key == hashCode) { + String index = mFragmentPositionMap.get(key); + if (position.equals(index)) { + //位置没变依然返回POSITION_UNCHANGED + return POSITION_UNCHANGED; + } else { + //位置变了 + return POSITION_NONE; + } + } + } + } + return POSITION_UNCHANGED; + } + + /** + * 将指定的Fragment替换/更新为新的Fragment + * @param oldFragment 旧Fragment + * @param newFragment 新Fragment + */ + public void replaceFragment(Fragment oldFragment, Fragment newFragment) { + int position = mFragmentList.indexOf(oldFragment); + if (position == -1) { + return; + } + //从Transaction移除旧的Fragment + removeFragmentInternal(oldFragment); + //替换List中对应的Fragment + mFragmentList.set(position, newFragment); + //刷新Adapter + notifyItemChanged(); + } + + /** + * 将指定位置的Fragment替换/更新为新的Fragment,同{@link #replaceFragment(Fragment oldFragment, Fragment newFragment)} + * @param position 旧Fragment的位置 + * @param newFragment 新Fragment + */ + public void replaceFragment(int position, Fragment newFragment) { + Fragment oldFragment = mFragmentList.get(position); + removeFragmentInternal(oldFragment); + mFragmentList.set(position, newFragment); + notifyItemChanged(); + } + + /** + * 移除指定的Fragment + * @param fragment 目标Fragment + */ + public void removeFragment(Fragment fragment) { + //先从List中移除 + mFragmentList.remove(fragment); + //然后从Transaction移除 + removeFragmentInternal(fragment); + //最后刷新Adapter + notifyItemChanged(); + } + + /** + * 移除指定位置的Fragment,同 {@link #removeFragment(Fragment fragment)} + * @param position + */ + public void removeFragment(int position) { + Fragment fragment = mFragmentList.get(position); + //然后从List中移除 + mFragmentList.remove(fragment); + //先从Transaction移除 + removeFragmentInternal(fragment); + //最后刷新Adapter + notifyItemChanged(); + } + + /** + * 添加Fragment + * @param fragment 目标Fragment + */ + public void addFragment(Fragment fragment) { + mFragmentList.add(fragment); + notifyItemChanged(); + } + + /** + * 在指定位置插入一个Fragment + * @param position 插入位置 + * @param fragment 目标Fragment + */ + public void insertFragment(int position, Fragment fragment) { + mFragmentList.add(position, fragment); + notifyItemChanged(); + } + + public void notifyItemChanged() { + //刷新之前重新收集位置信息 + setFragmentPositionMapForUpdate(); + notifyDataSetChanged(); + setFragmentPositionMap(); + } + + /** + * 从Transaction移除Fragment + * @param fragment 目标Fragment + */ + private void removeFragmentInternal(Fragment fragment) { + FragmentTransaction transaction = mFragmentManager.beginTransaction(); + transaction.remove(fragment); + transaction.commitAllowingStateLoss(); + } + + /** + * 此方法不用position做返回值即可破解fragment tag异常的错误 + */ + @Override + public long getItemId(int position) { + // 获取当前数据的hashCode,其实这里不用hashCode用自定义的可以关联当前Item对象的唯一值也可以,只要不是直接返回position + return mFragmentList.get(position).hashCode(); + } + + @Override + public Fragment getItem(int position) { + return mFragmentList.get(position); + } + + @Override + public int getCount() { + return mFragmentList.size(); + } + + public List getFragments() { + return mFragmentList; + } +} diff --git a/app/src/main/java/com/uiui/videoplayer/base/BaseLightActivity.java b/app/src/main/java/com/uiui/videoplayer/base/BaseRxActivity.java similarity index 61% rename from app/src/main/java/com/uiui/videoplayer/base/BaseLightActivity.java rename to app/src/main/java/com/uiui/videoplayer/base/BaseRxActivity.java index 26758b2..99100c7 100644 --- a/app/src/main/java/com/uiui/videoplayer/base/BaseLightActivity.java +++ b/app/src/main/java/com/uiui/videoplayer/base/BaseRxActivity.java @@ -1,12 +1,9 @@ package com.uiui.videoplayer.base; -import android.graphics.Color; import android.os.Bundle; import androidx.annotation.CallSuper; import androidx.annotation.CheckResult; -import androidx.annotation.ContentView; -import androidx.annotation.LayoutRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; @@ -16,23 +13,19 @@ import com.trello.rxlifecycle4.LifecycleTransformer; import com.trello.rxlifecycle4.RxLifecycle; import com.trello.rxlifecycle4.android.ActivityEvent; import com.trello.rxlifecycle4.android.RxLifecycleAndroid; -import com.uiui.videoplayer.R; -import com.zackratos.ultimatebarx.ultimatebarx.java.UltimateBarX; import io.reactivex.rxjava3.core.Observable; import io.reactivex.rxjava3.subjects.BehaviorSubject; +/** + * {@link com.trello.rxlifecycle4.components.RxActivity} + * copied form RxActivity} + */ +public abstract class BaseRxActivity extends AppCompatActivity implements LifecycleProvider { + private final BehaviorSubject lifecycleSubject = BehaviorSubject.create(); -public abstract class BaseLightActivity extends AppCompatActivity implements LifecycleProvider { - public final BehaviorSubject lifecycleSubject = BehaviorSubject.create(); - - public BaseLightActivity() { - super(); - } - - @ContentView - public BaseLightActivity(@LayoutRes int contentLayoutId) { - super(contentLayoutId); + public BehaviorSubject getLifecycleSubject() { + return lifecycleSubject; } @Override @@ -61,40 +54,8 @@ public abstract class BaseLightActivity extends AppCompatActivity implements Lif protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); lifecycleSubject.onNext(ActivityEvent.CREATE); -// StatusBarUtil.init(this); - setContentView(this.getLayoutId()); - UltimateBarX.statusBar(this) -// .transparent() - .colorRes(R.color.colorAccent) - .fitWindow(true) - .light(false) - .apply(); - UltimateBarX.navigationBar(this) - .transparent() -// .color(Color.TRANSPARENT) - .fitWindow(false) - .light(false) - .apply(); - initView(); - initData(); } - /** - * 设置布局 - */ - public abstract int getLayoutId(); - - /** - * 初始化视图 - */ - public abstract void initView(); - - - /** - * 初始化数据 - */ - public abstract void initData(); - @Override @CallSuper protected void onStart() { @@ -130,3 +91,4 @@ public abstract class BaseLightActivity extends AppCompatActivity implements Lif super.onDestroy(); } } + diff --git a/app/src/main/java/com/uiui/videoplayer/base/BaseTransparentActivity.java b/app/src/main/java/com/uiui/videoplayer/base/BaseTransparentActivity.java new file mode 100644 index 0000000..dfb8c1c --- /dev/null +++ b/app/src/main/java/com/uiui/videoplayer/base/BaseTransparentActivity.java @@ -0,0 +1,45 @@ +package com.uiui.videoplayer.base; + +import android.os.Bundle; + +import androidx.annotation.CallSuper; +import androidx.annotation.Nullable; + +import com.uiui.videoplayer.R; +import com.zackratos.ultimatebarx.ultimatebarx.java.UltimateBarX; + +public abstract class BaseTransparentActivity extends BaseRxActivity { + + public BaseTransparentActivity() { + super(); + } + + @Override + @CallSuper + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); +// StatusBarUtil.init(this); + UltimateBarX.statusBar(this) + .transparent() + .colorRes(R.color.colorPrimaryDark) + .light(setNightMode()) + .fitWindow(true) + .apply(); + UltimateBarX.navigationBar(this) + .transparent() + .colorRes(R.color.colorPrimaryDark) + .light(setNightMode()) + .fitWindow(true) + .apply(); + } + + /** + * 设置布局 + */ + protected abstract int getLayoutId(); + + /** + * @return 是否是黑色状态栏 + */ + protected abstract boolean setNightMode(); +} \ No newline at end of file diff --git a/app/src/main/java/com/uiui/videoplayer/base/mvvm/BaseMvvmActivity.java b/app/src/main/java/com/uiui/videoplayer/base/mvvm/BaseMvvmActivity.java new file mode 100644 index 0000000..2a091c0 --- /dev/null +++ b/app/src/main/java/com/uiui/videoplayer/base/mvvm/BaseMvvmActivity.java @@ -0,0 +1,54 @@ +package com.uiui.videoplayer.base.mvvm; + +import android.os.Bundle; +import android.util.Log; + +import androidx.annotation.Nullable; +import androidx.databinding.DataBindingUtil; +import androidx.databinding.ViewDataBinding; +import androidx.lifecycle.ViewModel; +import androidx.lifecycle.ViewModelProvider; + +import com.uiui.videoplayer.base.BaseTransparentActivity; + +import java.lang.reflect.Modifier; +import java.lang.reflect.ParameterizedType; + +public abstract class BaseMvvmActivity extends BaseTransparentActivity { + + private static final String TAG = BaseMvvmActivity.class.getSimpleName(); + + protected VM mViewModel; + protected VDB mViewDataBinding; + protected Class vmClass; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + //ViewDataBinding + mViewDataBinding = DataBindingUtil.setContentView(this, getLayoutId()); + mViewDataBinding.setLifecycleOwner(this); + //ViewModel + vmClass = (Class) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0]; + boolean isAbstract = Modifier.isAbstract(vmClass.getModifiers()); + Log.e(TAG, "isLocalClass:" + vmClass.getSimpleName().equals(ViewModel.class.getSimpleName()) + " isAbstract:" + isAbstract); + if (!isAbstract) {//不是一个抽象类 + mViewModel = new ViewModelProvider(this).get(vmClass); + } + initDataBinding(); + initView(); + initData(); + } + + protected abstract void initDataBinding(); + + /** + * 初始化视图 + */ + protected abstract void initView(); + + /** + * 初始化数据 + */ + protected abstract void initData(); +} diff --git a/app/src/main/java/com/uiui/videoplayer/base/mvvm/BaseViewModel.java b/app/src/main/java/com/uiui/videoplayer/base/mvvm/BaseViewModel.java new file mode 100644 index 0000000..e84064b --- /dev/null +++ b/app/src/main/java/com/uiui/videoplayer/base/mvvm/BaseViewModel.java @@ -0,0 +1,73 @@ +package com.uiui.videoplayer.base.mvvm; + +import android.content.Context; + +import androidx.databinding.ViewDataBinding; +import androidx.lifecycle.ViewModel; + +import com.trello.rxlifecycle4.android.ActivityEvent; + +import java.lang.ref.WeakReference; + +import io.reactivex.rxjava3.subjects.BehaviorSubject; + +/** + * 所有viewmodel的基类 + */ +public abstract class BaseViewModel extends ViewModel implements ViewDataBindingCallback { + + /** + * 当前viewmodel对应的页面binding + */ + protected VDB binding; + + @Override + public void setVDBinding(ViewDataBinding vdBinding) { + + binding = (VDB)vdBinding; + } + + @Override + public VDB getVDBinding() { + if (binding == null) { + throw new NullPointerException("BaseViewModel >> getVDBinding >> null!!!"); + } + return binding; + } + + + /** + * 上下文 + */ + private WeakReference ctx; + + @Override + public void setCtx(Context context) { + if(ctx == null) { + ctx = new WeakReference<>(context); + } + } + + @Override + public Context getCtx() { + if (ctx == null) { + throw new NullPointerException("BaseViewModel >> getCtx >> null!!!"); + } + return ctx.get(); + } + + + public abstract void onDestroy(); + + private BehaviorSubject mBehaviorSubject; + + @Override + public void setLifecycle(BehaviorSubject subject) { + this.mBehaviorSubject =subject; + } + + @Override + public BehaviorSubject getLifecycle() { + return mBehaviorSubject; + } +} diff --git a/app/src/main/java/com/uiui/videoplayer/base/mvvm/ViewDataBindingCallback.java b/app/src/main/java/com/uiui/videoplayer/base/mvvm/ViewDataBindingCallback.java new file mode 100644 index 0000000..80488db --- /dev/null +++ b/app/src/main/java/com/uiui/videoplayer/base/mvvm/ViewDataBindingCallback.java @@ -0,0 +1,26 @@ +package com.uiui.videoplayer.base.mvvm; + +import android.content.Context; + +import androidx.databinding.ViewDataBinding; + +import com.trello.rxlifecycle4.android.ActivityEvent; + +import io.reactivex.rxjava3.subjects.BehaviorSubject; + +public interface ViewDataBindingCallback { + + + void setVDBinding(VDB binding); + + VDB getVDBinding() throws NullPointerException; + + + void setCtx(Context context); + + Context getCtx() throws NullPointerException; + + void setLifecycle(BehaviorSubject subject); + + BehaviorSubject getLifecycle(); +} diff --git a/app/src/main/java/com/uiui/videoplayer/fragment/pic/PictureFragment.java b/app/src/main/java/com/uiui/videoplayer/fragment/pic/PictureFragment.java index 9ad1f0a..7286e80 100644 --- a/app/src/main/java/com/uiui/videoplayer/fragment/pic/PictureFragment.java +++ b/app/src/main/java/com/uiui/videoplayer/fragment/pic/PictureFragment.java @@ -17,15 +17,13 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; -import android.widget.ImageView; import com.uiui.videoplayer.R; -import com.uiui.videoplayer.activity.pic.GalleryPresenter; +import com.uiui.videoplayer.adapter.EquallyDividedItemDecoration; import com.uiui.videoplayer.adapter.PicAdapter; -import com.uiui.videoplayer.adapter.RecyclerViewSpacesItemDecoration; -import com.uiui.videoplayer.base.BGAGridDivider; import com.uiui.videoplayer.base.BaseFragment; import com.uiui.videoplayer.bean.PhotoInfo; +import com.uiui.videoplayer.utils.ScreenUtils; import com.uiui.videoplayer.utils.ToastUtil; import java.util.ArrayList; @@ -127,20 +125,12 @@ public class PictureFragment extends BaseFragment implements PictureContact.Pict mPresenter.attachView(this); GridLayoutManager layoutManager = new GridLayoutManager(mContext, SPAN_COUNT, LinearLayoutManager.VERTICAL, false); - HashMap stringIntegerHashMap = new HashMap<>(); - WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); - DisplayMetrics dm = new DisplayMetrics(); - wm.getDefaultDisplay().getRealMetrics(dm); - float density = dm.density; // 屏幕密度(0.75 / 1.0 / 1.5) - stringIntegerHashMap.put(RecyclerViewSpacesItemDecoration.TOP_DECORATION, (int) (density * 1));//top间距 - stringIntegerHashMap.put(RecyclerViewSpacesItemDecoration.BOTTOM_DECORATION, (int) (density * 1));//底部间距 - stringIntegerHashMap.put(RecyclerViewSpacesItemDecoration.LEFT_DECORATION, (int) (density * 20));//左间距 - stringIntegerHashMap.put(RecyclerViewSpacesItemDecoration.RIGHT_DECORATION, (int) (density * 20));//右间距 - recyclerView.addItemDecoration(new RecyclerViewSpacesItemDecoration(stringIntegerHashMap)); + recyclerView.setLayoutManager(layoutManager); + + EquallyDividedItemDecoration equallyDividedItemDecoration = new EquallyDividedItemDecoration(SPAN_COUNT, ScreenUtils.dip2px(mContext, 1)); + recyclerView.addItemDecoration(equallyDividedItemDecoration); mPicAdapter = new PicAdapter(layoutManager); - recyclerView.setLayoutManager(layoutManager); - recyclerView.addItemDecoration(BGAGridDivider.newInstanceWithSpaceRes(R.dimen.dp_2)); recyclerView.setAdapter(mPicAdapter); swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override diff --git a/app/src/main/java/com/uiui/videoplayer/fragment/video/VideoFragment.java b/app/src/main/java/com/uiui/videoplayer/fragment/video/VideoFragment.java index 1bcf329..aa3e98d 100644 --- a/app/src/main/java/com/uiui/videoplayer/fragment/video/VideoFragment.java +++ b/app/src/main/java/com/uiui/videoplayer/fragment/video/VideoFragment.java @@ -1,23 +1,16 @@ package com.uiui.videoplayer.fragment.video; import android.app.Activity; -import android.content.Context; -import android.content.res.Configuration; import android.os.Bundle; -import android.util.DisplayMetrics; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.view.WindowManager; -import android.widget.ImageView; -import android.widget.TextView; import androidx.constraintlayout.widget.ConstraintLayout; import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.DefaultItemAnimator; import androidx.recyclerview.widget.RecyclerView; -import androidx.recyclerview.widget.SimpleItemAnimator; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import com.arialyy.annotations.Download; @@ -25,22 +18,19 @@ import com.arialyy.aria.core.Aria; import com.arialyy.aria.core.task.DownloadTask; import com.google.gson.JsonObject; import com.uiui.videoplayer.R; -import com.uiui.videoplayer.activity.video.VideoActivity; -import com.uiui.videoplayer.adapter.RecyclerViewSpacesItemDecoration; +import com.uiui.videoplayer.adapter.EquallyDividedItemDecoration; import com.uiui.videoplayer.adapter.VideoAdapter; import com.uiui.videoplayer.base.BaseFragment; import com.uiui.videoplayer.base.CustomDialog; import com.uiui.videoplayer.base.RecycleGridLayoutManager; -import com.uiui.videoplayer.base.SpacesItemDecoration; import com.uiui.videoplayer.bean.LocalVideoInfo; import com.uiui.videoplayer.gson.GsonUtils; +import com.uiui.videoplayer.utils.ScreenUtils; import com.uiui.videoplayer.utils.ToastUtil; import com.uiui.videoplayer.utils.VideoUtils; import java.io.File; import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; @@ -65,8 +55,9 @@ public class VideoFragment extends BaseFragment implements VideoContact.VideoVie private VideoPresenter mPresenter; private RecycleGridLayoutManager mManager; - private VideoAdapter adapter; - + private VideoAdapter mVideoAdapter; + private static final int SPAN_COUNT = 3; + // TODO: Rename parameter arguments, choose names that match // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER private static final String ARG_PARAM1 = "param1"; @@ -145,38 +136,22 @@ public class VideoFragment extends BaseFragment implements VideoContact.VideoVie refreshLayout.setRefreshing(true); } }); -// ((SimpleItemAnimator) recyclerView.getItemAnimator()).setSupportsChangeAnimations(false); -// int orientation = getResources().getConfiguration().orientation; -// if (orientation == Configuration.ORIENTATION_LANDSCAPE) { -// mManager = new RecycleGridLayoutManager(mContext, 4); -// } else if (orientation == Configuration.ORIENTATION_PORTRAIT) { - mManager = new RecycleGridLayoutManager(mContext, 3); -// } - - HashMap stringIntegerHashMap = new HashMap<>(); - WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); - DisplayMetrics dm = new DisplayMetrics(); - wm.getDefaultDisplay().getRealMetrics(dm); - float density = dm.density; // 屏幕密度(0.75 / 1.0 / 1.5) - stringIntegerHashMap.put(RecyclerViewSpacesItemDecoration.TOP_DECORATION, (int) (density * 1));//top间距 - stringIntegerHashMap.put(RecyclerViewSpacesItemDecoration.BOTTOM_DECORATION, (int) (density * 1));//底部间距 - stringIntegerHashMap.put(RecyclerViewSpacesItemDecoration.LEFT_DECORATION, (int) (density * 20));//左间距 - stringIntegerHashMap.put(RecyclerViewSpacesItemDecoration.RIGHT_DECORATION, (int) (density * 20));//右间距 - recyclerView.addItemDecoration(new RecyclerViewSpacesItemDecoration(stringIntegerHashMap)); - + mManager = new RecycleGridLayoutManager(mContext, SPAN_COUNT); recyclerView.setLayoutManager(mManager); + + EquallyDividedItemDecoration equallyDividedItemDecoration = new EquallyDividedItemDecoration(SPAN_COUNT, ScreenUtils.dip2px(mContext, 1)); + recyclerView.addItemDecoration(equallyDividedItemDecoration); recyclerView.setNestedScrollingEnabled(false); - recyclerView.addItemDecoration(new SpacesItemDecoration(getResources().getDimensionPixelSize(R.dimen.PX1x), getResources().getDimensionPixelSize(R.dimen.PX1x), - getResources().getDimensionPixelSize(R.dimen.PX1x), getResources().getDimensionPixelSize(R.dimen.PX1x))); + ((DefaultItemAnimator) recyclerView.getItemAnimator()).setSupportsChangeAnimations(false); - adapter = new VideoAdapter(mContext); - adapter.setOnLongClickListener(new VideoAdapter.onItemLongClickListener() { + mVideoAdapter = new VideoAdapter(mContext); + mVideoAdapter.setOnLongClickListener(new VideoAdapter.onItemLongClickListener() { @Override public void onItemLongClick(String path, int position) { showDialog(path, position); } }); - recyclerView.setAdapter(adapter); + recyclerView.setAdapter(mVideoAdapter); mPresenter.getHomeVideo(); refreshLayout.setRefreshing(true); @@ -194,7 +169,7 @@ public class VideoFragment extends BaseFragment implements VideoContact.VideoVie dialog.dismiss(); File file = new File(path); if (file.delete()) { - adapter.removeItem(position); + mVideoAdapter.removeItem(position); ToastUtil.show("删除成功"); } else { ToastUtil.show("删除失败,检查权限是否开启"); @@ -219,7 +194,7 @@ public class VideoFragment extends BaseFragment implements VideoContact.VideoVie } else { cl_nodata.setVisibility(View.GONE); recyclerView.setVisibility(View.VISIBLE); - adapter.setData(video); + mVideoAdapter.setData(video); } refreshLayout.setRefreshing(false); } @@ -230,10 +205,6 @@ public class VideoFragment extends BaseFragment implements VideoContact.VideoVie } - - - - //在这里处理任务执行中的状态,如进度进度条的刷新 @Download.onTaskRunning void running(DownloadTask task) { diff --git a/app/src/main/java/com/uiui/videoplayer/utils/Utils.java b/app/src/main/java/com/uiui/videoplayer/utils/Utils.java index 2e3a28b..4e82883 100644 --- a/app/src/main/java/com/uiui/videoplayer/utils/Utils.java +++ b/app/src/main/java/com/uiui/videoplayer/utils/Utils.java @@ -33,7 +33,9 @@ public class Utils { if (fileS == 0) { return wrongSize; } - if (fileS < 1048576) { + if (fileS < 1024) { + fileSizeString = df.format((double) fileS) + "MB"; + } else if (fileS < 1048576) { fileSizeString = df.format((double) fileS / 1024) + "GB"; } else { fileSizeString = df.format((double) fileS / 1048576) + "TB"; diff --git a/app/src/main/res/drawable-hdpi/icon_vip.png b/app/src/main/res/drawable-hdpi/icon_vip.png new file mode 100644 index 0000000..e88a4e6 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/icon_vip.png differ diff --git a/app/src/main/res/drawable-hdpi/status_download.png b/app/src/main/res/drawable-hdpi/status_download.png index fd0259a..2081bff 100644 Binary files a/app/src/main/res/drawable-hdpi/status_download.png and b/app/src/main/res/drawable-hdpi/status_download.png differ diff --git a/app/src/main/res/drawable/bt_vip_backround.xml b/app/src/main/res/drawable/bt_vip_backround.xml new file mode 100644 index 0000000..3e590f9 --- /dev/null +++ b/app/src/main/res/drawable/bt_vip_backround.xml @@ -0,0 +1,17 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/vip_background.xml b/app/src/main/res/drawable/vip_background.xml new file mode 100644 index 0000000..f5e4b3c --- /dev/null +++ b/app/src/main/res/drawable/vip_background.xml @@ -0,0 +1,17 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index b426d7f..de1597b 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,267 +1,137 @@ - + + + + + + android:layout_width="match_parent" + android:layout_height="match_parent"> - - - - + app:layout_constraintTop_toTopOf="parent"> - - - - - + app:layout_constraintTop_toTopOf="parent"> + + + + + + - + android:layout_width="match_parent" + android:layout_height="0dp" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintTop_toBottomOf="@id/constraintLayout2"> - + app:layout_constraintTop_toTopOf="parent" + app:tl_indicator_color="@color/black" + app:tl_indicator_style="NORMAL" + app:tl_indicator_width_equal_title="true" + app:tl_tab_space_equal="true" + app:tl_textBold="SELECT" + app:tl_textSelectColor="@color/black" + app:tl_textSelectSize="@dimen/sp_11" + app:tl_textSize="@dimen/sp_10" + app:tl_textUnSelectColor="@color/gray" + app:tl_textUnSelectSize="@dimen/sp_10" /> - - - - - + app:layout_constraintTop_toBottomOf="@id/main_sliding_tab_layout" /> - - - - - - - - - - + - - - - - - - - - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main_land.xml b/app/src/main/res/layout/activity_main_land.xml new file mode 100644 index 0000000..b426d7f --- /dev/null +++ b/app/src/main/res/layout/activity_main_land.xml @@ -0,0 +1,267 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_vip.xml b/app/src/main/res/layout/activity_vip.xml new file mode 100644 index 0000000..ec361d1 --- /dev/null +++ b/app/src/main/res/layout/activity_vip.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_picture.xml b/app/src/main/res/layout/fragment_picture.xml index 253ee09..a87e10e 100644 --- a/app/src/main/res/layout/fragment_picture.xml +++ b/app/src/main/res/layout/fragment_picture.xml @@ -1,9 +1,9 @@ + android:layout_height="match_parent"> diff --git a/app/src/main/res/layout/fragment_video.xml b/app/src/main/res/layout/fragment_video.xml index f74d4fe..7af5d08 100644 --- a/app/src/main/res/layout/fragment_video.xml +++ b/app/src/main/res/layout/fragment_video.xml @@ -1,9 +1,9 @@ + android:layout_height="match_parent"> + android:layout_height="match_parent" + android:overScrollMode="never" /> @@ -18,10 +18,8 @@ android:id="@+id/video_image" android:layout_width="match_parent" android:layout_height="match_parent" - android:layout_marginTop="@dimen/dp_2" android:adjustViewBounds="true" android:scaleType="centerCrop" - app:corner_radius="@dimen/dp_4" app:is_cover_src="true" /> Hello blank fragment + 免费存储空间:%s/%s + 剩余使用空间:%s diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index c8050c6..fd8f794 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -7,15 +7,16 @@ @color/colorAccent @color/colorBackground ?attr/colorPrimary + - - - - - - - + + + + + + + + + diff --git a/app/src/uiui/java/com/uiui/sn/manager/RemoteManager.java b/app/src/uiui/java/com/uiui/sn/manager/RemoteManager.java index e7e594b..0dcd2dc 100644 --- a/app/src/uiui/java/com/uiui/sn/manager/RemoteManager.java +++ b/app/src/uiui/java/com/uiui/sn/manager/RemoteManager.java @@ -25,6 +25,8 @@ public class RemoteManager { public static final String hidePackageKey = "HIDE_PACKAGE_NAME"; public static final String disablePackageKey = "DISABLE_PACKAGE_NAME"; + private static boolean mServiceConnected = false; + @SuppressLint("StaticFieldLeak") private static RemoteManager sInstance; private Context mContext; @@ -41,6 +43,7 @@ public class RemoteManager { @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.e(TAG, "onServiceConnected: " + name); + mServiceConnected = true; mIGetInfoInterface = IGetInfoInterface.Stub.asInterface(service); try { for (ConnectedListener listener : mListeners) { @@ -102,6 +105,9 @@ public class RemoteManager { public void setListener(ConnectedListener listener) { mListeners.add(listener); + if (mServiceConnected) { + listener.onConnected(); + } } public void removeListener(ConnectedListener listener) { diff --git a/settings.gradle b/settings.gradle index 783af2e..abac977 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,2 +1,2 @@ rootProject.name='UIUI家庭空间' -include ':app', ':JZVideo', ':niceimageview' +include ':app', ':JZVideo', ':niceimageview', ':FlycoTabLayoutZ_Lib'