深度剖析之 PagerSlidingTabStrip

Android 智能问答机器人的实现 开发是面向对象。我们找工作应该更多是面向面试。哪怕进大厂真的只是去宁螺丝,但你要进去得先学会面试的时候造飞机不是么?作者13年java转Android开发,在小厂待过,也去过华为,OPPO等,去年四月份进了阿里一直到现在。等大厂待过也面试过很多人。深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。这里附上上述的技术体系图相关的几十套腾讯、头条、阿里、美团等公司的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含。 阅读详情

剖析项目名称: Android PagerSlidingTabStrip (default Material Design)
剖析原项目地址:https://codeload.github.com/jpardogo/PagerSlidingTabStrip/zip/master
剖析理由:只知其然而不知其所以然,如此不好。想要快速的进阶,不走寻常路,剖析开源项目,深入理解扩展知识,仅仅这样还不够,还需要如此:左手爱哥的设计模式,右手重构改善既有设计,如此漫长打坐,回过头再看来时的路,书已成山,相信翔哥说的,量变引起质变。


话不多说,献上Gif(没有Gif就是耍流氓了O(∩_∩)O~)

Android studio 导入项目里面一键搞定(AS的魅力真的很大,我都把持不住啦)

compile 'com.jpardogo.materialtabstrip:library:1.1.0'

作为一个依赖导入到自己项目,xml布局调用实例:

 <com.astuetz.PagerSlidingTabStrip
        android:id="@+id/tabs"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="?attr/colorPrimary" />

PagerSlidingTabStrip配合ViewPager一起使用,当ViewPager的onPagerChangeListener回调时,PagerSlidingTabStrip也一起随之变动,具体做法都已封装到了PagerSlidingTabStrip.setViewPager()方法里,使用时调用实例如下:

// Initialize the ViewPager and set an adapter
  ViewPager pager = (ViewPager) findViewById(R.id.pager);
  pager.setAdapter(new TestAdapter(getSupportFragmentManager()));

  // Bind the tabs to the ViewPager
  PagerSlidingTabStrip tabs = (PagerSlidingTabStrip) findViewById(R.id.tabs);
  tabs.setViewPager(pager);

如果你需要监听PagerSlidingTabStrip的check状态变化,只需要如此:

 // continued from above
   tabs.setOnPageChangeListener(mPageChangeListener);

下面是一些关于自定义属性的简短说明,如果你需要定制化的UI可以通过引用这些属性帮助你实现你想要的效果。


  • android:textColorPrimary 文字颜色
  • pstsIndicatorColor 滑动指示器颜色
  • pstsIndicatorHeight 滑动指示器高度
  • pstsUnderlineColor 视图的底部的全宽线的颜色
  • pstsUnderlineHeight 视图的底部的全宽线的高度
  • pstsDividerColor 选项卡之间的分隔线的颜色
  • pstsDividerWidth 选项卡之间的分隔线的宽度
  • pstsDividerPadding 选项卡之间的分隔线的Pading填充
  • pstsShouldExpand 如果设置为true,每个选项卡都是相同的weight,即LinearLayout的权重一样,默认为false
  • pstsScrollOffset 滑动Tab的偏移量
  • pstsPaddingMiddle 如果true,视图的标签会以居中显示的方式呈现。
  • pstsTabPaddingLeftRight 每个标签左右填充宽度
  • pstsTabBackground 每个标签的背景,应该是一个selector,checked=”true/false”对应不同的背景
  • pstsTabTextSize Tab标签的文字大小
  • pstsTabTextColor Tab标签的文字颜色
  • pstsTabTextStyle
  • pstsTabTextAllCaps 如果为true,所有标签都是大写字母,默认为true
  • pstsTabTextAlpha 设置文本alpha透明度不选中的选项卡。0 . . 255之间,150是默认值。
  • pstsTabTextFontFamily Tab标签文字的字体
  • setTypeface(Typeface typeface, int style) 设置字体,把字体放入assets里通过该方法调用

先看看github上作者提供的compile:

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile "com.android.support:appcompat-v7:22.2.0"
    compile 'com.android.support:cardview-v7:22.2.0'
    compile 'com.jakewharton:butterknife:6.0.0'
    compile 'com.readystatesoftware.systembartint:systembartint:1.0.3'
    compile 'com.nineoldandroids:library:2.4.0'
    compile 'com.jpardogo.materialtabstrip:library:1.1.0'
}

