【问题标题】:Custom icon on Tabs选项卡上的自定义图标
【发布时间】:2015-06-25 11:57:27
【问题描述】:

我正在使用带有 ViewPager 的 PagerSlidingTabStrip

有没有一种方法可以根据某些操作动态更改选项卡图标。就像收到通知一样,我想更改通知选项卡上的图标以显示有多少通知未读。

或任何其他无需太多调整即可支持该功能的库。

【问题讨论】:

标签: android android-viewpager


【解决方案1】:

您可以通过实现PagerSlidingTabStrip.CustomTabProvider 接口来实现。我为您的案例制作了example project,让我们一步一步探索。

首先,为我们的标签页创建一个布局,例如 tab_layout。它将包含 2 个TextView 的标题和徽章。就我而言,它看起来像:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">

<TextView
    android:id="@+id/tab_title"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerInParent="true"
    android:gravity="center"
    android:textColor="@android:color/white"
    android:textStyle="bold"
    android:textSize="16sp"
    android:singleLine="true" />

<TextView
    android:id="@+id/badge"
    android:layout_width="16dp"
    android:layout_height="16dp"
    android:layout_toRightOf="@+id/tab_title"
    android:textSize="12sp"
    android:gravity="center"
    android:layout_marginLeft="8dp"
    android:layout_centerVertical="true"
    android:textColor="@android:color/white"
    android:background="@drawable/badge_background" />

</RelativeLayout>

其次,为标签创建一个简单的模型,其中包含标签标题和通知数量。我称它为ViewPagerTab

public class ViewPagerTab {
    public String title;
    public int notifications;

    public ViewPagerTab(String title, int notifications) {
        this.title = title;
        this.notifications = notifications;
    }
}

第三,在你的FragmentPagerAdapter上实现PagerSlidingTabStrip.CustomTabProvider接口。在这里,我们将扩展选项卡布局并初始化选项卡视图,还将为位置定义片段:

public class MainAdapter extends FragmentPagerAdapter
        implements PagerSlidingTabStrip.CustomTabProvider {

    ArrayList<ViewPagerTab> tabs;

    public MainAdapter(FragmentManager fm, ArrayList<ViewPagerTab> tabs) {
        super(fm);
        this.tabs = tabs;
    }

    @Override
    public View getCustomTabView(ViewGroup viewGroup, int i) {
        RelativeLayout tabLayout = (RelativeLayout)
                LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.tab_layout, null);

        TextView tabTitle = (TextView) tabLayout.findViewById(R.id.tab_title);
        TextView badge = (TextView) tabLayout.findViewById(R.id.badge);

        ViewPagerTab tab = tabs.get(i);

        tabTitle.setText(tab.title.toUpperCase());
        if (tab.notifications > 0) {
            badge.setVisibility(View.VISIBLE);
            badge.setText(String.valueOf(tab.notifications));
        } else {
            badge.setVisibility(View.GONE);
        }

        return tabLayout;
    }

    @Override
    public void tabSelected(View view) {
        //if you don't want badges disappear when you select tab comment next lines
        RelativeLayout tabLayout = (RelativeLayout) view;
        TextView badge = (TextView) tabLayout.findViewById(R.id.badge);
        badge.setVisibility(View.GONE);
    }

    @Override
    public void tabUnselected(View view) {

    }

    @Override
    public Fragment getItem(int position) {
        switch (position) {
            case 0:
                return new OneFragment();
            case 1:
                return new TwoFragment();
            case 2:
                return new ThreeFragment();
        }
        return new OneFragment();
    }

    @Override
    public int getCount() {
        return tabs.size();
    }
}

第四,MainActivityonCreate方法中初始化tabs和pager:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    tabs = (PagerSlidingTabStrip) findViewById(R.id.tabs);
    pager = (ViewPager) findViewById(R.id.pager);

    ArrayList<ViewPagerTab> tabsList = new ArrayList<>();
    tabsList.add(new ViewPagerTab("One", 0));
    tabsList.add(new ViewPagerTab("Two", 1));
    tabsList.add(new ViewPagerTab("Three", 2));

    adapter = new MainAdapter(getSupportFragmentManager(), tabsList);

    pager.setAdapter(adapter);
    tabs.setViewPager(pager);

    pager.setOffscreenPageLimit(3);
    getSupportActionBar().hide();
}

