Reduce the padding of the HeadeCell in DataGrid and make the text displayed on more that on line


#1

Hi there,

Since I have a wide tabular data (more than 10 columns) and should fit in the ipad screen width (landscape mode) I have to reduce the width and font-size for each column … I tried to to that but the header title clipped and appended by … so Is there a way to Reduce the padding of the HeadeCell in DataGrid and make the text displayed on more that on line in order to gain extra space as much as possible.


#2

Hi Ssaeed. 

I’m a bit unclear on what you are asking here unfortunately. Do you think you could send us a screenshot? I can then do my best to try and help you out and help you achieve what you are looking for.

Regards,
Chris


#3

Hi Chris,

Thanks for your reply, The problem that I faced appears in this image

As you see the header title is trimmed and suffixed by ( … )

What I need is to make the text over 2 lines and reduce the left padding to gain extra space to let the entire text fits well inside the heade cell without any trimming.

Thanks & best regards,


#4

Hi Ssaeed,

If you add this category to your project somewhere, you can then change these different properties to achieve what you want. This is currently in our private API, but we will be exposing it in our next release.

@interface SDataGridHeaderCell (indent)
@property (nonatomic, assign) float leftIndentForTextView;
@property (nonatomic, assign) float rightIndentForTextView;
@property (nonatomic, assign) float topIndentForTextView;
@property (nonatomic, assign) float bottomIndentForTextView;
@end

This doesn’t allow for text on multiple lines however. If you do want text on multiple lines you’ll need to use a custom header cell. You can find out more about custom cells in the “CustomCell” sample project that is packaged with our downloads.

Regards,
Chris


#5

hi, Chris, the sample is for customizing a data cell, do you have example of customizing a header cell, we need multiple line for header, but don’t know which function we need to call to set the content.

Thanks


#6

I moved to Shinobi Grid… which has more flexibility


#7

Hey!

Multi-line header cells are not supported out of the box (at the time of writing, the latest version of grids is 2.0).

To get multi-line header cells you will need to subclass SDataGridHeaderCell. This subclass will have a UILabel set to allow multiple lines with the word wrapping line break mode.

SDataGridHeader cells have a UITextField property. This data grid will try to set the text of this text field to the column header, so we need to hide this text field and observe any changes in its ‘text’ property, allowing us to update our multi-line label. Below is an implementation of a multi-line header cell subclass:

@implementation SIGridHeaderCell {
    UILabel *_multiLineLabel;
}


- (id)initWithReuseIdentifier:(NSString *)identifier{
    self = [super initWithReuseIdentifier:identifier];
    if (self) {
        
        // Remove the default UITextField from our cell.
        [self.textField removeFromSuperview];
        
        // Set up our multi-line label.
        _multiLineLabel = [[UILabel alloc] init];
        [_multiLineLabel setNumberOfLines:0];
        [_multiLineLabel setLineBreakMode:NSLineBreakByWordWrapping];
        [self addSubview:_multiLineLabel];
        
        // Observe changes in default text field's 'text' property so we can update the multi-line label.
        [self.textField addObserver:self forKeyPath:@"text" options:NSKeyValueObservingOptionNew context:nil];
    }
    return self;
}


-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    
    // Update our multi-line label with the column header text that was just set on the default text field.
    _multiLineLabel.text = ((UITextField *)object).text;
}

- (void)layoutSubviews{
    [super layoutSubviews];    
    
    // Update our label's frame whenever the cell is resized or moved.
    _multiLineLabel.frame = CGRectInset([self bounds], 0, 0);
    
    // Update the label's styling as we know by this point the defualt label will have had its styling applied.
    _multiLineLabel.backgroundColor = self.textField.backgroundColor;
    _multiLineLabel.font = self.textField.font;
    _multiLineLabel.textColor = self.textField.textColor;
}

@end

If you know the height your header needs to be to accomodate your wrapping text and you are happy to hard code this height then you can just fix your grid’s defaultHeaderRowHeight like so:

// An example of setting the row height to a height of 50 points.
grid.defaultHeaderRowHeight = @50;

Otherwise, you’ll have to do a bit of work to calculate the largest possible height that a header should be. In order to calculate the size needed to accomodate the text in our header row, we need to make sure the font size is explicitly set on the header cells. (It doesn’t have to be the same for every header cell; it just needs to be set.)

If we are going to be calculating the size needed to accomodate the text in our header row, it stands to reason that we would have to explicitely set a font size. So you will need to assign a style object to your column, specifying at least a font size. Below is an example of create a cell style object with a specific font size, then setting this style object on a few column objects. You will want the following code where you set up your grid (probably your view controller):