用了V7包,状态栏和标题栏的颜色修改需要,cardView稍后细说,butterknife第三方注解框架,我比较喜欢用xutils,用法都差不多,这里就不细说,不解就看官方文档说明,systembartint这个是一个关于沉浸式状态栏的兼容包,向下兼容到4.4,nineoldandroids动画库。这里简单的提一下,沉浸式状态栏,在不同的手机和系统上可能存在兼容性问题,这里以5.1系统的手机为实例,做个简单的demo

<style name="AppBaseTheme" parent="Theme.AppCompat.Light.NoActionBar">
          <!-- window 背景色 -->
        <item name="android:windowBackground">@color/background_window</item>
        <!-- ...and here we setting appcompat’s color theming attrs -->
         <!-- 标题栏的颜色 -->
        <item name="colorPrimary">@color/colorPrimary</item>
         <!-- 状态栏颜色--> 
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
         <!-- 控件颜色 -->  
        <item name="colorAccent">@color/colorAccent</item>
         <!-- 控件文字颜色 -->  
        <item name="android:textColorPrimary">@android:color/white</item>
    </style>

    <style name="AppTheme" parent="AppBaseTheme" />

Value-v19里面设置透明属性并在activity_main里面设置一个属性fitsSystemWindows(给状态栏预留空间,如果开发中遇到兼容问题建议这里通过style引用该属性):

 <style name="AppTheme" parent="AppBaseTheme">
        <item name="android:windowTranslucentStatus">true</item>
    </style>

  android:fitsSystemWindows="true"

Activity测试类调用systembartint设置沉浸式状态栏相关属性

public class MainActivity extends ActionBarActivity {

    private SystemBarTintManager mTintManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // create our manager instance after the content view is set
        mTintManager = new SystemBarTintManager(this);
        // enable status bar tint
        mTintManager.setStatusBarTintEnabled(true);

        //changeColor(getResources().getColor(R.color.green));
        mTintManager.setTintColor(getResources().getColor(R.color.colorPrimary));
    }
}

demo太简单了,就不上传资源了,作者github上demo底部动态控制沉浸式状态栏,通过onClick获取颜色值,调用changeColor重新赋值,在开发中结合抽屉控件可以达到意想不到的效果。不过这些都不是本文重点,还是回到主题PagerSlidingTabStrip.java

public class PagerSlidingTabStrip extends HorizontalScrollView {

    //透明度,如果没有传入自定义属性文字颜色透明度,那么默认值为150
    public static final int DEF_VALUE_TAB_TEXT_ALPHA = 150;
    private int mTabBackgroundResId = R.drawable.psts_background_tab;

    public PagerSlidingTabStrip(Context context) {
        this(context, null);
    }

    public PagerSlidingTabStrip(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public PagerSlidingTabStrip(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        //当你想让一个高度值不足scrollview的子控件fillparent的时候,单独的定义android:layout_height="fill_parent"是不起作用的,必须加上fillviewport属性,当子控件的高度值大于scrollview的高度时,这个标签就没有任何意义了
        setFillViewport(true);
        //控制是否执行OnDraw方法绘制
        setWillNotDraw(false);
        //添加ScrollView的唯一子布局LinearLayout
        mTabsContainer = new LinearLayout(context);
        mTabsContainer.setOrientation(LinearLayout.HORIZONTAL);
        addView(mTabsContainer);

        //初始化画笔
        mRectPaint = new Paint();
        mRectPaint.setAntiAlias(true);
        mRectPaint.setStyle(Style.FILL);

        //获取屏幕相关属性
        DisplayMetrics dm = getResources().getDisplayMetrics();
        //解析自定义属性值
        mScrollOffset = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mScrollOffset, dm);
        //............此处略..............

        //初始化分割线画笔
        mDividerPaint = new Paint();
        mDividerPaint.setAntiAlias(true);
        mDividerPaint.setStrokeWidth(mDividerWidth);

        // get system attrs for container 解析属性
        TypedArray a = context.obtainStyledAttributes(attrs, ANDROID_ATTRS);
        int textPrimaryColor = a.getColor(TEXT_COLOR_PRIMARY, getResources().getColor(android.R.color.black));
        mUnderlineColor = textPrimaryColor;
        mDividerColor = textPrimaryColor;
        mIndicatorColor = textPrimaryColor;
        int padding = a.getDimensionPixelSize(PADDING_INDEX, 0);
        mPaddingLeft = padding > 0 ? padding : a.getDimensionPixelSize(PADDING_LEFT_INDEX, 0);
        mPaddingRight = padding > 0 ? padding : a.getDimensionPixelSize(PADDING_RIGHT_INDEX, 0);
        a.recycle();

        String tabTextTypefaceName = "sans-serif";
        // Use Roboto Medium as the default typeface from API 21 onwards
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            //走版本分支设置字体,在android 21后提供了这个字体
            tabTextTypefaceName = "sans-serif-medium";
            mTabTextTypefaceStyle = Typeface.NORMAL;
        }

