Android: 不推荐使用非滑动标签?
Android: non-sliding tabs are deprecated?
我有一个非常简单的任务(至少我是这么认为的)- 制作 5 个不可滚动的静态标签,其中包含图标和片段
我在这个任务上花了一整天,我真的很惊讶,在现代 Android API 中似乎很难实现,因为我发现的所有东西都是无用的:
PagerTabStrip - 它是可滚动的,不能使用固定数量的显示标签
ActionBar.TabListener - 自 API 21
以来已弃用
FragmentTabHost - 有一些错误 "Exception raised during rendering: No tab known for tag null"
SlidingTabLayout - 再次滑动 :( 不能使用固定数量的显示标签
也许我错过了什么?问候。
使用新工具
替代操作栏(工具栏)
https://developer.android.com/reference/android/widget/Toolbar.html
正如我所承诺的,我为您制作了一些演示项目。
对你的问题最简单的解决方案似乎是 LinearLayout,这就是我使用的以及 android 的图像。
首先您需要在名为 attrs.xml 的值文件夹中创建一个文件。如果你已经有了它,那么只需添加 stylable
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="SimpleTabIndicator">
<attr name="numberOfTabs" format="integer"/>
<attr name="indicatorColor" format="color"/>
</declare-styleable>
</resources>
然后创建一个名为SimpleTabIndicator
的class
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;
public class SimpleTabIndicator extends View {
private static final String TAG = SimpleTabIndicator.class.getSimpleName();
private float density;
private int measuredHeight, measuredWidth;
private int mNumberOfTabs;
private Paint mIndicatorPaint;
private int mIndicatorColor = 0xFFFDE992;
private int currentTab = 1;
public SimpleTabIndicator(Context context) {
super(context);
init(null, 0);
}
public SimpleTabIndicator(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs, 0);
}
public SimpleTabIndicator(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(attrs, defStyleAttr);
}
private void init(AttributeSet attrs, int style) {
if (!isInEditMode() && Build.VERSION.SDK_INT >= 11) {
setLayerType(View.LAYER_TYPE_NONE, null);
}
Resources res = getResources();
density = res.getDisplayMetrics().density;
TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.SimpleTabIndicator, style, 0);
mIndicatorColor = typedArray.getColor(R.styleable.SimpleTabIndicator_indicatorColor, mIndicatorColor);
mNumberOfTabs = typedArray.getInt(R.styleable.SimpleTabIndicator_numberOfTabs, 1);
typedArray.recycle();
mIndicatorPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mIndicatorPaint.setStyle(Paint.Style.FILL);
mIndicatorPaint.setColor(mIndicatorColor);
}
public int getNumberOfTabs() {
return mNumberOfTabs;
}
public void setNumberOfTabs(int mNumberOfTabs) {
this.mNumberOfTabs = mNumberOfTabs;
invalidate();
}
public int getCurrentTab() {
return currentTab;
}
public void setCurrentTab(int currentTab) {
this.currentTab = currentTab;
invalidate();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
measuredHeight = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
measuredWidth = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
setMeasuredDimension(measuredWidth, measuredHeight);
}
@Override
protected void onDraw(Canvas canvas) {
if (measuredHeight <= 0 || measuredWidth <= 0 || mNumberOfTabs == 0) {
return; // Not much we can draw :(
}
int length = measuredWidth / mNumberOfTabs;
int startX = (currentTab - 1) * length;
canvas.drawRect(startX, 0, startX + length, measuredHeight, mIndicatorPaint);
}
}
接下来是 ZoomOutPageTransformer。这家伙是 Google 的 "borrowed"。
import android.support.v4.view.ViewPager;
import android.view.View;
public class ZoomOutPageTransformer implements ViewPager.PageTransformer {
private static final float MIN_SCALE = 0.85f;
private static final float MIN_ALPHA = 0.5f;
public void transformPage(View view, float position) {
int pageWidth = view.getWidth();
int pageHeight = view.getHeight();
if (position < -1) { // [-Infinity,-1)
// This page is way off-screen to the left.
view.setAlpha(0);
}
else if (position <= 1) { // [-1,1]
// Modify the default slide transition to shrink the page as well
float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position));
float vertMargin = pageHeight * (1 - scaleFactor) / 2;
float horzMargin = pageWidth * (1 - scaleFactor) / 2;
if (position < 0) {
view.setTranslationX(horzMargin - vertMargin / 2);
}
else {
view.setTranslationX(-horzMargin + vertMargin / 2);
}
// Scale the page down (between MIN_SCALE and 1)
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
// Fade the page relative to its size.
view.setAlpha(MIN_ALPHA + (scaleFactor - MIN_SCALE) / (1 - MIN_SCALE) * (1 - MIN_ALPHA));
}
else { // (1,+Infinity]
// This page is way off-screen to the right.
view.setAlpha(0);
}
}
}
接下来创建一个名为 dummy_fragment_layout.xml
的布局
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/fragmentNumber"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:gravity="center_horizontal"
android:text="1"
android:textSize="50sp"
android:textStyle="bold"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@id/fragmentNumber"
android:gravity="center_horizontal"
android:text="Fragment"
android:textSize="30sp"/>
</RelativeLayout>
现在主要activityactivity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#808080"
android:orientation="vertical"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="?actionBarSize"
android:background="#26292E"
android:orientation="horizontal">
<ImageView
android:id="@+id/tab1"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:adjustViewBounds="true"
android:onClick="onTabSelected"
android:padding="10dp"
android:src="@android:drawable/btn_radio"
android:tag="1"/>
<ImageView
android:id="@+id/tab2"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:adjustViewBounds="true"
android:onClick="onTabSelected"
android:padding="10dp"
android:src="@android:drawable/btn_star"
android:tag="2"/>
<ImageView
android:id="@+id/tab3"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:adjustViewBounds="true"
android:onClick="onTabSelected"
android:padding="10dp"
android:src="@android:drawable/btn_star"
android:tag="3"/>
<ImageView
android:id="@+id/tab4"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:adjustViewBounds="true"
android:onClick="onTabSelected"
android:padding="10dp"
android:src="@android:drawable/btn_star"
android:tag="4"/>
<ImageView
android:id="@+id/tab5"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:adjustViewBounds="true"
android:onClick="onTabSelected"
android:padding="10dp"
android:src="@android:drawable/btn_star"
android:tag="5"/>
</LinearLayout>
<test.kseneman.si.test.SimpleTabIndicator
android:id="@+id/tabIndicator"
android:layout_width="match_parent"
android:layout_height="2dp"
android:background="#26292E"
app:indicatorColor="#FFFDE992"
app:numberOfTabs="5"/>
<android.support.v4.view.ViewPager
android:id="@+id/pager"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
最后是 MainActivity
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
public class MainActivity extends ActionBarActivity {
private ViewPager mPager;
private DummyFragmentsAdapter mPagerAdapter;
private SimpleTabIndicator tabIndicator;
private ImageView selectedImageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mPagerAdapter = new DummyFragmentsAdapter(getSupportFragmentManager());
tabIndicator = (SimpleTabIndicator) findViewById(R.id.tabIndicator);
// Default state
selectedImageView = (ImageView) findViewById(R.id.tab1);
mPager = (ViewPager) findViewById(R.id.pager);
mPager.setAdapter(mPagerAdapter);
mPager.setPageTransformer(false, new ZoomOutPageTransformer());
}
public void onTabSelected(View v) {
// Sanity check
if (v == null || !(v instanceof ImageView) || v.getTag() == null) {
return;
}
int postion = Integer.valueOf((String) v.getTag());
Log.d("onTabSelected", "postion: " + postion);
if (postion == mPager.getCurrentItem() + 1) {
// The same selected, do nothing?
return;
}
// Change selected images
selectedImageView.setImageResource(android.R.drawable.btn_star);
selectedImageView = (ImageView) v;
selectedImageView.setImageResource(android.R.drawable.btn_radio);
mPager.setCurrentItem(postion - 1); // They start at 0
tabIndicator.setCurrentTab(postion);
}
private class DummyFragmentsAdapter extends FragmentStatePagerAdapter {
public DummyFragmentsAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
DummyFragment fragment = new DummyFragment();
Bundle b = new Bundle();
b.putInt(DummyFragment.EXTRA_FRAGMENT_NUMBER, position);
fragment.setArguments(b);
return fragment;
}
@Override
public int getCount() {
return 5;
}
}
}
完整的项目 zip 可用 here
这是它的样子
我有一个非常简单的任务(至少我是这么认为的)- 制作 5 个不可滚动的静态标签,其中包含图标和片段
我在这个任务上花了一整天,我真的很惊讶,在现代 Android API 中似乎很难实现,因为我发现的所有东西都是无用的:
PagerTabStrip - 它是可滚动的,不能使用固定数量的显示标签
ActionBar.TabListener - 自 API 21
以来已弃用
FragmentTabHost - 有一些错误 "Exception raised during rendering: No tab known for tag null"
SlidingTabLayout - 再次滑动 :( 不能使用固定数量的显示标签
也许我错过了什么?问候。
使用新工具 替代操作栏(工具栏) https://developer.android.com/reference/android/widget/Toolbar.html
正如我所承诺的,我为您制作了一些演示项目。
对你的问题最简单的解决方案似乎是 LinearLayout,这就是我使用的以及 android 的图像。
首先您需要在名为 attrs.xml 的值文件夹中创建一个文件。如果你已经有了它,那么只需添加 stylable
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="SimpleTabIndicator">
<attr name="numberOfTabs" format="integer"/>
<attr name="indicatorColor" format="color"/>
</declare-styleable>
</resources>
然后创建一个名为SimpleTabIndicator
的classimport android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;
public class SimpleTabIndicator extends View {
private static final String TAG = SimpleTabIndicator.class.getSimpleName();
private float density;
private int measuredHeight, measuredWidth;
private int mNumberOfTabs;
private Paint mIndicatorPaint;
private int mIndicatorColor = 0xFFFDE992;
private int currentTab = 1;
public SimpleTabIndicator(Context context) {
super(context);
init(null, 0);
}
public SimpleTabIndicator(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs, 0);
}
public SimpleTabIndicator(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(attrs, defStyleAttr);
}
private void init(AttributeSet attrs, int style) {
if (!isInEditMode() && Build.VERSION.SDK_INT >= 11) {
setLayerType(View.LAYER_TYPE_NONE, null);
}
Resources res = getResources();
density = res.getDisplayMetrics().density;
TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.SimpleTabIndicator, style, 0);
mIndicatorColor = typedArray.getColor(R.styleable.SimpleTabIndicator_indicatorColor, mIndicatorColor);
mNumberOfTabs = typedArray.getInt(R.styleable.SimpleTabIndicator_numberOfTabs, 1);
typedArray.recycle();
mIndicatorPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mIndicatorPaint.setStyle(Paint.Style.FILL);
mIndicatorPaint.setColor(mIndicatorColor);
}
public int getNumberOfTabs() {
return mNumberOfTabs;
}
public void setNumberOfTabs(int mNumberOfTabs) {
this.mNumberOfTabs = mNumberOfTabs;
invalidate();
}
public int getCurrentTab() {
return currentTab;
}
public void setCurrentTab(int currentTab) {
this.currentTab = currentTab;
invalidate();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
measuredHeight = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
measuredWidth = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
setMeasuredDimension(measuredWidth, measuredHeight);
}
@Override
protected void onDraw(Canvas canvas) {
if (measuredHeight <= 0 || measuredWidth <= 0 || mNumberOfTabs == 0) {
return; // Not much we can draw :(
}
int length = measuredWidth / mNumberOfTabs;
int startX = (currentTab - 1) * length;
canvas.drawRect(startX, 0, startX + length, measuredHeight, mIndicatorPaint);
}
}
接下来是 ZoomOutPageTransformer。这家伙是 Google 的 "borrowed"。
import android.support.v4.view.ViewPager;
import android.view.View;
public class ZoomOutPageTransformer implements ViewPager.PageTransformer {
private static final float MIN_SCALE = 0.85f;
private static final float MIN_ALPHA = 0.5f;
public void transformPage(View view, float position) {
int pageWidth = view.getWidth();
int pageHeight = view.getHeight();
if (position < -1) { // [-Infinity,-1)
// This page is way off-screen to the left.
view.setAlpha(0);
}
else if (position <= 1) { // [-1,1]
// Modify the default slide transition to shrink the page as well
float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position));
float vertMargin = pageHeight * (1 - scaleFactor) / 2;
float horzMargin = pageWidth * (1 - scaleFactor) / 2;
if (position < 0) {
view.setTranslationX(horzMargin - vertMargin / 2);
}
else {
view.setTranslationX(-horzMargin + vertMargin / 2);
}
// Scale the page down (between MIN_SCALE and 1)
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
// Fade the page relative to its size.
view.setAlpha(MIN_ALPHA + (scaleFactor - MIN_SCALE) / (1 - MIN_SCALE) * (1 - MIN_ALPHA));
}
else { // (1,+Infinity]
// This page is way off-screen to the right.
view.setAlpha(0);
}
}
}
接下来创建一个名为 dummy_fragment_layout.xml
的布局<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/fragmentNumber"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:gravity="center_horizontal"
android:text="1"
android:textSize="50sp"
android:textStyle="bold"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@id/fragmentNumber"
android:gravity="center_horizontal"
android:text="Fragment"
android:textSize="30sp"/>
</RelativeLayout>
现在主要activityactivity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#808080"
android:orientation="vertical"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="?actionBarSize"
android:background="#26292E"
android:orientation="horizontal">
<ImageView
android:id="@+id/tab1"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:adjustViewBounds="true"
android:onClick="onTabSelected"
android:padding="10dp"
android:src="@android:drawable/btn_radio"
android:tag="1"/>
<ImageView
android:id="@+id/tab2"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:adjustViewBounds="true"
android:onClick="onTabSelected"
android:padding="10dp"
android:src="@android:drawable/btn_star"
android:tag="2"/>
<ImageView
android:id="@+id/tab3"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:adjustViewBounds="true"
android:onClick="onTabSelected"
android:padding="10dp"
android:src="@android:drawable/btn_star"
android:tag="3"/>
<ImageView
android:id="@+id/tab4"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:adjustViewBounds="true"
android:onClick="onTabSelected"
android:padding="10dp"
android:src="@android:drawable/btn_star"
android:tag="4"/>
<ImageView
android:id="@+id/tab5"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:adjustViewBounds="true"
android:onClick="onTabSelected"
android:padding="10dp"
android:src="@android:drawable/btn_star"
android:tag="5"/>
</LinearLayout>
<test.kseneman.si.test.SimpleTabIndicator
android:id="@+id/tabIndicator"
android:layout_width="match_parent"
android:layout_height="2dp"
android:background="#26292E"
app:indicatorColor="#FFFDE992"
app:numberOfTabs="5"/>
<android.support.v4.view.ViewPager
android:id="@+id/pager"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
最后是 MainActivity
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
public class MainActivity extends ActionBarActivity {
private ViewPager mPager;
private DummyFragmentsAdapter mPagerAdapter;
private SimpleTabIndicator tabIndicator;
private ImageView selectedImageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mPagerAdapter = new DummyFragmentsAdapter(getSupportFragmentManager());
tabIndicator = (SimpleTabIndicator) findViewById(R.id.tabIndicator);
// Default state
selectedImageView = (ImageView) findViewById(R.id.tab1);
mPager = (ViewPager) findViewById(R.id.pager);
mPager.setAdapter(mPagerAdapter);
mPager.setPageTransformer(false, new ZoomOutPageTransformer());
}
public void onTabSelected(View v) {
// Sanity check
if (v == null || !(v instanceof ImageView) || v.getTag() == null) {
return;
}
int postion = Integer.valueOf((String) v.getTag());
Log.d("onTabSelected", "postion: " + postion);
if (postion == mPager.getCurrentItem() + 1) {
// The same selected, do nothing?
return;
}
// Change selected images
selectedImageView.setImageResource(android.R.drawable.btn_star);
selectedImageView = (ImageView) v;
selectedImageView.setImageResource(android.R.drawable.btn_radio);
mPager.setCurrentItem(postion - 1); // They start at 0
tabIndicator.setCurrentTab(postion);
}
private class DummyFragmentsAdapter extends FragmentStatePagerAdapter {
public DummyFragmentsAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
DummyFragment fragment = new DummyFragment();
Bundle b = new Bundle();
b.putInt(DummyFragment.EXTRA_FRAGMENT_NUMBER, position);
fragment.setArguments(b);
return fragment;
}
@Override
public int getCount() {
return 5;
}
}
}
完整的项目 zip 可用 here
这是它的样子