你会得到这样的东西:

最后,要在运行时获取和更改选项卡视图,您只需在您的ActivityFragment 中调用PagerSlidingTabStrip 对象的getChildAt 函数,然后做您想做的事:

private void notifyTabStripChanged(int position, int notificationsCount) {
    LinearLayout tabHost = (LinearLayout) tabs.getChildAt(0);
    RelativeLayout tabLayout = (RelativeLayout) tabHost.getChildAt(position);
    TextView badge = (TextView) tabLayout.findViewById(R.id.badge);
    if (notificationsCount > 0) {
        badge.setVisibility(View.VISIBLE);
        badge.setText(String.valueOf(notificationsCount));
    } else {
        badge.setVisibility(View.GONE);
    }
}

别忘了,孩子的观看次数是从 0 开始的。如果要使用图片,只需将 ImageView 替换为 TextView 徽章并更改其图片资源而不是文本即可。享受吧!

【讨论】:

  • 嘿,非常感谢您的项目和解释。帮助很大。会接受它,但我用不同的方式做了 - 我将函数 addIconTab(final int position, int resId) 更改为膨胀自定义视图而不是 ImageButton。在我使用PagerSlidingTabStrip 的片段中,我使用getChildtAt() 获取选项卡并根据需要设置文本或隐藏它。
  • 不客气!这是您的选择,但我认为 IconTabProvider 是为仅带有图标的选项卡创建的,而 CustomTabProvider 是为完全可自定义的选项卡创建的。无论如何,很高兴帮助你:)
  • 在较小的设备上,标签文本的大小不同。
【解决方案2】:

您可以通过分叉此库并更改 IconTabProvider 的行为来实现您想要的,在示例应用程序中使用 there 实现仅使用静态资源。


对你的 lib fork 所做的更改以添加动态图标更改:

PagerSlidingTabStrip:

更改 IconTabProvider 接口的 getPageIconResId 方法的返回类型(和名称)

public interface IconTabProvider {
    //public int getPageIconResId(int position) becomes
    public Bitmap getPageIconBitmap(int position)
}

这会导致在PagerSlidingTabStrip 中更新对此方法的调用

--

并且还要从

更改方法 addIconTab
private void addIconTab(final int position, int resId) {
    ImageButton tab = new ImageButton(getContext());
    tab.setImageResource(resId);
    addTab(position, tab);
}

private void addIconTab(final int position, bitmap icon) {
    ImageButton tab = new ImageButton(getContext());
    tab.setImageBitmap(icon);
    addTab(position, tab);
}

然后你需要为你的标签栏创建一个适配器,这里是一个例子:

public class DynamicIconPagerAdapter extends PagerAdapter implements IconTabProvider {

    public HashMap<Integer, Bitmap> mapBetweenPositionAndIcons = new HashMap();

    public DynamicIconPagerAdapter () {
        super();
    }

    @Override
    public int getCount() {
        return mapBetweenPositionAndIcons.size();
    }

    @Override
    public Bitmap getPageIconResId(int position) {
        return mapBetweenPositionAndIcons.get(position);
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        // looks a little bit messy here
        TextView v = new TextView(getActivity());
        v.setBackgroundResource(R.color.background_window);
        v.setText("PAGE " + (position + 1));
        final int padding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 16, getResources()
                .getDisplayMetrics());
        v.setPadding(padding, padding, padding, padding);
        v.setGravity(Gravity.CENTER);
        container.addView(v, 0);
        return v;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object view) {
        container.removeView((View) view);
    }

    @Override
    public boolean isViewFromObject(View v, Object o) {
        return v == ((View) o);
    }

}

最后,当您想要更新图标时,只需更改地图的相应位图 (mapBetweenPositionAndIcons) 并在 PagerSlidingTabStrip 对象上调用 notifyDataSetChanged()。

由于时间不够,我还没有测试我的解决方案,但我会尽快测试! ;)

【讨论】:

    猜你喜欢
    • 2018-10-31
    • 1970-01-01
    • 2021-11-03
    • 2020-02-26
    • 2022-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多