        // get custom attrs for tabs and container 解析自定义属性值
        a = context.obtainStyledAttributes(attrs, R.styleable.PagerSlidingTabStrip);
        mIndicatorColor = a.getColor(R.styleable.PagerSlidingTabStrip_pstsIndicatorColor, mIndicatorColor);
       //............此处略..............
        //释放
        a.recycle();

        //Tab text color selector 创建tab文字的selector
        if (mTabTextColor == null) {
            mTabTextColor = createColorStateList(
                    textPrimaryColor,
                    textPrimaryColor,
                    Color.argb(tabTextAlpha,
                            Color.red(textPrimaryColor),
                            Color.green(textPrimaryColor),
                            Color.blue(textPrimaryColor)));
        }

        //Tab text typeface and style 
        if (fontFamily != null) {
            tabTextTypefaceName = fontFamily;
        }
        mTabTextTypeface = Typeface.create(tabTextTypefaceName, mTabTextTypefaceStyle);

        //Bottom padding for the tabs container parent view to show indicator and underline 底部填充的容器父视图选项卡显示指示器和下划线
        setTabsContainerParentViewPaddings();

        //Configure tab's container LayoutParams for either equal divided space or just wrap tabs  配置选项卡的容器LayoutParams,设置权重
        mTabLayoutParams = isExpandTabs ?
                new LinearLayout.LayoutParams(0, LayoutParams.MATCH_PARENT, 1.0f) :
                new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
    }
}

onAttachedToWindow方法给传入的ViewPager的Adapter注册观察者,onDetachedFromWindow则注销观察者,当Adapter数据发生变化时,通过观察者调用onChanged方法调用该类里定义的刷新方法,当数据集失效时,会调用DataSetObserver的onINvalidated()方法。

 @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        if (mPager != null) {
            if (!mAdapterObserver.isAttached()) {
                mPager.getAdapter().registerDataSetObserver(mAdapterObserver);
                mAdapterObserver.setAttached(true);
            }
        }
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        if (mPager != null) {
            if (mAdapterObserver.isAttached()) {
                mPager.getAdapter().unregisterDataSetObserver(mAdapterObserver);
                mAdapterObserver.setAttached(false);
            }
        }
    }

View视图的测量,onLayout重新计算width,并添加OnGlobalLayoutListener

 @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        if (isPaddingMiddle || mPaddingLeft > 0 || mPaddingRight > 0) {
             //重新计算宽度
            int width;
            if (isPaddingMiddle) {
                width = getWidth();
            } else {
                // Account for manually set padding for offsetting tab start and end positions.
                width = getWidth() - mPaddingLeft - mPaddingRight;
            }

            //Make sure tabContainer is bigger than the HorizontalScrollView to be able to scroll    设置mTabsContainer的最小宽度>父布局宽度,确保能横屏滑动
            mTabsContainer.setMinimumWidth(width);
            //Clipping padding to false to see the tabs while we pass them swiping
            setClipToPadding(false);
        }

        if (mTabsContainer.getChildCount() > 0) {
          //当在一个视图树中全局布局发生改变或者视图树中的某个视图的可视状态发生改变时,所要调用的回调函数的接口类
            mTabsContainer
                    .getChildAt(0)
                    .getViewTreeObserver()
                    .addOnGlobalLayoutListener(firstTabGlobalLayoutListener);
        }

        super.onLayout(changed, l, t, r, b);
    }