// Create your header style however you like, here I have a font size of 40 (very large!)
SDataGridCellStyle *myHeaderStyle = [SDataGridCellStyle styleWithBackgroundColor:nil 
                                                                   withTextColor:nil 
                                                               withTextAlignment:nil 
                                                       withVerticalTextAlignment:nil
                                                                        withFont:[UIFont systemFontOfSize:40]];

// Set the style as the header cell style for your columns.
myColumn1.headerCellStyle = myHeaderStyle;
myColumn2.headerCellStyle = myHeaderStyle;
....

Now we just need to calculate the header height. Since your columns can have titles of varying length and different font sizes, the most flexible way to calculate the maximum height needed would be to loop around each of our column objects and calculate the largest height needed to render its title, storing the largest height calculated as we go along:

float largestTextHeight = 0.f;
for (SDataGridColumn *column in self.grid.columns) {
        
    // The column's title.
    NSString *colTitle = column.title;
    // The column's font.
    UIFont *colFont = column.headerCellStyle.font;
        
    // Here we use the create a size object that represents the area that the text cell can render in. 
    // Since we want to know the height of the text, we give it the biggest possible float so that our text can expand as much as it needs.
    CGSize sizeTextCanRenderIn = CGSizeMake([column.width floatValue], self.grid.frame.size.height);
        
    // Next we find out the height that the text needs to fit our column's width.
    float textHeightNeeded = [colTitle sizeWithFont:colFont constrainedToSize:sizeTextCanRenderIn].height;
        
    // If this height is larger than any other height we have calculated so far, store it.
    if (textHeightNeeded > largestTextHeight) {
        largestTextHeight = textHeightNeeded;
    }
}
 
// Set the grid's default header row height to the largest size we need.    
self.grid.defaultHeaderRowHeight = [NSNumber numberWithFloat:largestTextHeight];

This should give you multi-line headers that will be high enough to fit any text / font combination that you set on your columns when you initialised them!

Thanks,
Jan


#8

how should i solve this problem in xamarin.ios edition ?


#9

Hi,

Achieving this with the Xamarin.iOS bindings is very similar to the native version, however there are a couple of extra little steps to make the bindings happy.

First, you can create your custom Header Cell like so:

[Register ("MyHeaderCell")]
public class MyHeaderCell : SDataGridHeaderCell
{
	UILabel multiLineLabel;
	
	[Export ("initWithReuseIdentifier:")]
	public MyHeaderCell(string reuseId) : base (reuseId)
	{
		TextField.RemoveFromSuperview();

		AddSubview(multiLineLabel = new UILabel {
			Lines = 0,
			LineBreakMode = UILineBreakMode.WordWrap
		});

		TextField.AddObserver(this, new NSString("text"), NSKeyValueObservingOptions.New, IntPtr.Zero);
	}

	public override void ObserveValue (NSString keyPath, NSObject ofObject, NSDictionary change, IntPtr context)
	{
		multiLineLabel.Text = (ofObject as UITextField).Text;
	}

	public override void LayoutSubviews ()
	{
		base.LayoutSubviews ();
		
		multiLineLabel.Frame = Bounds;

		multiLineLabel.BackgroundColor = TextField.BackgroundColor;
		multiLineLabel.Font = TextField.Font;
		multiLineLabel.TextColor = TextField.TextColor;
	}
}

You will notice that this is almost identical to the native version, however I’ve highlighted two lines that are very important.

The first is the Register attribute, which will bind the C# class to the give name and expose it to the native code. The necessity of this will become clear in a minute.

The second is the Export attribute, which binds a method/property to a given Obj-C selector. In this case we are binding the initWithReuseIdentifier: selector to our object’s constructor, so that the object and be created from the native code.

Once we’ve created our custom implementation, you can create a column and tell it to use our new HeaderCell like so:

SDataGridColumn column = new SDataGridColumn ("This is a really long title", "test", new Class("SDataGridTextCell"), new Class("MyHeaderCell"));

You will notice here that we have to pass in Obj-C classes, so we create a new Obj-C class using the name we registered previously (Important: The name must be the string from the Register attribute, not the actual C# class name, if they differ!).

Hopefully this should be enough to get you on the right path. You can see the CreatingCustomCells Xamarin.iOS sample provided with your download for a complete example of creating custom cells which uses the same principles described here.

Hope this is of some help,

William


#10

thanks for your quick reply,i will try this. :sunglasses: