Here I'm trying to change the position of TabIndicator to top from bottom but not getting success. I want just like as image is showing.
I have done everything but indicator is in bottom not in top and even I can't add dividers between Tabs too. Please look at my code and help me to solve this issue.
My code is like:
<?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:orientation="vertical">
<com.cws.widget.MyTabLayout
android:id="#+id/mainTabLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="1dp"
app:tabBackground="#color/drawer_tab_background"
app:tabGravity="fill"
app:tabIndicatorColor="#color/green"
app:tabMode="fixed" />
<com.cws.widget.NonSiwpablePager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
And styles.xml
<style name="AppCompatTheme" parent="Theme.AppCompat.Light.NoActionBar"></style>
<style name="AppToolbarTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Customize your theme here. -->
<item name="android:windowNoTitle">true</item>
<item name="colorPrimary">#000</item>
<item name="colorPrimaryDark">#color/colorPrimaryDark</item>
<item name="colorAccent">#color/colorAccent</item>
<item name="colorControlNormal">#FFF</item>
</style>
MyTabLayout.java
public class MyTabLayout extends TabLayout {
public MyTabLayout(Context context) {
super(context);
}
public MyTabLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyTabLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int height = 0;
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
child.measure(widthMeasureSpec, View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
int h = child.getMeasuredHeight();
if (h > height) height = h;
}
heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
ViewPager.java
public class NonSiwpablePager extends ViewPager {
public NonSiwpablePager(Context context) {
super(context);
}
public NonSiwpablePager(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
return false;
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return false;
}
}
Firstly you need to remove that tab indicator,
app:tabIndicatorHeight="0dp"
this line add into <com.cws.widget.MyTabLayout> xml file. and after that add that http://pastie.org/private/5lsxm7l8qoay4naobuddow as background
app:tabBackground="#drawable/selector_tab"
Hope it will work for you
Related
I want to set status bar color in my custom DrawerLayout like default navigation drawee. It work perfectly but DraweeLayout should be behind status bar and status bar color should be custom.
Below is my v21\style.
<resources>
<style name="AppTheme.Base" parent="Theme.AppCompat.Light.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<item name="android:statusBarColor">#color/orange</item>
</style>
Here is activity_main.xml
<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"
android:fitsSystemWindows="false">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:orientation="vertical"
>
<android.support.v7.widget.Toolbar
android:id="#+id/my_awesome_toolbar"
android:layout_height="80dp"
android:layout_width="match_parent"
android:minHeight="?attr/actionBarSize"
android:background="#color/orange"
android:fitsSystemWindows="true"
/>
</LinearLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="50dp">
<LinearLayout
android:id="#+id/llFirst"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#color/orange"
android:layout_marginTop="25dp"
android:orientation="horizontal">
<ImageView
android:id="#+id/imgMenu"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_gravity="center"
android:src="#drawable/menu" />
</LinearLayout>
</FrameLayout>
<ExpandableListView
android:id="#+id/lvLeft"
android:layout_width="280dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="#color/white"
android:choiceMode="singleChoice"
android:dividerHeight="0dp"
/>
</android.support.v4.widget.DrawerLayout>
Here is my MainActivity.
public class MainActivity extends Activity implements View.OnClickListener, ExpandableListView.OnChildClickListener {
private MyAdapter drawerLayoutAdapter;
private DrawerLayout drawer_layout;
private ImageView imgMenu;
private ArrayList<String> alTemp;
private ArrayList<MyModel> arrayList;
private ExpandableListView expandbleLis;
private Activity activity;
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setId();
setListner();
setSliderColor();
slideMenu();
loadArraylist();
drawerLayoutAdapter = new MyAdapter(MainActivity.this, arrayList);
expandbleLis.setAdapter(drawerLayoutAdapter);
expandbleLis.setOnChildClickListener(this);
}
private void setListner()
{
imgMenu.setOnClickListener(this);
// it is used to close all child view on expandable listview and show only one childview at a time.
expandbleLis.setOnGroupExpandListener(new ExpandableListView.OnGroupExpandListener() {
int previousGroup = -1;
#Override
public void onGroupExpand(int groupPosition) {
if(groupPosition != previousGroup)
expandbleLis.collapseGroup(previousGroup);
previousGroup = groupPosition;
}
});
}
private void loadArraylist()
{
arrayList = new ArrayList<MyModel>();
alTemp = new ArrayList<>();
//here we have pur zero position blank because on zero position we will be put profile picture layout.
arrayList.add(new MyModel("", 0, alTemp));
alTemp = new ArrayList<>();
alTemp.add("My Profile");
arrayList.add(new MyModel("Profile", R.drawable.profile, alTemp));
alTemp = new ArrayList<>();
alTemp.add("My Transaction");
arrayList.add(new MyModel("Transaction History", R.drawable.transaction, alTemp));
alTemp = new ArrayList<>();
alTemp.add("My Setting");
arrayList.add(new MyModel("Setting", R.drawable.setting, alTemp));
alTemp = new ArrayList<>();
alTemp.add("Logout");
arrayList.add(new MyModel("Log out", R.drawable.logout, alTemp));
}
private void slideMenu()
{
try
{
DrawerLayout.LayoutParams layoutParams = (DrawerLayout.LayoutParams) expandbleLis.getLayoutParams();
expandbleLis.setLayoutParams(layoutParams);
expandbleLis.setAdapter(drawerLayoutAdapter);
if (drawer_layout.isDrawerOpen(expandbleLis))
{
drawer_layout.closeDrawer(expandbleLis);
}
expandbleLis.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, final int pos, long id)
{
drawer_layout.setDrawerListener(new DrawerLayout.SimpleDrawerListener() {
#Override
public void onDrawerClosed(View drawerView)
{
super.onDrawerClosed(drawerView);
}
});
drawer_layout.closeDrawer(expandbleLis);
displayView(pos);
}
});
} catch (Exception e)
{
e.printStackTrace();
}
}
private void displayView(final int positionTitle)
{
try
{
closeDrawer();
new Handler().postDelayed(new Runnable() {
#Override
public void run()
{
switch (positionTitle)
{
case 0:
break;
case 1:
break;
case 2:
break;
}
}
}, 200);
} catch (Exception e)
{
e.printStackTrace();
}
}
private void setId()
{
try
{
drawer_layout = (DrawerLayout) findViewById(R.id.drawer_layout);
imgMenu = (ImageView) findViewById(R.id.imgMenu);
// below is for expandable listview.
expandbleLis = (ExpandableListView) findViewById(R.id.lvLeft);
expandbleLis.setDividerHeight(1);
expandbleLis.setGroupIndicator(null); // it is used to hide expandable list symbol.
expandbleLis.setClickable(true);
} catch (Exception e)
{
e.printStackTrace();
}
}
public void openDrawer()
{
try
{
expandbleLis.invalidateViews();
drawer_layout.openDrawer(expandbleLis);
} catch (Exception e)
{
e.printStackTrace();
}
}
private void closeDrawer()
{
try
{
if (drawer_layout.isDrawerOpen(expandbleLis))
{
drawer_layout.closeDrawer(expandbleLis);
}
} catch (Exception e)
{
e.printStackTrace();
}
}
#Override
public void onClick(View v)
{
switch (v.getId())
{
case R.id.imgMenu:
openDrawer();
break;
}
}
#Override
public boolean onChildClick(ExpandableListView parent, View v,
int groupPosition, int childPosition, long id)
{
Toast.makeText(MainActivity.this, "Clicked On Child",
Toast.LENGTH_SHORT).show();
return true;
}
}
Actually I want to implement custom Drawer layout in which status bar color should be custom as well as Drawer layout should be behind of status bar which will semi transparent. Here I have attach picture and I want to implement as same. I have try almost every solution but not get any proper result so please help me to solve such issue. Thanks in advance.
I think you are looking for ScrimInsetsFrameLayout.
Here is Custom ScrimInsetsFrameLayout class with which you can implement this kind of behaviour
ScrimInsetsFrameLayout.java
public class ScrimInsetsFrameLayout extends FrameLayout {
private Drawable mInsetForeground;
private Rect mInsets;
private Rect mTempRect = new Rect();
private OnInsetsCallback mOnInsetsCallback;
public ScrimInsetsFrameLayout(Context context) {
super(context);
init(context, null, 0);
}
public ScrimInsetsFrameLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs, 0);
}
public ScrimInsetsFrameLayout(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
init(context, attrs, defStyle);
}
private void init(Context context, AttributeSet attrs, int defStyle) {
final TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.ScrimInsetsView, defStyle, 0);
if (a == null) {
return;
}
mInsetForeground = a
.getDrawable(R.styleable.ScrimInsetsView_insetForeground1);
a.recycle();
setWillNotDraw(true);
}
#Override
protected boolean fitSystemWindows(Rect insets) {
mInsets = new Rect(insets);
setWillNotDraw(mInsetForeground == null);
ViewCompat.postInvalidateOnAnimation(this);
if (mOnInsetsCallback != null) {
mOnInsetsCallback.onInsetsChanged(insets);
}
return true; // consume insets
}
#Override
public void draw(Canvas canvas) {
super.draw(canvas);
int width = getWidth();
int height = getHeight();
if (mInsets != null && mInsetForeground != null) {
int sc = canvas.save();
canvas.translate(getScrollX(), getScrollY());
// Top
mTempRect.set(0, 0, width, mInsets.top);
mInsetForeground.setBounds(mTempRect);
mInsetForeground.draw(canvas);
// Bottom
mTempRect.set(0, height - mInsets.bottom, width, height);
mInsetForeground.setBounds(mTempRect);
mInsetForeground.draw(canvas);
// Left
mTempRect
.set(0, mInsets.top, mInsets.left, height - mInsets.bottom);
mInsetForeground.setBounds(mTempRect);
mInsetForeground.draw(canvas);
// Right
mTempRect.set(width - mInsets.right, mInsets.top, width, height
- mInsets.bottom);
mInsetForeground.setBounds(mTempRect);
mInsetForeground.draw(canvas);
canvas.restoreToCount(sc);
}
}
#Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (mInsetForeground != null) {
mInsetForeground.setCallback(this);
}
}
#Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (mInsetForeground != null) {
mInsetForeground.setCallback(null);
}
}
public void setOnInsetsCallback(OnInsetsCallback onInsetsCallback) {
mOnInsetsCallback = onInsetsCallback;
}
public static interface OnInsetsCallback {
public void onInsetsChanged(Rect insets);
}
}
Now Regarding Use of this class.
-> activity_main.xml
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true" >
<RelativeLayout
android:id="#+id/frame_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true" >
<include
android:id="#+id/toolbar_headers"
layout="#layout/toolbar_header"
android:visibility="invisible" />
</RelativeLayout>
<yourpackagename.ScrimInsetsFrameLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="start"
android:layout_marginRight="-8dp"
android:elevation="8dp"
android:fitsSystemWindows="true"
app:insetForeground1="#4000" >
<!-- this would be your custom drawer layout -->
<include
android:id="#+id/drawar_layout"
layout="#layout/drawar_layout" />
</bhagyagold.com.extraclasses.ScrimInsetsFrameLayout>
</android.support.v4.widget.DrawerLayout>
here impotent tag is android:fitsSystemWindows check this in all views carefully.
-> java part
finally open or close your drawer with this layout.
for e.g
mLayout = (ScrimInsetsFrameLayout) findViewById(R.id.container);
mDrawerLayout.closeDrawer(mLayout);
-> styles.xml
<style name="AppTheme" parent="Theme.AppCompat.Light">
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="colorPrimary">#color/colorPrimary</item>
<item name="colorPrimaryDark">#color/colorPrimaryDark</item>
<item name="colorAccent">colorPrimaryDark</item>
<item name="android:statusBarColor">#android:color/transparent</item>
<item name="android:windowContentTransitions">true</item>
<item name="android:windowAllowEnterTransitionOverlap">true</item>
<item name="android:windowAllowReturnTransitionOverlap">true</item>
<item name="android:windowSharedElementEnterTransition">#android:transition/move</item>
<item name="android:windowSharedElementExitTransition">#android:transition/move</item>
<item name="windowNoTitle">true</item>
</style>
EDIT :
-> attrs.xml
<resources>
<declare-styleable name="ScrimInsetsView">
<attr name="insetForeground1" format="reference|color" />
</declare-styleable>
</resources>
Happy coding..
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">#color/statusbar_color</item>
<item name="colorPrimaryDark">#color/statusbar_color</item>
<item name="colorAccent">#color/colorAccent</item>
</style>
Add that code in your style.XML and then apply in your manifiest in application tag set that theam like . ..
android:theme="#style/AppTheme"
I dont know to add more listview inside one page layout (attach picture)
I want Each ListView is not scrolling. Page layout is scrolling only.
Help me!!
Build same home layout app: https://play.google.com/store/apps/details?id=com.google.android.youtube
Answer
I had resolve this problem
Step1: Make new file java:
public class ExpandableHeightListview extends ListView {
boolean expanded = false;
public ExpandableHeightListview(Context context)
{
super(context);
}
public ExpandableHeightListview(Context context, AttributeSet attrs)
{
super(context, attrs);
}
public ExpandableHeightListview(Context context, AttributeSet attrs,int defStyle)
{
super(context, attrs, defStyle);
}
public boolean isExpanded()
{
return expanded;
}
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
// HACK! TAKE THAT ANDROID!
if (isExpanded())
{
// Calculate entire height by providing a very large height hint.
// But do not use the highest 2 bits of this integer; those are
// reserved for the MeasureSpec mode.
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
ViewGroup.LayoutParams params = getLayoutParams();
params.height = getMeasuredHeight();
}
else
{
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
public void setExpanded(boolean expanded)
{
this.expanded = expanded;
}
}
Step2: Java: Replace all ListView ->ExpandableHeightListview, and set listview.setExpanded(true);
Step3: layout xml: Replace
<yourpackage.ExpandableHeightListview
android:id="#+id/etResponse"
android:layout_width="match_parent"
android:layout_weight="1"
android:layout_height="300dp"
android:scrollbars="none"
android:orientation="vertical"
android:fadingEdge="none">
</yourpackage.ExpandableHeightListview>
Step4: Done!
You can calculate height of listview belong to number item in this. Here is example :
public class ExpandedListView extends ListView {
private android.view.ViewGroup.LayoutParams params;
private int old_count = 0;
public ExpandedListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onDraw(Canvas canvas) {
if (getCount() != old_count) {
old_count = getCount();
params = getLayoutParams();
if (getChildAt(0)!= null){
params.height = getCount() * (old_count > 0 ? (getChildAt(0).getHeight()) : 0) ;
}else
params.height = 0;
setLayoutParams(params);
requestLayout();
}
super.onDraw(canvas);
}
}
And use it in xml like this :
.......
<your package.ExpandedListView
android:id="#+id/lv1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="none" />
<your package.ExpandedListView
android:id="#+id/lv2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="none" />
....
Note This solution will fix the height of listView.
You need to set the height of each ListView. Lets say 30dp also give layout_weight="1" Here is example LinearLayout nested inside ScrollView
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ListView
android:id="#+id/lastest"
android:layout_marginTop="10sp"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="30dp" />
<ListView
android:id="#+id/featured"
android:layout_marginTop="10sp"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="30dp" />
<ListView
android:id="#+id/startup"
android:layout_marginTop="10sp"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="30dp" />
</LinearLayout>
</ScrollView>
Hope it helps
Please use custom Listview:
public class ExpandableHeightListview extends ListView
{
boolean expanded = false;
public ExpandableHeightListview(Context context)
{
super(context);
}
public ExpandableHeightListview(Context context, AttributeSet attrs)
{
super(context, attrs);
}
public ExpandableHeightListview(Context context, AttributeSet attrs,int defStyle)
{
super(context, attrs, defStyle);
}
public boolean isExpanded()
{
return expanded;
}
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
// HACK! TAKE THAT ANDROID!
if (isExpanded())
{
// Calculate entire height by providing a very large height hint.
// But do not use the highest 2 bits of this integer; those are
// reserved for the MeasureSpec mode.
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
ViewGroup.LayoutParams params = getLayoutParams();
params.height = getMeasuredHeight();
}
else
{
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
public void setExpanded(boolean expanded)
{
this.expanded = expanded;
}
}
in .xml file:
<yourpackagename.ExpandableHeightListview
android:id="#+id/listView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/White"
android:scrollbars="none"
android:orientation="vertical"
android:fadingEdge="none">
</cyourpackagename.ExpandableHeightListview>
I am using a custom shape for the custom gridview.
The grid view attribute :
<com.View.UI.ExpandableHeightGridView
android:id="#+id/issueList"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/archiveTitle"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:background="#drawable/customshape"
android:numColumns="3"
android:overScrollMode="never"
android:scrollbars="none"
android:isScrollContainer="false"
/>
the custom class extend gridview (which is use for increase the height when the element is add to the gridview)
public class ExpandableHeightGridView extends GridView{
boolean expanded = false;
public ExpandableHeightGridView(Context context)
{
super(context);
}
public ExpandableHeightGridView(Context context, AttributeSet attrs)
{
super(context, attrs);
}
public ExpandableHeightGridView(Context context, AttributeSet attrs,
int defStyle)
{
super(context, attrs, defStyle);
}
public boolean isExpanded()
{
return expanded;
}
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
if (isExpanded())
{
// Calculate entire height by providing a very large height hint.
// View.MEASURED_SIZE_MASK represents the largest height possible.
int expandSpec = MeasureSpec.makeMeasureSpec(MEASURED_SIZE_MASK,
MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
// ViewGroup.LayoutParams params = getLayoutParams();
// params.height = getMeasuredHeight();
}
else
{
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
public void setExpanded(boolean expanded)
{
this.expanded = expanded;
}
}
And the custom_shape.xml
<solid android:color="#FFF" />
<stroke
android:width="1dp"
android:color="#808080" />
<corners android:radius="10dp" />
It works on my phone (more new) but when it run on the old tablet it show Shape round rect too large to be rendered into a texture , it is a gridview than contain ~ 40 element so it may be tall.
How to fix it?
I made a custom Viewgroup which i need to use in my application, but i need to put it in a ScrollView. When the layout is made only with my custom ViewGroup everything works fine, but when I put it in a ScrollView i can't see anything.
My layout:
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/scrollView1"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<com.example.test.CustomLayout
android:id="#+id/layout"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</com.example.test.CustomLayout>
</ScrollView>
My viewgroup:
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
/* do something and call for each child
View v = getChildAt(i);
v.measure(wspec, hspec);
*/
setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// TODO Auto-generated method stub
//do something and call layout on every child
}
UPDATE:
My CustomLayout class
public class CustomLayout extends ViewGroup{
/*My params*/
public CustomLayout(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
public CustomLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// TODO Auto-generated method stub
//do something and call layout on every child
}
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
/* do something and call for each child
View v = getChildAt(i);
v.measure(wspec, hspec);
*/
setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}
}
UPDATE 2:
Sorry but I made some other tries and it looks like if I have the viewgroup in a scrollview on the onMeasure method i got heightMeasureSpec = 0, then if I put the viewgroup in any other layout, i got an integer. Maybe this would help?
I got it, I had to measure the Viewgroup myself, or else i got no height at all.
So:
int heightMeasured = 0;
/*for each child get height and
heightMeasured += childHeight;*/
//If I am in a scrollview i got heightmeasurespec == 0, so
if(heightMeasureSpec == 0){
heightMeasureSpec = MeasureSpec.makeMeasureSpec(heightMeasured, MeasureSpec.AT_MOST);
}
setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), getDefaultSize(this.getSuggestedMinimumHeight(), heightMeasureSpec));
Now for me it works.
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/scrollView1"
android:layout_width="match_parent"
android:layout_height="match_parent" >
try to change android:layout_height to match_parent
You're using wrap_content for the height:
<com.example.test.CustomLayout
android:id="#+id/layout"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
Which would resolve to 0px afaik as there is no content - try giving you're component a default minimum height
Check this would work perfect!
public class MaxHeightScrollView extends ScrollView {
public static int DEFAULT_MAX_HEIGHT = -1;
private int maxHeight = DEFAULT_MAX_HEIGHT;
public MaxHeightScrollView(Context context) {
super(context);
}
public MaxHeightScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.getTheme().obtainStyledAttributes(
attrs,
R.styleable.ScrollMaxHeight,
0, 0);
try {
setMaxHeight(a.getInt(R.styleable.ScrollMaxHeight_maxHeight, 0));
} finally {
a.recycle();
}
}
public MaxHeightScrollView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
try {
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
if (maxHeight != DEFAULT_MAX_HEIGHT
&& heightSize > maxHeight) {
heightSize = maxHeight;
heightMeasureSpec = MeasureSpec.makeMeasureSpec(heightSize, MeasureSpec.AT_MOST);
getLayoutParams().height = heightSize;
} else {
heightMeasureSpec = MeasureSpec.makeMeasureSpec(heightSize, MeasureSpec.AT_MOST);
setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec)
, getDefaultSize(this.getSuggestedMinimumHeight(), heightMeasureSpec));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
public void setMaxHeight(int maxHeight) {
this.maxHeight = maxHeight;
}
}
make attr.xml in values folder and add below code
<resources>
<declare-styleable name="ScrollMaxHeight">
<attr name="maxHeight" format="integer"/>
</declare-styleable>
</resources>
Use like this
<com.yourapppackage.customviews.MaxHeightScrollView
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="wrap_content"
app:maxHeight="200"
android:fadeScrollbars="false"
android:gravity="center_horizontal">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
...........
............
</LinearLayout>
</com.yourapppackage.customviews.MaxHeightScrollView>
You are also using this contructor below, right? Because this is the one get called when you create your view in xml.
public CustomLayout(Context context, AttributeSet attrs) {
super(context, attrs);
// Do your stuff
}
I'm trying to display 8 items inside a gridview. Sadly, the gridview height is always too little, so that it only shows the first row, and a little part of the second.
Setting android:layout_height="300dp" makes it work. wrap_content and fill_parent apparently not.
My grid view:
<GridView
android:id="#+id/myId"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:horizontalSpacing="2dp"
android:isScrollContainer="false"
android:numColumns="4"
android:stretchMode="columnWidth"
android:verticalSpacing="20dp" />
My items resource:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:minHeight="?android:attr/listPreferredItemHeight" >
<ImageView
android:id="#+id/appItemIcon"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:src="#android:drawable/ic_dialog_info"
android:scaleType="center" />
<TextView
android:id="#+id/appItemText"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="My long application name"
android:gravity="center_horizontal"
android:textAppearance="?android:attr/textAppearanceSmall" />
</LinearLayout>
The issue does not seem related to a lack of vertical space.
What can I do ?
After (too much) research, I stumbled on the excellent answer of Neil Traft.
Adapting his work for the GridView has been dead easy.
ExpandableHeightGridView.java:
package com.example;
public class ExpandableHeightGridView extends GridView
{
boolean expanded = false;
public ExpandableHeightGridView(Context context)
{
super(context);
}
public ExpandableHeightGridView(Context context, AttributeSet attrs)
{
super(context, attrs);
}
public ExpandableHeightGridView(Context context, AttributeSet attrs,
int defStyle)
{
super(context, attrs, defStyle);
}
public boolean isExpanded()
{
return expanded;
}
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
// HACK! TAKE THAT ANDROID!
if (isExpanded())
{
// Calculate entire height by providing a very large height hint.
// View.MEASURED_SIZE_MASK represents the largest height possible.
int expandSpec = MeasureSpec.makeMeasureSpec(MEASURED_SIZE_MASK,
MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
ViewGroup.LayoutParams params = getLayoutParams();
params.height = getMeasuredHeight();
}
else
{
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
public void setExpanded(boolean expanded)
{
this.expanded = expanded;
}
}
Include it in your layout like this:
<com.example.ExpandableHeightGridView
android:id="#+id/myId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:horizontalSpacing="2dp"
android:isScrollContainer="false"
android:numColumns="4"
android:stretchMode="columnWidth"
android:verticalSpacing="20dp" />
Lastly you just need to ask it to expand:
mAppsGrid = (ExpandableHeightGridView) findViewById(R.id.myId);
mAppsGrid.setExpanded(true);
After using the answer from #tacone and making sure it worked, I decided to try shorting down the code. This is my result. PS: It is the equivalent of having the boolean "expanded" in tacones answer always set to true.
public class StaticGridView extends GridView {
public StaticGridView(Context context) {
super(context);
}
public StaticGridView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public StaticGridView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(MEASURED_SIZE_MASK, MeasureSpec.AT_MOST));
getLayoutParams().height = getMeasuredHeight();
}
}
Another similar approach that worked for me, is to calculate the height for one row and then with static data (you may adapt it to paginate) you can calculate how many rows you have and resize the GridView height easily.
private void resizeGridView(GridView gridView, int items, int columns) {
ViewGroup.LayoutParams params = gridView.getLayoutParams();
int oneRowHeight = gridView.getHeight();
int rows = (int) (items / columns);
params.height = oneRowHeight * rows;
gridView.setLayoutParams(params);
}
Use this code after setting the adapter and when the GridView is drawn or you will get height = 0.
gridView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
if (!gridViewResized) {
gridViewResized = true;
resizeGridView(gridView, numItems, numColumns);
}
}
});
Found tacones answer helpfull... so i ported it to C# (Xamarin)
public class ExpandableHeightGridView: GridView
{
bool _isExpanded = false;
public ExpandableHeightGridView(Context context) : base(context)
{
}
public ExpandableHeightGridView(Context context, IAttributeSet attrs) : base(context, attrs)
{
}
public ExpandableHeightGridView(Context context, IAttributeSet attrs, int defStyle) : base(context, attrs, defStyle)
{
}
public bool IsExpanded
{
get { return _isExpanded; }
set { _isExpanded = value; }
}
protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
// HACK! TAKE THAT ANDROID!
if (IsExpanded)
{
// Calculate entire height by providing a very large height hint.
// View.MEASURED_SIZE_MASK represents the largest height possible.
int expandSpec = MeasureSpec.MakeMeasureSpec( View.MeasuredSizeMask, MeasureSpecMode.AtMost);
base.OnMeasure(widthMeasureSpec,expandSpec);
var layoutParameters = this.LayoutParameters;
layoutParameters.Height = this.MeasuredHeight;
}
else
{
base.OnMeasure(widthMeasureSpec,heightMeasureSpec);
}
}
}
Jacob R solution in Kotlin:
class ExpandableHeightGridView #JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : GridView(context, attrs, defStyleAttr) {
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
val expandSpec = MeasureSpec.makeMeasureSpec(MEASURED_SIZE_MASK,
MeasureSpec.AT_MOST)
super.onMeasure(widthMeasureSpec, expandSpec)
layoutParams.height = measuredHeight
}
}
After adding GridView to RecyclerView I got a full-size GridView (all rows are visible), as expected.
Just calculate the height for AT_MOST and set to on measure. Here GridView Scroll will not work so. Need to use Vertical Scroll View explicitly.
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int heightSpec;
if (getLayoutParams().height == LayoutParams.WRAP_CONTENT) {
heightSpec = MeasureSpec.makeMeasureSpec(
Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
}
else {
// Any other height should be respected as is.
heightSpec = heightMeasureSpec;
}
super.onMeasure(widthMeasureSpec, heightSpec);
}