再来看看大功臣onDraw方法

  @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (isInEditMode() || mTabCount == 0) {
            return;
        }

        final int height = getHeight();
        // draw divider
        if (mDividerWidth > 0) {
            mDividerPaint.setStrokeWidth(mDividerWidth);
            mDividerPaint.setColor(mDividerColor);
            for (int i = 0; i < mTabCount - 1; i++) {
                //绘制tab间每条分割线
                View tab = mTabsContainer.getChildAt(i);
                canvas.drawLine(tab.getRight(), mDividerPadding, tab.getRight(), height - mDividerPadding, mDividerPaint);
            }
        }

        // draw underline
        if (mUnderlineHeight > 0) {
            //视图的底部的全宽线的颜色
            mRectPaint.setColor(mUnderlineColor);
            canvas.drawRect(mPaddingLeft, height - mUnderlineHeight, mTabsContainer.getWidth() + mPaddingRight, height, mRectPaint);
        }

        // draw indicator line
        if (mIndicatorHeight > 0) {
            //绘制滑动条
            mRectPaint.setColor(mIndicatorColor);
            //Pair用于存储一组数据的,该类位于v4下util包,这里调用getIndicatorCoordinates方法通过当前Tab和NextTab计算出距离存放入Pair,个人感觉比数组集合map那些好用多了

            Pair<Float, Float> lines = getIndicatorCoordinates();
            canvas.drawRect(lines.first + mPaddingLeft, height - mIndicatorHeight, lines.second + mPaddingLeft, height, mRectPaint);
        }
    }

对外公开的方法setViewPager(),该方法的调用必须在ViewPager设置Adapter之后不然会抛出异常。

 public void setViewPager(ViewPager pager) {
        this.mPager = pager;
        if (pager.getAdapter() == null) {
            throw new IllegalStateException("ViewPager does not have adapter instance.");
        }

        isCustomTabs = pager.getAdapter() instanceof CustomTabProvider;
        pager.setOnPageChangeListener(mPageListener);
        pager.getAdapter().registerDataSetObserver(mAdapterObserver);
        mAdapterObserver.setAttached(true);
        notifyDataSetChanged();
    }

这里的PagerChangerListener代码如下:

 private class PageListener implements OnPageChangeListener {

        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
            //重新赋值当前选中位置和偏移量
            mCurrentPosition = position;
            mCurrentPositionOffset = positionOffset;
            //根据positionOffset计算出mTabsContainer实际的偏移值,再通过scrollTo方法实现滑动到指定位置,并调用重绘指示器位置
            int offset = mTabCount > 0 ? (int) (positionOffset * mTabsContainer.getChildAt(position).getWidth()) : 0;
            scrollToChild(position, offset);
            invalidate();
            if (mDelegatePageListener != null) {
                mDelegatePageListener.onPageScrolled(position, positionOffset, positionOffsetPixels);
            }
        }

        @Override
        public void onPageScrollStateChanged(int state) {
            if (state == ViewPager.SCROLL_STATE_IDLE) {
                scrollToChild(mPager.getCurrentItem(), 0);
            }
            //Full tabTextAlpha for current item
            View currentTab = mTabsContainer.getChildAt(mPager.getCurrentItem());
           //改变选中tab的文字颜色 不透明
            select(currentTab);
            //Half transparent for prev item

            if (mPager.getCurrentItem() - 1 >= 0) {
                View prevTab = mTabsContainer.getChildAt(mPager.getCurrentItem() - 1);
                //取消上一个选中Tab状态 让该Tab处于半透明状态
                 unSelect(prevTab);
            }

            //Half transparent for next item
            if (mPager.getCurrentItem() + 1 <= mPager.getAdapter().getCount() - 1) {
                View nextTab = mTabsContainer.getChildAt(mPager.getCurrentItem() + 1);
                unSelect(nextTab);
            }

            if (mDelegatePageListener != null) {
                mDelegatePageListener.onPageScrollStateChanged(state);
            }
        }

        @Override
        public void onPageSelected(int position) {
            updateSelection(position);
            if (mDelegatePageListener != null) {
                mDelegatePageListener.onPageSelected(position);
            }
        }

    }

自定义方法notifyDataSetChanged做了三件事,先移除现有的childView,再遍历addView,设置每个Tab的属性(TextView)

  public void notifyDataSetChanged() {
        mTabsContainer.removeAllViews();
        mTabCount = mPager.getAdapter().getCount();
        View tabView;
        for (int i = 0; i < mTabCount; i++) {
            if (isCustomTabs) {
                tabView = ((CustomTabProvider) mPager.getAdapter()).getCustomTabView(this, i);
            } else {
                tabView = LayoutInflater.from(getContext()).inflate(R.layout.psts_tab, this, false);
            }

            CharSequence title = mPager.getAdapter().getPageTitle(i);
            addTab(i, title, tabView);
        }

        updateTabStyles();
    }

