美文网首页Android控件Android收藏文章Android
MagicIndicator系列之三 —— MagicInd

MagicIndicator系列之三 —— MagicInd

作者: hackware | 来源:发表于2016-07-24 15:30 被阅读15992次

    这是 MagicIndicator 系列的第三篇文章,如果你没有看过前两篇,建议出门先看一下。当然你不看也没关系,我用一句话来介绍它: MagicIndicator 是一个可定制、易扩展的页面指示器框架,使用它可极大的简化页面指示器的开发。

    本文将给大家简单阐述 MagicIndicator 的原理,并介绍 4 种扩展 MagicIndicator 的方式,分别是:

    1. 继承 IPagerNavigator 打造任意的指示效果
    2. 继承 IPagerTitleView 打造任意效果的指示器标题
    3. 继承 IPagerIndicator 打造任意效果的指示器
    4. 使用 CommonPagerTitleView 加载自定义布局

    使用这四种方法,基本可以搞定所有的指示器效果,没有做不到,只有想不到!

    原理浅析


    MagicIndicator 其实非常简单。和其它所有指示器框架一样,也是通过监听 ViewPager.OnPageChangeListener 来实现切换效果的。但 MagicIndicator 有两点明显不同:

    • MagicIndicator 不提供 setViewPager 方法来和 ViewPager 强绑定,因此在不使用 ViewPager 的情况下(比如手动切换 Fragment,轻量级的广告轮播控件,ViewFlipper 等),也是可以使用 MagicIndicator 的,只需要你手动调用 onPageXXX 系列方法。

    • MagicIndicator 将指示器进行了抽象,意在通过扩展来实现不同的切换效果,而不是像其他所有指示器框架那样,提供了一大堆的 setter 方法,却只能实现很有限的切换效果。

    在布局文件中使用的 <MagicIndicator/> 标签,本质上就是一个 FrameLayout:

    public class MagicIndicator extends FrameLayout {
        private IPagerNavigator mNavigator;
    
        public MagicIndicator(Context context) {...}
    
        public MagicIndicator(Context context, AttributeSet attrs) {...}
    
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
            if (mNavigator != null) {
                mNavigator.onPageScrolled(position, positionOffset, positionOffsetPixels);
            }
        }
    
        public void onPageSelected(int position) {
            if (mNavigator != null) {
                mNavigator.onPageSelected(position);
            }
        }
    
        public void onPageScrollStateChanged(int state) {
            if (mNavigator != null) {
                mNavigator.onPageScrollStateChanged(state);
            }
        }
    
        public void setNavigator(IPagerNavigator navigator) {...}
    }
    

    MagicIndicator 中,指示器(也许叫导航器更为恰当)被抽象成了 IPagerNavigator,设置到 MagicIndicator 类中的 IPagerNavigator 被作为唯一的子元素添加到其中。onPageXXX 系列回调原封不动的传递给了 IPagerNavigator。因此,要想实现不同的指示器效果,只需继承任意的 View 并实现 IPagerNavigator 接口即可。

    考虑大多数情况下的指示器(导航器)都类似下面的效果:

    magicindicator.gif

    MagicIndicator 中内置了一个 CommonNavigator 来简化这样的指示器(导航器)的开发,CommonNavigator 继承了 FrameLayout 并实现了 IPagerNavigator 接口,并根据指示器标题是否可变(数目是否可变,比如新闻应用的频道数就可变)来加载不同的子元素(布局文件),如下:

    指示器标题可变,可滚动

    <?xml version="1.0" encoding="utf-8"?>
    <HorizontalScrollView xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/scroll_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fadingEdge="none"
        android:scrollbars="none">
    
        <FrameLayout
            android:layout_width="wrap_content"
            android:layout_height="match_parent">
    
            <LinearLayout
                android:id="@+id/indicator_container"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="horizontal" />
    
            <LinearLayout
                android:id="@+id/title_container"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:orientation="horizontal" />
    
        </FrameLayout>
    
    </HorizontalScrollView>
    

    指示器标题不可变

    <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <LinearLayout
            android:id="@+id/indicator_container"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="horizontal" />
    
        <LinearLayout
            android:id="@+id/title_container"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="horizontal" />
    
    </FrameLayout>
    

    这两个布局中都有两个 LinearLayout,分别是 indicator_container 和 title_container,它俩被放在一个 FrameLayout 中,我想你已经明白了:指示器标题在指示器的上方,分别位于两层,互不影响。indicator_container 的宽高和 title_container 相等

    title_container 的子元素被抽象成了 IPagerTitleView,如下:

    public interface IPagerTitleView {
        /**
         * 被选中
         */
        void onSelected(int index, int totalCount);
    
        /**
         * 未被选中
         */
        void onDeselected(int index, int totalCount);
    
        /**
         * 离开
         *
         * @param leavePercent 离开的百分比, 0.0f - 1.0f
         * @param leftToRight  从左至右离开
         */
        void onLeave(int index, int totalCount, float leavePercent, boolean leftToRight);
    
        /**
         * 进入
         *
         * @param enterPercent 进入的百分比, 0.0f - 1.0f
         * @param leftToRight  从左至右进入
         */
        void onEnter(int index, int totalCount, float enterPercent, boolean leftToRight);
    }
    

    onPageXXX 系列回调被 NavigatorHelper 转换成了 onEnter、onLeave、onSelected、onDeselected 4 个回调传递给 IPagerTitleView。通过这 4 个回调,可实现各种各样炫酷的效果。关于 onEnter 和 onLeave 回调,我打个比方:从 ViewPager 的第 2 页切换到第 3 页过程中,第 2 个 IPagerTitleView 会不断收到 onLeave 回调,leavePerent 从 0.0f 渐变为 1.0f,leftToRight 始终为 true,第 3 个 IPagerTitleView 会不断收到 onEnter 回调, enterPercent 从 0.0f 渐变成 1.0f,leftToRight 始终为 true。

    indicator_container 仅有一个子元素且它被抽象成了 IPagerIndicator:

    public interface IPagerIndicator {
        void onPageScrolled(int position, float positionOffset, int positionOffsetPixels);
    
        void onPageSelected(int position);
    
        void onPageScrollStateChanged(int state);
    
        void onPositionDataProvide(List<PositionData> dataList);
    }
    

    onPageXXX 系列回调原封不动的传递给了它,此外,还有个最重要的 onPositionDataProvide 回调,这个是干嘛的呢?试想一下,如果要使得扩展 IPagerIndicator 可以实现任意的切换效果,那最起码应该把每一个 IPagerTitleView 的位置信息传递给 IPagerIndicator 吧,有了这些位置信息,继承 View 并实现 IPagerIndicator 后,不论是画圆还是画直线,或是画上图中的贝塞尔吸附式效果,才有坐标可循啊。

    我们看一下 PositionData 类:

    public class PositionData {
        public int mLeft;
        public int mTop;
        public int mRight;
        public int mBottom;
        public int mContentLeft;
        public int mContentTop;
        public int mContentRight;
        public int mContentBottom;
    
        public int width() {
            return mRight - mLeft;
        }
    
        public int height() {
            return mBottom - mTop;
        }
    
        public int contentWidth() {
            return mContentRight - mContentLeft;
        }
    
        public int contentHeight() {
            return mContentBottom - mContentTop;
        }
    
        public int horizontalCenter() {
            return mLeft + width() / 2;
        }
    
        public int verticalCenter() {
            return mTop + height() / 2;
        }
    }
    

    PositionData 中不仅封装了 IPagerTitleView 上下左右的位置,还封装了其内容区域的位置,有内容区域的位置,我们才可能实现上图中第三个指示器效果:不论 IPagerTitleView 的宽度如何变化,直线宽度始终和内容宽度相等

    由于 IPagerTitleView 是抽象的,CommonNavigator 不可能知道其内容区域的边界到底在哪里,因此还得我们告诉它,要提供内容边界给 CommonNavigator,实现 IMeasurablePagerTitleView 即可:

    public interface IMeasurablePagerTitleView extends IPagerTitleView {
        int getContentLeft();
    
        int getContentTop();
    
        int getContentRight();
    
        int getContentBottom();
    }
    

    如果不实现 IMeasuablePagerTitleView,则默认内容区域边界就是 IPagerTitleView 的边界(mLeft,mTop,mRight,mBottom)。

    继承 IPagerNavigator


    一般情况下,使用 CommonNavigator 就能满足需求。但是当遇到一些明显 CommonNavigator 搞不定的情况,比如 Smartisan OS 桌面的指示器效果:

    smartisan.gif

    就需要继承 View,实现 IPagerNavigator 接口,拿起手里的 Canvas 开画吧!

    额,今天就不去实现这个效果了,因为需要处理的细节比较多,后面我处理好后会把这个效果上传到 demo 中,我们来个简单的,效果如下:

    custom_indicator.gif

    这个效果没有跟随手指的过渡,看起来比较呆板,我就叫它 DummyCircleNavigator 吧:

    public class DummyCircleNavigator extends View implements IPagerNavigator {
    
        public DummyCircleNavigator(Context context) {
            super(context);
        }
    
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        }
    
        @Override
        public void onPageSelected(int position) {
        }
    
        @Override
        public void onPageScrollStateChanged(int state) {
        }
    
        // 被添加到 magicindicator 时调用
        @Override
        public void onAttachToMagicIndicator() {
        }
    
        // 从 magicindicator 上移除时调用
        @Override
        public void onDetachFromMagicIndicator() {
        }
    
        // 当指示数目改变时调用
        @Override
        public void notifyDataSetChanged() {
        }
    }
    

    除了实现 onPageXXX 系列回调,还需要实现 onAttachToMagicIndicator、onDetachFromMagicIndicator、notifyDataSetChanged 三个方法。

    我们需要让外部来配置圆的半径、颜色、数量,圆之间的间距以及圆的描边宽度。同时,我们需要一个变量来表示当前选中了哪一个圆,当然,画笔也必不可少:

    private int mRadius;
    private int mCircleColor;
    private int mStrokeWidth;
    private int mCircleSpacing;
    private int mCurrentIndex;
    private int mCircleCount;
    private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    

    根据用户设置的 mCircleSpacing,mRadius,mCircleCount,结合当前的宽度,我们可以计算出每一个圆的圆心位置:

    private List<PointF> mCirclePoints = new ArrayList<PointF>();
    
    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        prepareCirclePoints();
    }
    
    private void prepareCirclePoints() {
        mCirclePoints.clear();
        if (mCircleCount > 0) {
            int y = getHeight() / 2;
            int measureWidth = mCircleCount * mRadius * 2 + (mCircleCount - 1) * mCircleSpacing;
            int centerSpacing = mRadius * 2 + mCircleSpacing;
            int startX = (getWidth() - measureWidth) / 2 + mRadius;
            for (int i = 0; i < mCircleCount; i++) {
                PointF pointF = new PointF(startX, y);
                mCirclePoints.add(pointF);
                startX += centerSpacing;
            }
        }
    }
    

    圆心位置已准备就绪,那就开画吧:

    @Override
    protected void onDraw(Canvas canvas) {
        drawDeselectedCircles(canvas);
        drawSelectedCircle(canvas);
    }
    
    private void drawDeselectedCircles(Canvas canvas) {
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(mStrokeWidth);
        mPaint.setColor(mCircleColor);
        for (int i = 0, j = mCirclePoints.size(); i < j; i++) {
            PointF pointF = mCirclePoints.get(i);
            canvas.drawCircle(pointF.x, pointF.y, mRadius, mPaint);
        }
    }
    
    private void drawSelectedCircle(Canvas canvas) {
        mPaint.setStyle(Paint.Style.FILL);
        if (mCirclePoints.size() > 0) {
            float selectedCircleX = mCirclePoints.get(mCurrentIndex).x;
            canvas.drawCircle(selectedCircleX, getHeight() / 2, mRadius, mPaint);
        }
    }
    

    最后,不要忘了给 mCurrentIndex 赋值,同时,mCircleCount 变化时需要重新计算圆心位置:

    @Override
    public void onPageSelected(int position) {
        mCurrentIndex = position;
        invalidate();
    }
    
    public void setCircleCount(int circleCount) {
        mCircleCount = circleCount;
    }
    
    @Override
    public void notifyDataSetChanged() {
        prepareCirclePoints();
        invalidate();
    }
    

    注意,setCircleCount 方法中,并没有重新计算圆心位置,而是希望外部调用 notifyDataSetChanged 来计算并刷新。希望自定义的 IPagerNavigator 都应该遵守此约定。

    好了,大功告成了,是不是很容易!

    继承 IPagerTitleView


    如果你使用了 CommonNavigator,但是内置的 IPagerTitleView 无法满足需求,那就自定义 IPagerTitleView 吧。比如,简书的这种效果靠内置的 IPagerTitleView 是 hold 不住的:

    jianshu.gif

    因为它既不是跟随手指渐变,也不是抬起手指(onPageSelected)才去改变颜色。而是在滑动一段距离后且手指未抬起时去改变颜色。

    我们来实现这种效果:直接继承 TextView 并实现 IPagerTitleView,在 onEnter 回调中做判断,如果 enterPercent 大于设定的阈值,就将文字颜色设为选中颜色,否则,设为未选中颜色,代码如下:

    public class ColorFlipPagerTitleView extends TextView implements IPagerTitleView {
        private int mNormalColor;
        private int mSelectedColor;
        private float mChangePercent = 0.45f;
    
        public ColorFlipPagerTitleView(Context context) {
            super(context);
            setGravity(Gravity.CENTER);
            int padding = UIUtil.dip2px(context, 10);
            setPadding(padding, 0, padding, 0);
            setSingleLine();
            setEllipsize(TextUtils.TruncateAt.END);
        }
    
        @Override
        public void onLeave(int index, int totalCount, float leavePercent, boolean leftToRight) {
            if (leavePercent >= mChangePercent) {
                setTextColor(mNormalColor);
            } else {
                setTextColor(mSelectedColor);
            }
        }
    
        @Override
        public void onEnter(int index, int totalCount, float enterPercent, boolean leftToRight) {
            if (enterPercent >= mChangePercent) {
                setTextColor(mSelectedColor);
            } else {
                setTextColor(mNormalColor);
            }
        }
    
        // 部分 setter、getter 略
    }
    

    如果你还想提供内容的边界,那就继承 IMeasuablePagerTitleView 吧,并实现以下方法:

    @Override
    public int getContentLeft() {
        Rect bound = new Rect();
        getPaint().getTextBounds(getText().toString(), 0, getText().length(), bound);
        int contentWidth = bound.width();
        return getLeft() + getWidth() / 2 - contentWidth / 2;
    }
    
    @Override
    public int getContentTop() {
        Paint.FontMetrics metrics = getPaint().getFontMetrics();
        float contentHeight = metrics.bottom - metrics.top;
        return (int) (getHeight() / 2 - contentHeight / 2);
    }
    
    @Override
    public int getContentRight() {
        Rect bound = new Rect();
        getPaint().getTextBounds(getText().toString(), 0, getText().length(), bound);
        int contentWidth = bound.width();
        return getLeft() + getWidth() / 2 + contentWidth / 2;
    }
    
    @Override
    public int getContentBottom() {
        Paint.FontMetrics metrics = getPaint().getFontMetrics();
        float contentHeight = metrics.bottom - metrics.top;
        return (int) (getHeight() / 2 + contentHeight / 2);
    }
    

    效果如下:

    jianshu.gif

    继承 IPagerIndicator


    如果你使用了 CommonNavigator,但是内置的 IPagerIndicator hold不住你的需求,那就自定义吧。

    目前内置的 IPagerIndicator 全是跟随手指滑动的,我们来打造一个简单的、不跟随的指示器。这个指示器会在被选中的 IPagerTitleView 下方显示一个小点。

    我们继承 View 并实现 IPagerIndicator,代码很短,我就全贴代码了:

    public class DotPagerIndicator extends View implements IPagerIndicator {
        private List<PositionData> mDataList;
        private float mRadius;
        private float mYOffset;
        private float mCircleCenterX;
        private int mDotColor;
        private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    
        public DotPagerIndicator(Context context) {
            super(context);
        }
    
        @Override
        public void onPageSelected(int position) {
            if (mDataList == null || mDataList.isEmpty()) {
                return;
            }
            PositionData data = mDataList.get(position);
            mCircleCenterX = data.mLeft + data.width() / 2;
            invalidate();
        }
    
        @Override
        public void onPositionDataProvide(List<PositionData> dataList) {
            mDataList = dataList;
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            mPaint.setColor(mDotColor);
            canvas.drawCircle(mCircleCenterX, getHeight() - mYOffset - mRadius, mRadius, mPaint);
        }
    
        // 一些 getter、setter 略
    }
    

    效果如下:

    dot.gif

    是不是很简单!

    使用 CommonPagerTitleView 加载自定义布局


    每当内置的 IPagerTitleView 不满足需求时,你可以选择扩展它,但更好的方式是使用 CommonPagerTitleView。CommonPagerTitleView 继承 FrameLayout 并实现了 IMeasurablePagerTitleView,它支持将自定义的布局文件设置进来,并且把 onEnter、onLeave . . . getContentLeft、getContentTop 等方法都回调出去,交给外面去实现,代码如下:

    public class CommonPagerTitleView extends FrameLayout implements IMeasurablePagerTitleView {
        private OnPagerTitleChangeListener mOnPagerTitleChangeListener;
        private ContentPositionDataProvider mContentPositionDataProvider;
    
        public CommonPagerTitleView(Context context) {
            super(context);
        }
    
        public void setContentView(int layoutId) {
            View child = LayoutInflater.from(getContext()).inflate(layoutId, null);
            setContentView(child, null);
        }
    
        @Override
        public void onSelected(int index, int totalCount) {
            if (mOnPagerTitleChangeListener != null) {
                mOnPagerTitleChangeListener.onSelected(index, totalCount);
            }
        }
    
        // 省略一部分方法
    
        public interface OnPagerTitleChangeListener {
            void onSelected(int index, int totalCount);
    
            void onDeselected(int index, int totalCount);
    
            void onLeave(int index, int totalCount, float leavePercent, boolean leftToRight);
    
            void onEnter(int index, int totalCount, float enterPercent, boolean leftToRight);
        }
    
        public interface ContentPositionDataProvider {
            int getContentLeft();
    
            int getContentTop();
    
            int getContentRight();
    
            int getContentBottom();
        }
    }
    

    上面的大图中的最后一个效果就是这么做的。我们先定义一个布局文件:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:orientation="vertical"
        android:paddingLeft="10dp"
        android:paddingRight="10dp">
    
        <ImageView
            android:id="@+id/title_img"
            android:layout_width="20dp"
            android:layout_height="20dp" />
    
        <TextView
            android:id="@+id/title_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="5dp" />
    
    </LinearLayout>
    

    再将布局文件设置到 CommonPagerTitleView 并进行初始化:

    @Override
    public IPagerTitleView getTitleView(Context context, final int index) {
        CommonPagerTitleView commonPagerTitleView = new CommonPagerTitleView(MainActivity.this);
        commonPagerTitleView.setContentView(R.layout.simple_pager_title_layout);
    
        // 初始化
        final ImageView titleImg = (ImageView) commonPagerTitleView.findViewById(R.id.title_img);
        titleImg.setImageResource(R.mipmap.ic_launcher);
        final TextView titleText = (TextView) commonPagerTitleView.findViewById(R.id.title_text);
        titleText.setText(mDataList.get(index));
    
        commonPagerTitleView.setOnPagerTitleChangeListener(new CommonPagerTitleView.OnPagerTitleChangeListener() {
    
            @Override
            public void onSelected(int index, int totalCount) {
                titleText.setTextColor(Color.RED);
            }
    
            @Override
            public void onDeselected(int index, int totalCount) {
                titleText.setTextColor(Color.BLACK);
            }
    
            @Override
            public void onLeave(int index, int totalCount, float leavePercent, boolean leftToRight) {
                titleImg.setScaleX(1.3f + (0.8f - 1.3f) * leavePercent);
                titleImg.setScaleY(1.3f + (0.8f - 1.3f) * leavePercent);
            }
    
            @Override
            public void onEnter(int index, int totalCount, float enterPercent, boolean leftToRight) {
                titleImg.setScaleX(0.8f + (1.3f - 0.8f) * enterPercent);
                titleImg.setScaleY(0.8f + (1.3f - 0.8f) * enterPercent);
            }
        });
    
        return commonPagerTitleView;
    }
    

    通过设置一个 OnPagerTitleChangeListener 来实现切换效果。我们再回顾一下效果图:

    custom_layout.gif

    结合代码,我相信你已经完全掌握 CommonPagerTitleView 啦。

    结语


    今天就是这些。写长文好累,给个 star 呗,地址:
    https://github.com/hackware1993/MagicIndicator。对 MagicIndicator 还有疑问,欢迎加QQ群:373360748

    相关文章

      网友评论

      • 我的资讯圈:你好,这个怎么居中呢?
      • zp_风:您好,只是指示器滚动,上面内容只是更新能用吗?(不需要页面滑动切换效果)
      • 27902aa78e16:您好,为什么我每次第一次进来的时候点击tab切换会很卡 连续点击几次之后就好了
        Surko:你的ViewPager里内容是不是比较多,viewPager肯定也要加载的
      • 88c2b9cb63a8:请问如何设置屏幕上标题的数量?比如说我有8个,默认显示5个,其余滑动的时候显示出来
      • DreamArea:作者你好,请教个问题,demo中最后一个scrollable tab,小三角指示器是否可以尖头朝下,就是倒过来
      • 安卓猿:需求:指示线的宽度等于标题文字的宽度, 标题文字个数可能不同。
        这种特性的支持貌似不够友好。 谢谢大神,如果能一键支持,那就太爽了:smiley: :smiley:
      • 2642e925bad0:怎么设置指示器标题位置在布局中均分呀,现在放上去都挤在一块
      • 谁把我的昵称都占用了:用Fragment容器的时候不能滑动切换fragment页面,能解决吗
      • 荒漠狂沙走万里:你好,这个好像在7.0是有问题。magicIndicator.onPageSelected(index);没有作用。viewpage没有滑动指定的index。能帮忙看一下吗?
      • 简祖明:设计模式用的相当棒
      • 57855e86d40d:有没有这么一个情景,每个indicator都是上面图标+下面文字组成!向下滑动recyclerview的时候,indicator向上移动,图标消失,文字悬浮在顶部!这种怎么实现?楼主有思路吗😊
      • mcp1993:楼主我用这个控件滑动时指示线会卡顿,请问是怎么回事,有什么思路吗
      • coexist:使用的时候不结合Fragment和ViewPager使用,只是普通的点击tab来改变数据时,
        该如何实现,类似于setCurrent()的功能
      • 6207e5d1fbaa:大神,你好,你的这种完全解耦的架构很精妙,佩服。
        我看到NavigatorHelper这个类的onPageScrolled()方法是一个很关键的方法,但是一点注释也没有,我看了半天,跟不上你的思维:joy:,可否详细讲解一个您的思路呢?
        6207e5d1fbaa:为什么在onPageScrolled()方法中不只处理onEnter()和onLeave()两种情况呢?
      • 就这样很好:怎么设置文字之间的距离啊?是用什么方法?能给我说一下吗?
      • 我脑中旳橡皮擦:大神 这个怎么滑动切换fragment 怎么和fragment关联起来
      • 1511a4f14934:大神辛苦了,感谢分享!顺便问一下,如果只有两个title 怎么设置平分
        我家小梅最可爱:@JoonyLee 2个title 能设置宽度吗,我想2个title在中间,2个title的宽度占屏幕的5分之一
        JoonyLee: commonNavigator.setAdjustMode(true);添加这个就平分了
        JoonyLee:找到了吗?哥们
      • jszsl:大神辛苦了,感谢分享!顺便问一下,如果我想在指示器的文本上加一个获取焦点时的效果(例如半透明发光背景),该怎么加,请指导一下,本人菜鸟一个,多谢多谢!
      • 吉凶以情迁:最大的毛病就是只能写死高度,不能wrap_content
        吉凶以情迁:扩展性不好,对于只会写布局 样式的小白来说 ,一个实心白色 边框线指示器都不知道该如何改造实现
      • 学子要远行:作者你好,我用eclipse开发的(公司老项目所以用不了androidstudio),我想请教eclipse环境下应该怎样使用这个库呢?帮帮忙:pray: 拜托
      • developerYk:作者 你好 为什么我设置之后 我的字没有居中显示啊?我用的是你第7个Indicator
      • ca0cee294b9b:作者,您好,为什么将MagicIndicator的父控件改成RelativeLayout,将指示器置底,怎么就都没动静了呢?
      • 45299b777c4c:作者你好,这个能是指示器与viewpage关联,然后viewpage中加fragment吗
        我家小梅最可爱:我现在也是需要你这个效果,请问你是怎么做的?
        hackware:@陌生也是美 不明白你的意思
        45299b777c4c:@陌生也是美 而不是指示器直接加fragment,我需要滑动切换fragment的效果
      • 75522fb1d19c:都把demo看了几遍了,没找到相关方法.纠结啊
        小赛斯:我也遇到同样的问题,我以前是用LinearLayout加HorizontalScrollView 实现的,没这么麻烦,你可以试试,毕竟博主这个适用于有viewPager 切换的
        hackware: @lifetin 你确定看了FragmentContainerExampleActivity?😂
      • 75522fb1d19c:哎.搞了一上午,方法都找了,都不管用.希望作者能加个设置当前指示器的方法吧
        setCurent或是什么的.想设置哪个就设置哪个.
        75522fb1d19c:@hackware 那这个是Farmange的方法呀.我是只要一个指导器.不能直接通过MagicIndicator或是CommonNavigator下的方法设置吗?
        hackware: @lifetin demo都写的那么细了,干嘛不看
        hackware: @lifetin 有啊,handlePageSelected啊
      • 75522fb1d19c:我没有用viewPager,点击了指示器,那指示器下面的线条不跟着滚动到当前点击的这个,要用哪个方法来设置呢?
        我试着用 magicIndicator.onPageSelected(index);
        但是只会变动一次,之后那指示器不滚动了
      • 4640f78109a4:作者你好,为什么我把viewpagerhelper里的addonpagechangelistener换成setonpagechangelistener后好多效果都无效了,难道不能改为setonpage吗?
        4640f78109a4:@hackware 有什么办法能在ec里使用的时候把add改为set呢?
        4640f78109a4:@hackware 因为我用的ec。。。。。。是哪里出了问题,为什么会出现这个问题啊
        hackware:@fmlong 你如果在自己的项目里用,是没问题的,但你如果在magicindicator的demo里改,肯定有问题啊,只有最后那个indicator能响应了,你改这个干嘛
      • 寒平洛一:作者请看,http://img.hoop8.com/1608B/Ht519kGc.png,这个平分居中的,并没有平分空间,看左右边距就知道,而且你把文字改成中文两个字就很明显~强迫症受不了。。。望改善
        hackware:@寒平洛一 你删掉getTitleWeight即可
        寒平洛一:@hackware 哦哦,感谢您的解答,我该如何解决比较好
        hackware:@寒平洛一 亲,这是由于在CommonAdapter里重载了weight属性。
      • qiaoStr:不错 谢谢大神
      • coolzpw:辛苦了!写的很好~!对这个控件大体的实现思路熟悉了
        coolzpw:@hackware 嘿嘿!加油!
        hackware:@coolzpw 谢谢,希望它能帮到你

      本文标题:MagicIndicator系列之三 —— MagicInd

      本文链接:https://www.haomeiwen.com/subject/jwwwjttx.html