プロジェクトで新しいデザインTabLayoutを使用しようとしています。レイアウトをすべての画面サイズと向きに適応させたいのですが、一方向で正しく見ることができます。
TabLayoutを次のように設定する重力とモードを扱っています。
tabLayout.setTabGravity(TabLayout.GRAVITY_CENTER);
tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);
そのため、スペースがない場合、tabLayoutはスクロール可能ですが、スペースがある場合は中央に配置されると予想しています。
ガイドから:
public static final int GRAVITY_CENTER TabLayoutの中央にタブをレイアウトするために使用される重力。
public static final int GRAVITY_FILL可能な限りTabLayoutを埋めるために使用される重力。このオプションは、MODE_FIXEDとともに使用した場合にのみ有効になります。
public static final int MODE_FIXED固定タブはすべてのタブを同時に表示し、タブ間のクイックピボットの恩恵を受けるコンテンツに最適です。タブの最大数は、ビューの幅によって制限されます。固定タブの幅は、最も広いタブラベルに基づいて同じです。
public static final int MODE_SCROLLABLEスクロール可能なタブは、特定の瞬間にタブのサブセットを表示し、より長いタブラベルとより多くのタブを含むことができます。ユーザーがタブラベルを直接比較する必要がない場合、タッチインターフェースでコンテキストを閲覧するのに最適です。
GRAVITY_FILLはMODE_FIXEDとのみ互換性がありますが、atはGRAVITY_CENTERに対して何も指定していません。MODE_SCROLLABLEと互換性があると思いますが、これはGRAVITY_CENTERとMODE_SCROLLABLEを使用して取得するものです
したがって、両方の方向でSCROLLABLEを使用していますが、GRAVITY_CENTERは使用していません。
これは私が風景に期待するものです。しかし、これを得るには、MODE_FIXEDを設定する必要があります。そのため、私はポートレートで取得します。
TabLayoutが画面に収まる場合、GRAVITY_CENTERがSCROLLABLEで機能しないのはなぜですか?重力とモードを動的に設定する方法はありますか?
どうもありがとうございました!
編集:これは私のTabLayoutのレイアウトです:
<Android.support.design.widget.TabLayout
Android:id="@+id/sliding_tabs"
Android:layout_width="match_parent"
Android:background="@color/orange_pager"
Android:layout_height="wrap_content" />
なぜこの動作が起こるのかわからなかったので、次のコードを使用しました。
float myTabLayoutSize = 360;
if (DeviceInfo.getWidthDP(this) >= myTabLayoutSize ){
tabLayout.setTabMode(TabLayout.MODE_FIXED);
} else {
tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);
}
基本的に、tabLayoutの幅を手動で計算し、tabLayoutがデバイスに収まるかどうかに応じてTab Modeを設定する必要があります。
手動でレイアウトのサイズを取得する理由は、すべてのタブがスクロール可能モードで同じ幅を持っているわけではないためです。
タブの重力はMODE_FIXED
のみに影響します。
考えられる解決策の1つは、layout_width
をwrap_content
に設定し、layout_gravity
をcenter_horizontal
に設定することです。
<Android.support.design.widget.TabLayout
Android:id="@+id/sliding_tabs"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:layout_gravity="center_horizontal"
app:tabMode="scrollable" />
タブが画面の幅よりも小さい場合、TabLayout
自体も小さくなり、重力のために中央に配置されます。タブが画面の幅よりも大きい場合、TabLayout
は画面の幅と一致し、スクロールがアクティブになります。
これは私がやった方法です
TabLayout.xml
<Android.support.design.widget.TabLayout
Android:id="@+id/tab_layout"
Android:layout_height="wrap_content"
Android:layout_width="wrap_content"
Android:background="@Android:color/transparent"
app:tabGravity="fill"
app:tabMode="scrollable"
app:tabTextAppearance="@style/TextAppearance.Design.Tab"
app:tabSelectedTextColor="@color/myPrimaryColor"
app:tabIndicatorColor="@color/myPrimaryColor"
Android:overScrollMode="never"
/>
作成する
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mToolbar = (Toolbar) findViewById(R.id.toolbar_actionbar);
mTabLayout = (TabLayout)findViewById(R.id.tab_layout);
mTabLayout.setOnTabSelectedListener(this);
setSupportActionBar(mToolbar);
mTabLayout.addTab(mTabLayout.newTab().setText("Dashboard"));
mTabLayout.addTab(mTabLayout.newTab().setText("Signature"));
mTabLayout.addTab(mTabLayout.newTab().setText("Booking/Sampling"));
mTabLayout.addTab(mTabLayout.newTab().setText("Calendar"));
mTabLayout.addTab(mTabLayout.newTab().setText("Customer Detail"));
mTabLayout.post(mTabLayout_config);
}
Runnable mTabLayout_config = new Runnable()
{
@Override
public void run()
{
if(mTabLayout.getWidth() < MainActivity.this.getResources().getDisplayMetrics().widthPixels)
{
mTabLayout.setTabMode(TabLayout.MODE_FIXED);
ViewGroup.LayoutParams mParams = mTabLayout.getLayoutParams();
mParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
mTabLayout.setLayoutParams(mParams);
}
else
{
mTabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);
}
}
};
実行可能な部分で@Mario Velascoのソリューションを少し変更しました
Android-tablayouthelper を見てください
TabLayout.MODE_FIXEDとTabLayout.MODE_SCROLLABLEの自動切り替えは、タブの合計幅に依存します。
app:tabMode = "scrollable"とAndroid:layout_gravity = "bottom"を追加するだけで物事がシンプルになります
ちょうどこのような
<Android.support.design.widget.TabLayout
Android:id="@+id/tabs"
Android:layout_width="match_parent"
Android:layout_height="?attr/actionBarSize"
Android:layout_gravity="bottom"
app:tabMode="scrollable"
app:tabIndicatorColor="@color/colorAccent" />
これを実現するために、AdaptiveTabLayoutクラスを作成しました。これは、実際に問題を解決し、質問に答え、他の回答ではできない問題を回避/回避するための唯一の方法でした。
ノート:
MODE_SCROLLABLE
に十分なスペースがあるが、MODE_FIXED
に十分なスペースがない場合を処理します。このケースを処理しないと、デバイスによっては異なるテキストサイズが表示されたり、一部のタブに2行のテキストが表示されたりするため、見た目が悪くなります。wrap_content
である必要があります。 xmlにモードや重力を設定しないでください。AdaptiveTabLayout.Java
import Android.content.Context;
import Android.support.annotation.NonNull;
import Android.support.annotation.Nullable;
import Android.support.design.widget.TabLayout;
import Android.util.AttributeSet;
import Android.widget.LinearLayout;
public class AdaptiveTabLayout extends TabLayout
{
private boolean mGravityAndModeSeUpNeeded = true;
public AdaptiveTabLayout(@NonNull final Context context)
{
this(context, null);
}
public AdaptiveTabLayout(@NonNull final Context context, @Nullable final AttributeSet attrs)
{
this(context, attrs, 0);
}
public AdaptiveTabLayout
(
@NonNull final Context context,
@Nullable final AttributeSet attrs,
final int defStyleAttr
)
{
super(context, attrs, defStyleAttr);
setTabMode(MODE_SCROLLABLE);
}
@Override
protected void onLayout(final boolean changed, final int l, final int t, final int r, final int b)
{
super.onLayout(changed, l, t, r, b);
if (mGravityAndModeSeUpNeeded)
{
setModeAndGravity();
}
}
private void setModeAndGravity()
{
final int tabCount = getTabCount();
final int screenWidth = UtilsDevice.getScreenWidth();
final int minWidthNeedForMixedMode = getMinSpaceNeededForFixedMode(tabCount);
if (minWidthNeedForMixedMode == 0)
{
return;
}
else if (minWidthNeedForMixedMode < screenWidth)
{
setTabMode(MODE_FIXED);
setTabGravity(UtilsDevice.isBigTablet() ? GRAVITY_CENTER : GRAVITY_FILL) ;
}
else
{
setTabMode(TabLayout.MODE_SCROLLABLE);
}
setLayoutParams(new LinearLayout.LayoutParams
(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
mGravityAndModeSeUpNeeded = false;
}
private int getMinSpaceNeededForFixedMode(final int tabCount)
{
final LinearLayout linearLayout = (LinearLayout) getChildAt(0);
int widestTab = 0;
int currentWidth;
for (int i = 0; i < tabCount; i++)
{
currentWidth = linearLayout.getChildAt(i).getWidth();
if (currentWidth == 0) return 0;
if (currentWidth > widestTab)
{
widestTab = currentWidth;
}
}
return widestTab * tabCount;
}
}
そして、これはDeviceUtilsクラスです。
import Android.content.res.Resources;
public class UtilsDevice extends Utils
{
private static final int sWIDTH_FOR_BIG_TABLET_IN_DP = 720;
private UtilsDevice() {}
public static int pixelToDp(final int pixels)
{
return (int) (pixels / Resources.getSystem().getDisplayMetrics().density);
}
public static int getScreenWidth()
{
return Resources
.getSystem()
.getDisplayMetrics()
.widthPixels;
}
public static boolean isBigTablet()
{
return pixelToDp(getScreenWidth()) >= sWIDTH_FOR_BIG_TABLET_IN_DP;
}
}
使用例:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:app="http://schemas.Android.com/apk/res-auto"
xmlns:tools="http://schemas.Android.com/tools"
Android:layout_width="match_parent"
Android:layout_height="match_parent">
<com.com.stackoverflow.example.AdaptiveTabLayout
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:background="?colorPrimary"
app:tabIndicatorColor="@color/white"
app:tabSelectedTextColor="@color/text_white_primary"
app:tabTextColor="@color/text_white_secondary"
tools:layout_width="match_parent"/>
</FrameLayout>
問題/助けを求める:
Logcat:
W/View: requestLayout() improperly called by Android.support.design.widget.TabLayout$SlidingTabStrip{3e1ebcd6 V.ED.... ......ID 0,0-466,96} during layout: running second layout pass
W/View: requestLayout() improperly called by Android.support.design.widget.TabLayout$TabView{3423cb57 VFE...C. ..S...ID 0,0-144,96} during layout: running second layout pass
W/View: requestLayout() improperly called by Android.support.design.widget.TabLayout$TabView{377c4644 VFE...C. ......ID 144,0-322,96} during layout: running second layout pass
W/View: requestLayout() improperly called by Android.support.design.widget.TabLayout$TabView{19ead32d VFE...C. ......ID 322,0-466,96} during layout: running second layout pass
私はそれを解決する方法がわかりません。助言がありますか?
これは、SCROLLABLE
とFIXED
+ FILL
の間で自動的に変更するために使用したソリューションです。 @ Fighter42ソリューションの完全なコードです。
(以下のコードは、Googleのタブ付きアクティビティテンプレートを使用した場合に変更を加える場所を示しています)
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
// Create the adapter that will return a fragment for each of the three
// primary sections of the activity.
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
// Set up the ViewPager with the sections adapter.
mViewPager = (ViewPager) findViewById(R.id.container);
mViewPager.setAdapter(mSectionsPagerAdapter);
// Set up the tabs
final TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(mViewPager);
// Mario Velasco's code
tabLayout.post(new Runnable()
{
@Override
public void run()
{
int tabLayoutWidth = tabLayout.getWidth();
DisplayMetrics metrics = new DisplayMetrics();
ActivityMain.this.getWindowManager().getDefaultDisplay().getMetrics(metrics);
int deviceWidth = metrics.widthPixels;
if (tabLayoutWidth < deviceWidth)
{
tabLayout.setTabMode(TabLayout.MODE_FIXED);
tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
} else
{
tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);
}
}
});
}
レイアウト:
<Android.support.design.widget.TabLayout
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:layout_gravity="center_horizontal" />
幅を埋める必要がない場合は、@ karaokyoソリューションを使用することをお勧めします。
これは私のために働いた唯一のコードです:
public static void adjustTabLayoutBounds(final TabLayout tabLayout,
final DisplayMetrics displayMetrics){
final ViewTreeObserver vto = tabLayout.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
tabLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
int totalTabPaddingPlusWidth = 0;
for(int i=0; i < tabLayout.getTabCount(); i++){
final LinearLayout tabView = ((LinearLayout)((LinearLayout) tabLayout.getChildAt(0)).getChildAt(i));
totalTabPaddingPlusWidth += (tabView.getMeasuredWidth() + tabView.getPaddingLeft() + tabView.getPaddingRight());
}
if (totalTabPaddingPlusWidth <= displayMetrics.widthPixels){
tabLayout.setTabMode(TabLayout.MODE_FIXED);
tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
}else{
tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);
}
tabLayout.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
}
});
}
DisplayMetricsは、これを使用して取得できます。
public DisplayMetrics getDisplayMetrics() {
final WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
final Display display = wm.getDefaultDisplay();
final DisplayMetrics displayMetrics = new DisplayMetrics();
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
display.getMetrics(displayMetrics);
}else{
display.getRealMetrics(displayMetrics);
}
return displayMetrics;
}
また、TabLayout XMLは次のようになります(tabMaxWidthを0に設定することを忘れないでください)。
<Android.support.design.widget.TabLayout
xmlns:app="http://schemas.Android.com/apk/res-auto"
Android:id="@+id/tab_layout"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
app:tabMaxWidth="0dp"/>
私はこれを次の方法で解決しました
if(tabLayout_chemistCategory.getTabCount()<4)
{
tabLayout_chemistCategory.setTabGravity(TabLayout.GRAVITY_FILL);
}else
{
tabLayout_chemistCategory.setTabMode(TabLayout.MODE_SCROLLABLE);
}
必要なのは、以下をTabLayoutに追加することです
custom:tabGravity="fill"
だから、あなたが持っているでしょう:
xmlns:custom="http://schemas.Android.com/apk/res-auto"
<Android.support.design.widget.TabLayout
Android:id="@+id/tabs"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
custom:tabGravity="fill"
/>
非常に単純な例であり、常に機能します。
/**
* Setup stretch and scrollable TabLayout.
* The TabLayout initial parameters in layout must be:
* Android:layout_width="wrap_content"
* app:tabMaxWidth="0dp"
* app:tabGravity="fill"
* app:tabMode="fixed"
*
* @param context your Context
* @param tabLayout your TabLayout
*/
public static void setupStretchTabLayout(Context context, TabLayout tabLayout) {
tabLayout.post(() -> {
ViewGroup.LayoutParams params = tabLayout.getLayoutParams();
if (params.width == ViewGroup.LayoutParams.MATCH_PARENT) { // is already set up for stretch
return;
}
int deviceWidth = context.getResources()
.getDisplayMetrics().widthPixels;
if (tabLayout.getWidth() < deviceWidth) {
tabLayout.setTabMode(TabLayout.MODE_FIXED);
params.width = ViewGroup.LayoutParams.MATCH_PARENT;
} else {
tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);
params.width = ViewGroup.LayoutParams.WRAP_CONTENT;
}
tabLayout.setLayoutParams(params);
});
}
<Android.support.design.widget.TabLayout
Android:id="@+id/tabList"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:layout_gravity="center"
app:tabMode="scrollable"/>
私の最終的な解決策
class DynamicModeTabLayout : TabLayout {
constructor(context: Context?) : super(context)
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
override fun setupWithViewPager(viewPager: ViewPager?) {
super.setupWithViewPager(viewPager)
val view = getChildAt(0) ?: return
view.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED)
val size = view.measuredWidth
if (size > measuredWidth) {
tabMode = MODE_SCROLLABLE
tabGravity = GRAVITY_CENTER
} else {
tabMode = MODE_FIXED
tabGravity = GRAVITY_FILL
}
}
}