I'm trying to implement the tablayout, I would like to set width of the tab depending on text content in individual tabs, right now it is set equally, which results on small text, tab width feels higher.
Try this:
public void wrapTabIndicatorToTitle(TabLayout tabLayout, int externalMargin, int internalMargin) {
View tabStrip = tabLayout.getChildAt(0);
if (tabStrip instanceof ViewGroup) {
ViewGroup tabStripGroup = (ViewGroup) tabStrip;
int childCount = ((ViewGroup) tabStrip).getChildCount();
for (int i = 0; i < childCount; i++) {
View tabView = tabStripGroup.getChildAt(i);
//set minimum width to 0 for instead for small texts, indicator is not wrapped as expected
tabView.setMinimumWidth(0);
// set padding to 0 for wrapping indicator as title
tabView.setPadding(0, tabView.getPaddingTop(), 0, tabView.getPaddingBottom());
// setting custom margin between tabs
if (tabView.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) {
ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) tabView.getLayoutParams();
if (i == 0) {
// left
settingMargin(layoutParams, externalMargin, internalMargin);
} else if (i == childCount - 1) {
// right
settingMargin(layoutParams, internalMargin, externalMargin);
} else {
// internal
settingMargin(layoutParams, internalMargin, internalMargin);
}
}
}
tabLayout.requestLayout();
}
}
private void settingMargin(ViewGroup.MarginLayoutParams layoutParams, int start, int end) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
layoutParams.setMarginStart(start);
layoutParams.setMarginEnd(end);
} else {
layoutParams.leftMargin = start;
layoutParams.rightMargin = end;
}
}
After setting the view pager in java file add :
wrapTabIndicatorToTitle(tabLayout,60,60);
Try this! It will reduce your efforts.
<android.support.design.widget.TabLayout
android:id="#+id/tblHome"
android:layout_width="match_parent"
android:layout_height="48dp"
app:tabMode="scrollable">
Put this below XML code for TabLayout
<android.support.design.widget.TabLayout
android:id="#+id/tab_Layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
app:tabGravity="fill"
app:tabMode="scrollable"
/>
Related
I have an AppBarLayout with CollapsingToolbarLayout, two views below and ViewPager at the rest of the screen
<Coordinator>
<AppBarLayout>
// Toolbar stuff inside
<CollapsingToolbarLayout app:layout_scrollFlags="scroll|exitUntilCollapsed"/>
// Should collapse by design
<FirstButtonView app:layout_scrollFlags="scroll" />
<TabLayout app:layout_scrollFlags="scroll|exitUntilCollapsed">
</AppBarLayout>
<ViewPager app:layout_behavior="#string/appbar_scrolling_view_behavior"/>
</Coordinator>
With this layout it collapsed toolbar as expected, but both views are being pinned to the top
As i see in AppBarLayout class, when it calculates possible scroll, it iterates through child views until meet flag SCROLL_FLAG_EXIT_UNTIL_COLLAPSED=2, then breaks the loop
public final int getTotalScrollRange() {
if (this.totalScrollRange != -1) {
return this.totalScrollRange;
} else {
int range = 0;
int i = 0;
for(int z = this.getChildCount(); i < z; ++i) {
View child = this.getChildAt(i);
AppBarLayout.LayoutParams lp = (AppBarLayout.LayoutParams)child.getLayoutParams();
int childHeight = child.getMeasuredHeight();
int flags = lp.scrollFlags;
if ((flags & 1) == 0) {
break;
}
range += childHeight + lp.topMargin + lp.bottomMargin;
if ((flags & 2) != 0) {
range -= ViewCompat.getMinimumHeight(child);
break;
}
}
return this.totalScrollRange = Math.max(0, range - this.getTopInset());
}
}
Is it possible somehow to solve it?
Target design
Based on Documentation on using "SCROLL_FLAG_SCROLL", "If any sibling views before this one do not have this flag, then this value has no effect."
Hence the same flag has to be used with other siblings.
Is there any way I can adjust listview's height as of it's content height in xamarin.forms? I could successfully do it for ios but for android, I applied a solution that leads to slow layout rendering.
code
public class CustomListViewRenderer : ListViewRenderer
{
...
protected async override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
base.OnMeasure(widthMeasureSpec, heightMeasureSpec);
if(Element == null || ((CustomListView)Element).IsScrollable)
{
return;
}
var view = (CustomListView)Element;
if(!view.IsScrollable)
{
var mAdapter = nativeList.Adapter;
int totalHeight = 0;
int listWidth = nativeList.MeasuredWidth;
int listHeight = nativeList.MeasuredHeight;
if(totalCount == nativeList.Count)
{
//return;
}
for (int i = 0; i < mAdapter.Count; i++)
{
global::Android.Views.View mView = mAdapter.GetView(i, null, nativeList);
mView.Measure(MeasureSpec.MakeMeasureSpec(listWidth, MeasureSpecMode.Exactly),
MeasureSpec.MakeMeasureSpec(0, MeasureSpecMode.Unspecified));
totalHeight += (int)(mView.MeasuredHeight / Resources.DisplayMetrics.Density);
totalCount = i + 1;
}
ViewGroup.LayoutParams param = nativeList.LayoutParameters;
param.Height = totalHeight
+ (nativeList.DividerHeight * (mAdapter.Count - 1));
view.HeightRequest = param.Height;
}
}
}
This however does not always generate exact height for listview, sometimes leaving space at bottom. Moreover it creates a great delay in laying out the page where list view has been used.
Can anyone please help me with this?
Is there any way I can adjust listview's height as of it's content height in xamarin.forms?
You could using HasUnevenRows property to implement this feature :
HasUnevenRows – true/false value, rows have varying heights if set to true. Defaults to false.
Row heights don't have to be manually set once HasUnevenRows has been set to true, because the heights will be automatically calculated by Xamarin.Forms.
C# :
RowHeightDemoListView.HasUnevenRows = true;
XAML :
<ListView x:Name="RowHeightDemoListView" HasUnevenRows="true" />
Here is my code:
private TabLayout tabLayout;
private int[] tabIcons = {
R.mipmap.ic_compass,
R.mipmap.ic_place,
R.mipmap.ic_passport,
R.mipmap.ic_setting
};
...
tabLayout.getTabAt(0).setIcon(tabIcons[0]);
tabLayout.getTabAt(1).setIcon(tabIcons[1]);
tabLayout.getTabAt(2).setIcon(tabIcons[2]);
tabLayout.getTabAt(3).setIcon(tabIcons[3]);
The size of icon is according to image size. How could I resize it?
set icons padding
for (int i = 0; i < tablayout.getTabWidget().getChildCount(); i++)
{
tablayout.getTabWidget().getChildAt(i).setPadding(10,10,10,10);
}
If you don't want to use xml for the custom view. Simply create imageview on runtime and add that in tablayout in a particular tab.
ImageView imgView= new ImageView(MainActivity.this);
imgView.setImageResource(drawableImage);
imgView.setPadding(10,10,10,10)
tabLayout.getTabAt(1).setCustomView(imgView);
It will look like this.
change of Icon size android.support.design.widget.TabLayout
for (int i = 0; i < view_bottom_tabLayout.getTabCount(); i++)
{
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(60, 60); //set new width & Height
params.gravity = Gravity.CENTER; //set gravity back to center
view_bottom_tabLayout.getChildAt(i).setLayoutParams(params);//set ur new params
}
To get total control of size I recommend using a custom view to render the tab.
First create a new layout - named "my_custom_tab" for this example
<?xml version="1.0" encoding="utf-8"?>
<!--Change the width, height, scaleType to whatever you like-->
<ImageView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="fitCenter"
android:id="#+id/icon"
android:layout_gravity="center_horizontal"
android:src="#mipmap/ic_launcher"/>
Now in your code set the custom image
private void setUpTabs (ViewPager viewPager) {
TabLayout tabs = (TabLayout) findViewById(R.id.tabs);
if (tabs != null) {
tabs.setupWithViewPager(viewPager);
int tabCount = tabAdapter.getCount(); //Assuming you have already somewhere set the adapter for the ViewPager
for (int i = 0; i < tabCount; i++) {
TabLayout.Tab tab = tabs.getTabAt(i);
if (tab != null){
ImageView myCustomIcon = (ImageView) LayoutInflater.from(tabs.getContext()).inflate(R.layout.my_custom_tab, null);
/*Here is where to set image if doing it dynamically
myCustomIcon.setImageBitmap(bitmap);
*/
tab.setCustomView(myCustomIcon);
}
}
}
}
you can do this:
LinearLayout ll = (LinearLayout) tabLayout.getChildAt(0);
for (int i = 0; i < ll.getChildCount(); i++) {
LinearLayout tabView = (LinearLayout) ll.getChildAt(i);
for (int j = 0; j < tabView.getChildCount(); j++) {
if (tabView.getChildAt(j) instanceof TextView) {
TextView textView = (TextView) tabView.getChildAt(j);
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) textView.getLayoutParams();
layoutParams.topMargin = 0;
textView.setLayoutParams(layoutParams);
} else if (tabView.getChildAt(j) instanceof ImageView) {
ImageView imageView = (ImageView) tabView.getChildAt(j);
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) imageView.getLayoutParams();
layoutParams.bottomMargin = 0;
imageView.setLayoutParams(layoutParams);
}
}
}
I decide to close this question. Since we actually cannot set specific size for icon in TabLayout but padding to it.
Ref:
https://developer.android.com/guide/practices/ui_guidelines/icon_design_tab
one code worked for me, the answer above of Deepak Sachdeva
just i edited it a litlle, try it 100% working
from first i add the tab with custom image
ImageView imgView= new ImageView(getApplicationContext());
imgView.setImageResource(R.drawable.icon);
imgView.setScaleType(ImageView.ScaleType.FIT_CENTER);
imgView.setLayoutParams(new LinearLayout.LayoutParams(100, 100));
tablayout1.addTab(tablayout1.newTab().setCustomView(imgView));
and do that to all your tabs, add them by this way.
Essentially, I need an "options" menu that can be accessed by swiping the screen left to right (or clicking on the options button in the left top corner of the screen). I also need it to cover the screen, but not fully replace it (it needs to be semi-opaque so that the previous menu is visible beneath it). What I have so far (I'm working on someone else's code, still haven't dechiphered it all, sorry for the lack of information):
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- As the main content view, the view below consumes the entire
space available using match_parent in both dimensions. -->
<FrameLayout
android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<!-- android:layout_gravity="start" tells DrawerLayout to treat
this as a sliding drawer on the left side for left-to-right
languages and on the right side for right-to-left languages.
The drawer is given a fixed width in dp and extends the full height of
the container. A solid background is used for contrast
with the content view. -->
<ListView
android:id="#+id/left_drawer"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:layout_gravity="start"
android:choiceMode="singleChoice"
android:divider="#android:color/transparent"
android:dividerHeight="0dp"
android:background="#color/blue"
/>
</android.support.v4.widget.DrawerLayout>
I have some functions to fill in the layout with clickable options, however, I can't make the options go full screen. I swipe left to right, and it only goes about 75% of the way. How can I make it a full-screen options panel?
(I can't make it a new Activity, it needs to overlap with the previous one)
I have the opacity handled and the options buttons, I just can't make this go all the way to the right side of the screen. :D
This works on all android versions:
View mSlidingView = findViewById(R.id.slider);
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
DrawerLayout.LayoutParams params = (DrawerLayout.LayoutParams) mSlidingView.getLayoutParams();
params.width = metrics.widthPixels;
mSlidingView.setLayoutParams(params);
Put this In your onCreate.
The best way to do this is to create a custom DrawerLayout. I found this solution to work perfectly.
Link to custom Full-Screen drawer layout implementation
public class FullDrawerLayout extends DrawerLayout {
private static final int MIN_DRAWER_MARGIN = 0; // dp
public FullDrawerLayout(Context context) {
super(context);
}
public FullDrawerLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public FullDrawerLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
if (widthMode != MeasureSpec.EXACTLY || heightMode != MeasureSpec.EXACTLY) {
throw new IllegalArgumentException(
"DrawerLayout must be measured with MeasureSpec.EXACTLY.");
}
setMeasuredDimension(widthSize, heightSize);
// Gravity value for each drawer we've seen. Only one of each permitted.
int foundDrawers = 0;
final int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = getChildAt(i);
if (child.getVisibility() == GONE) {
continue;
}
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (isContentView(child)) {
// Content views get measured at exactly the layout's size.
final int contentWidthSpec = MeasureSpec.makeMeasureSpec(
widthSize - lp.leftMargin - lp.rightMargin, MeasureSpec.EXACTLY);
final int contentHeightSpec = MeasureSpec.makeMeasureSpec(
heightSize - lp.topMargin - lp.bottomMargin, MeasureSpec.EXACTLY);
child.measure(contentWidthSpec, contentHeightSpec);
} else if (isDrawerView(child)) {
final int childGravity =
getDrawerViewGravity(child) & Gravity.HORIZONTAL_GRAVITY_MASK;
if ((foundDrawers & childGravity) != 0) {
throw new IllegalStateException("Child drawer has absolute gravity " +
gravityToString(childGravity) + " but this already has a " +
"drawer view along that edge");
}
final int drawerWidthSpec = getChildMeasureSpec(widthMeasureSpec,
MIN_DRAWER_MARGIN + lp.leftMargin + lp.rightMargin,
lp.width);
final int drawerHeightSpec = getChildMeasureSpec(heightMeasureSpec,
lp.topMargin + lp.bottomMargin,
lp.height);
child.measure(drawerWidthSpec, drawerHeightSpec);
} else {
throw new IllegalStateException("Child " + child + " at index " + i +
" does not have a valid layout_gravity - must be Gravity.LEFT, " +
"Gravity.RIGHT or Gravity.NO_GRAVITY");
}
}
}
boolean isContentView(View child) {
return ((LayoutParams) child.getLayoutParams()).gravity == Gravity.NO_GRAVITY;
}
boolean isDrawerView(View child) {
final int gravity = ((LayoutParams) child.getLayoutParams()).gravity;
final int absGravity = Gravity.getAbsoluteGravity(gravity,
child.getLayoutDirection());
return (absGravity & (Gravity.LEFT | Gravity.RIGHT)) != 0;
}
int getDrawerViewGravity(View drawerView) {
final int gravity = ((LayoutParams) drawerView.getLayoutParams()).gravity;
return Gravity.getAbsoluteGravity(gravity, drawerView.getLayoutDirection());
}
static String gravityToString(int gravity) {
if ((gravity & Gravity.LEFT) == Gravity.LEFT) {
return "LEFT";
}
if ((gravity & Gravity.RIGHT) == Gravity.RIGHT) {
return "RIGHT";
}
return Integer.toHexString(gravity);
}
}
<include
android:id="#+id/left_drawer"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="start"
layout="#layout/drawer"
android:layout_marginLeft="-64dp"/>
It's too late to answer, but for future reads of this question, I am giving my 2c tip: view which holds drawer should have end and right margins set to -64dp, because this value is aparently fixed in the code for rendering drawer.
So, in this case and since android:layout_gravity="start", ListView should have two additional parameters set as follows:
<ListView
...
android:layout_marginEnd="-65dp"
android:layout_marginRight="-65dp" />
On the other hand, if android:layout_gravity="end", then android:layout_marginStart and android:layout_marginLeft should be set to -65dp.
FrameLayout frameLayout = findViewById(R.id.frame_menu);
DrawerLayout.LayoutParams fparams = (DrawerLayout.LayoutParams) frameLayout.getLayoutParams();
DisplayMetrics displaymetrics = new DisplayMetrics();
activity.getWindowManager().getDefaultDisplay()
.getMetrics(displaymetrics);
int w = displaymetrics.widthPixels;
fparams.width = w;
frameLayout.setLayoutParams(fparams);
frameLayout.requestLayout();
Can anybody tell me how to align tab text in the center in android? I had given android:gravity="center" for LinearLayout and TabWidget. It is still not working. Can anybody tell me how to do this?
Thanks
use this
int tabCount = tabHost.getTabWidget().getTabCount();
for (int i = 0; i < tabCount; i++) {
final View view = tabHost.getTabWidget().getChildTabViewAt(i);
if ( view != null ) {
// reduce height of the tab
view.getLayoutParams().height *= 0.66;
// get title text view
final View textView = view.findViewById(android.R.id.title);
if ( textView instanceof TextView ) {
// just in case check the type
// center text
((TextView) textView).setGravity(Gravity.CENTER);
// wrap text
((TextView) textView).setSingleLine(false);
// explicitly set layout parameters
textView.getLayoutParams().height = ViewGroup.LayoutParams.FILL_PARENT;
textView.getLayoutParams().width = ViewGroup.LayoutParams.WRAP_CONTENT;
}
}
}
Use android:layout_gravity="center"