在调用addTab方法传入了tab的位置position,当点击了当前Tab即当前TextView响应了onClick事件,选中了该Tab,就会掉当前position

   private void addTab(final int position, CharSequence title, View tabView) {
        TextView textView = (TextView) tabView.findViewById(R.id.psts_tab_title);
        if (textView != null) {
            if (title != null) textView.setText(title);
        }

        tabView.setFocusable(true);
        tabView.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                //如果点击该Tab之前,该Tab是未选中状态,要修改相应的ui
                if (mPager.getCurrentItem() != position) {
                    View tab = mTabsContainer.getChildAt(mPager.getCurrentItem());
                    unSelect(tab);
                    mPager.setCurrentItem(position);
                } else if (mTabReselectedListener != null) {
                    //如果是重复选择就调用TabReselectedListener接口的回调函数
                    mTabReselectedListener.onTabReselected(position);
                }
            }
        });

        mTabsContainer.addView(tabView, position, mTabLayoutParams);
    }

看完这个开源项目,大致理顺思路:自定义横向ScrollView,构造参数设置ScrollView属性,解析自定义属性,onLayout测量视图绑定OnGlobalLayoutListener监听,在其回调函数里调用notifyDataSetChanged,onDraw方法绘制分割线指示器等,在我们调用setViewPager是通过notifyDataSetChanged添加子视图,并绑定监听事件。


总结:这个开源项目自定义属性比较多,定制扩展方便比较MaterialTabs开源项目,虽然原理都差不多。通过这个项目,加深了我对ViewTreeObserver、OnGlobalLayoutListener等相关类的理解createColorStateList方法可以写一个工具类封装类似的selector。

参考资料:
http://www.aiuxian.com/article/p-638915.html
http://blog.youkuaiyun.com/caesardadi/article/details/8307449

Material_Tabs:带选项卡的材料工具栏 Material_Tabs 带选项卡的材料工具栏 用法 有关此项目的工作实现,请参阅app/文件夹。 将以下依赖项包含到您的 gradle 文件中。 compile ' com.android.support:appcompat-v7:22.0.0 ' compile ' com.android.support:support-v4:22.0.0 ' compile ' com.android.support:cardview-v7:21.0.3 ' compile ' com.jpardogo.materialtabstrip:library:1.0.9 ' compile ' com.jakewharton:butterknife:6.1.0 ' 在您的布局中包含 PagerSlidingTabStr 立即下载

相关推荐

PagerSlidingTabStrip制作Android带标签的多界面滑动切换

主要介绍了使用PagerSlidingTabStrip制作Android带标签的多界面滑动切换效果的方法,PagerSlidingTabStrip是GitHub上的一个开源项目,调用这个库可以少写不少代码XD 需要的朋友可以参考下

探索 PagerSlidingTabStrip:打造优雅的Android标签导航

探索 PagerSlidingTabStrip:打造优雅的Android标签导航 PagerSlidingTabStrip是一个开源的Android库,由开发者ta893115871创建,它提供了一种简单但强大的方式来为你的应用添加滑动标签页。这款库的设计灵感来自于Google的Material Design规范,旨在帮助开发者轻松实现美观且交互流畅的界面。 项目简介 PagerSlidingTa...

gitblog_00036的博客 915

如何根据芯片手册时序图编写驱动程序

如何根据芯片手册时序图编写驱动程序 对于电子开发者来说,刚刚拿到一个芯片,常用的芯片可以参考网上的例程来做深入了解,对于一个不常用的芯片来说,Datasheet几乎是使用芯片的唯一的资料,所以根据Datasheet时序图写出对应的驱动程序就尤为重要。 本文根据一个简单的例子来阐述根据时序图来编写对应的程序过程。旨在讲解对于初学者应该怎么利用芯片的时序图编写符合要求的底层驱动程序(老鸟请跳过)。 下载芯片的Datasheet,(个人常用http://www.21icsearch.com/)如..

weixin_36447711的博客 1万+

PagerSlidingTabStrip的分析和使用

PagerSlidingTabStrip是GitHub上一个开源项目(地址:https://github.com/astuetz/PagerSlidingTabStrip)用于获得同样的Tab翻页效果。与官方ActionBar的Tab不同的是,Tab不属于ActionBar,而是通过TextView自定义了Tab,并通过与ViewPager联动,实现点击Tab和侧滑均能翻页的效果。

BrilliantEagle的专栏 2829

Android perfetto 简介

android linux 性能优化 原理及操作

求变,从思想开始 3474

Transformer时序预测避坑指南:TFT在风电场的5个实战经验

本文分享了Temporal Fusion Transformer在风电场功率预测中的五个实战经验,涵盖数据预处理、模型调优、显存优化、注意力机制解读及在线部署。针对风电数据噪声大、概念漂移等挑战,提供了从构建数据质量标签到高效超参调优的具体方案,并强调利用Transformer架构的可解释性进行业务洞察,助力实现稳健的工业级时序预测。

bert9linguist的博客 460

常用的第三方库

1.UI库PagerSlidingTabStrip————ViewPager的标题导航方便实用的viewPager标题的分页导航条引入依赖地址compile 'com.jpardogo.materialtabstrip:library:1.0.6'PagerSlidingTabStrip——GitHub 在xml文件中增加的属性值 pstsIndicatorColor 可以滑动的指示器的颜色

蔷薇_wendy的博客 668

YOLO11实战:手把手教你优化钢材表面缺陷识别模型(基于NEU-DET数据集)

本文详细介绍了如何使用YOLO11优化钢材表面缺陷识别模型,基于NEU-DET数据集进行实战训练。从数据增强、模型架构优化到训练过程控制,全面解析提升钢材缺陷检测性能的关键技术,特别针对裂纹、划痕等典型缺陷提出针对性解决方案。

weixin_29081163的博客 377

PagerSlidingTabStrip

代替了  tablayout + viewpager     在PagerSlidingTabStrip的基础上加了  选择改变字体颜色  和  可设置  选中字体颜色、大小      和  未选中字体的颜色、大小  具体使用步骤: 第一步: 在values下 建 attrs.xml  属性文件 xml version="1.0" encoding="utf-8"?>

XiFangzheng的博客 2495

Python控制tek示波器(1)

如何使用Python来控制tek示波器

m0_47441496的博客 3379

基于Keil软件实现对射式红外传感器计次 (江协科技HAL库)

用HAL库复现江协科技,让嵌入式学习之路更顺畅。

2401_82728381的博客 798

PagerSlidingTabStrip使用 和扩展4个属性

PagerSlidingTabStrip viewpaper fragment

mfc2003的专栏 1万+

生成式AI;语义通信技术;生成式AI辅助的云边协同算法及其可解释性

生成式AI 语义通信技术 生成式AI辅助的云边协同算法及其可解释性 一、端到端设计的物理层内生智能 二、生成式语义通信 三、生成式数字孪生网络 四、生成式AI辅助的云边协同算法及其可解释性 五、未来可能的研究方向

ZhangJiqun&191cm&85kg 425

Segment 3642BH通过skiiiD实现智能控制:硬件接口与自定义驱动开发实战

物联网(IoT)与智能家居的核心在于实现设备的互联互通与自动化控制。其基本原理是通过统一的控制平台,将具备不同通信协议的硬件设备接入网络,并编写相应的驱动逻辑进行指令交互。这项技术的价值在于能够打破设备孤岛,实现跨品牌、跨协议的集中管理与智能联动,从而提升能效、优化用户体验并构建复杂的自动化场景。在工程实践中,这常常涉及对RS-232/RS-485等串行通信接口的协议解析,以及利用如skiiiD这类平台进行自定义驱动开发。本文将以一个典型项目为例,详细阐述如何将一台使用传统接口的专业设备Segment 36

weixin_30335353的博客 385

在 TASKPROCESSING 上为 ABAP OData 服务添加多个系统别名:从原理到落地的完整实践

本文面向SAP Gateway与ABAP开发者,详细讲解如何在TASKPROCESSING OData服务上添加系统别名。首先介绍了系统别名的概念与设计初衷,阐述了添加别名的业务场景需求,包括多系统接入、用户分流和灰度发布等。随后提供了标准配置步骤,从SPRO路径到具体操作说明,并分享了三个实际案例说明如何实现跨区域统一待办、按用户角色分流和灰度发布。最后给出了验证方法和常见问题解决方案,帮助开发者掌握这项基础但关键的配置技能,实现服务路由的可控管理。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 136

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

<Android开源库> PagerSlidingTabStrip从头到脚

简介 PagerSlidingTabStrip,是我个人经常使用到的一个和ViewPager配合的页面指示器,可以满足开发过程中常用的需求,如类似于今日头条的首页新闻内容导航栏等等,之前自己开发的JuheNews和正在开发的GankIOClient均有使用到它,所以想对其进行一个全面的介绍。 PagerSlidingTabStrip源码地址: https:...

weixin_34224941的博客 280

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

2024年最新Android 标签栏pagerslidingtabstrip用法实例(含Demo)(1),kotlin面试题

在此为大家准备了四节优质的Android高级进阶视频:架构师项目实战——全球首批Android开发者对Android架构的见解在此为大家准备了四节优质的Android高级进阶视频:架构师项目实战——全球首批Android开发者对Android架构的见解。

2401_84538063的博客 985

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

PagerSlidingTabStrip介绍及使用,让ViewPager更绚丽

以前一直想着,ViewPager中间的那个横线怎么跟着屏幕的滑动而滑动,如下图所示: 我们可以看到中间的那个红线在跟着屏幕滑动而滑动 现在github上已经有了这个开源项目,所以我们可以直接拿来用,很方便很实用。文章末尾我将放上资源,可以直接下载。

HarryWeasley的专栏 2万+

Android 标签栏pagerslidingtabstrip用法实例(含Demo)

其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。以上分享【我的阿里P7移动开发架构师学习笔记】七大模块整套学习资料均免费分享,需要的小伙伴,我已经上传到石墨文档了,大家自取就可以了。白嫖可以,别忘了给我点个关注哈。当然我也为你们整理好了百度、阿里、腾讯、字节跳动等等互联网超级大厂的历年面试真题集锦。

m0_61331407的博客 729

PagerSlidingTabStrip源码分析及扩展

1. 简介PagerSlidingTabStrip是GITHUB上的开源库,继承自HorizontalScrollView,主要和viewpager一起使用,起到标识标题栏的作用.2. 源码分析1 变量 public OnPageChangeListener delegatePageListener; 是代理的监听器,用于外部回调,因为PagerSlidingTabStrip占据了viewpager

雨水的尾巴 1039

PagerSlidingTabStrip自定义设置

今天遇到这样的需求,PagerSlidingTabStrip要求减小滑动条的高度、不能有点击的效果、不能超出屏幕。 前两个需求,根据网上给出的设置,基本可以解决。记录如下:1.修改滑动条的高度pstsIndicatorColor 滑动条的颜色 pstsIndicatorHeight 滑动条的高度 在使用PagerSlidingTabStrip的xml文件中,先添加自定义的命名规则加上这

coosea128的博客 2364

安卓日记——PagerSlidingTabStrip使用介绍

最近在弄一些常用的好看的控件,当然少不了ViewPager,然后ViewPager通常要和标签组合使用,在很就之前我是用RadioGroup来当作标签的,然后发现了ViewPagerIndicator,但用起来很麻烦,但效果很多样化。但最终我选择了使用PagerSlidingTabStrip 原因有以下两点1. 加载简单 2. 使用简单加载只需在Moudle的Build.gradle里添加co

饥渴计科极客杰铿的博客 1531

开源项目 PagerSlidingTabStrip 常见问题解决方案

开源项目 PagerSlidingTabStrip 常见问题解决方案 1. 项目基础介绍和主要编程语言 项目介绍:PagerSlidingTabStrip 是一款适用于 Android 平台的指示器 TabLayout 组件,它模仿了 Boss 直聘的 UI 设计,并支持红点未读提示功能。这个项目为开发者提供了一个灵活的选项来创建具有滑动标签页的界面。 主要编程语言:Java 2. 新手在使用这个...

gitblog_01112的博客 645

开源项目: FlycoTabLayout

开源项目效果调用实例必练基本功Android studio 项目导入依赖compile路径dependencies{ compile 'com.android.support:support-v4:23.1.1' compile 'com.flyco.tablayout:FlycoTabLayout_Lib:2.0.2@aar' }FlycoTabLayout是一个Android T

AnalyzeSystem的博客 8万+
上一篇: 深度剖析之 Material Design Android Library
下一篇: 深度剖析之 CountdownView
AnalyzeSystem
博客等级 码龄11年 204粉丝 114原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值