I'd like to add UIGestureRecognizer to UITableViewCell.
When I call panAction: in CustomCell class, it will work.
But I'd like to call the method in ViewController class, and in this case, it will not work.
How do I fix it to work panAction:?
- (void)viewDidLoad
{
_tableView = [[UITableView alloc]initWithFrame:self.view.frame];
_tableView.delegate = self;
_tableView.dataSource = self;
[_tableView registerClass:[CustomCell class] forCellReuseIdentifier:#"Cell"];
[self.view addSubview:_tableView];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *nibName = #"Cell";
CustomCell *cell = (CustomCell*)[tableView dequeueReusableCellWithIdentifier:nibName];
if (!cell) {
cell = (CustomCell*)[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nibName];
}
return cell;
}
- (void)setupGesture
{
UIPanGestureRecognizer* panRecognizer = [[UIPanGestureRecognizer alloc]initWithTarget:self action:#selector(panAction:)];
CustomCell* cell = (CustomCell*)[_tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
[cell addGestureRecognizer:panRecognizer];
}
- (void)panAction:(UIPanGestureRecognizer *)sender
{
CGPoint location = [sender translationInView:sender.view];
NSLog(#"%f", location);
[sender setTranslation:CGPointZero inView:sender.view];
}
In the code posted above, you don't call setupGesture. This way your cell won't pick up the gestures. Also, you should just add create and add panRecognizer to the cell in tableview:cellForRowAtIndexpath: like so:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *nibName = #"Cell";
CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:nibName];
UIPanGestureRecognizer* panRecognizer = [[UIPanGestureRecognizer alloc]initWithTarget:self action:#selector(panAction:)];
[cell addGestureRecognizer:panRecognizer];
return cell;
}
Related
I want to swipe cell on click a button . I am succesful on swiping a cell. But i want to swipe on button which is in cell. my code is
- (NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"SimpleCell";
SimpleCell *cell = (SimpleCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"SimpleCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
SimpleCell *cekks=[[SimpleCell alloc]init];
cekks.scrollButton.alpha =0.0;
NSString *titleString;
UIButton *sender = [[UIButton alloc]init];
//[sender setBackgroundImage:[UIImage imageNamed:#"swipe.png"] forState:UIControlStateNormal];
sender.tag = indexPath.row;
titleString =#"Send A Gift";
UITableViewRowAction *sendAGift = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleNormal title:titleString handler:^(UITableViewRowAction *action, NSIndexPath *indexPath){
// [self deleteMail:[NSArray arrayWithObject:indexPath]:YES];
}];
[sendAGift setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:#"swipe.png"]]];
return #[sendAGift];
}
I think your class SimpleCell should contain the UIButton, in order perform reusing correctly.
It will be simpler if you create a custom UITableViewCell that contains all the UI actions over the cell and operate them within the cell, not in the UITableView itself.
Let's see an example:
Here's the customCell.h file:
#interface customCell : UITableViewCell {
UIButton *buttonSwipe;
}
#end
Here's the customCell.h file:
#import "customCell.h"
#implementation customCell
- (instancetype) initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self commonInit];
}
return self;
}
- (instancetype) initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
[self commonInit];
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
[self commonInit];
}
return self;
}
- (void) commonInit {
buttonSwipe = [UIButton... // Initialize here your button
[buttonSwipe addTarget:self action:#selector(swipeCell:) forControlEvents:UIControlEventTouchUpInside];
}
- (void) swipeCell {
// Embed here the code that makes the effect of swipe the cell.
}
This is a fast-untested workaround with some predefined code, but I think it's a working example if you want to make your cells swipe with your own code.
But if you want a faster way, I recommend you to visit Chris Wendel and his SWTableViewCell on GitHub
You can call editActionsForRowAtIndexPath: method as
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:SELECTED_ROW_INDEX inSection:0];
[self tableView:self.tableView editActionsForRowAtIndexPath:indexPath];
try the below code
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
//swipe button allocation
UIButton *btn = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 30, 30)];
btn.tag = indexPath.row;
[cell.contentView addSubview:btn];
[btn addTarget:self action:#selector(buttonTouched:) forControlEvents:UIControlEventTouchUpInside];
cell.textLabel.text = [NSString stringWithFormat:#"%lu",indexPath.row];
return cell;
}
-(void)buttonTouched:(id)sender{
UIButton *btn = (UIButton *)sender;
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:btn.tag inSection:0];
[self tableView:self.tableView editActionsForRowAtIndexPath:indexPath];
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
// Return NO if you do not want the specified item to be editable.
return YES;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
[self.objects removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
} else if (editingStyle == UITableViewCellEditingStyleInsert) {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view.
}
}
-(NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath{
NSLog(#"edit");
// code
return nil;
}
I'm having trouble with creating my UITableViewCell since UITableViewCell : initWithFrame : reuseIdentifier is deprecated. Please stay with me, I've looked over other questions about this but couldn't find them helpful. So here is my function.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
MyCellObject *cell = (MyCellObject *)[tableView_ dequeueReusableCellWithIdentifier:#"cellid"];
if (cell == nil) {
cell = [[[ChatCell alloc] initWithFrame:CGRectZero reuseIdentifier:#"cellid"] autorelease];
}
return cell;
}
As I read from other questions, I tried:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
MyCellObject *cell = (MyCellObject *)[tableView_ dequeueReusableCellWithIdentifier:#"cellid"];
if (cell == nil) {
cell = [[[MyCellObject alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cellid"] autorelease];
}
return cell;
}
But my cell won't display its text then. I can tap the cell row and it becomes selects, but no visible text. Because my cell text is handled in my MyCellObject and not cell.textLabel.text, I need to init the cell with a frame (initWithFrame), but I also need to init it with an identifier (reuseIdentifier).
Thanks!
EDIT: I don't think MyCellObject as everything worked before the above function was deprecated. Here's part of MyCellObject and it is derived from UITableViewCell:
- (id)initWithFrame:(CGRect)frame reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithFrame:frame reuseIdentifier:reuseIdentifier];
if (self == nil) {
return nil;
}
tagLabel = [[UILabel alloc] initWithFrame:CGRectZero];
tagLabel.backgroundColor = [UIColor clearColor];
tagLabel.font = [UIFont systemFontOfSize:14];
tagLabel.lineBreakMode = UILineBreakModeWordWrap;
tagLabel.opaque = YES;
[self addSubview:tagLabel];
}
The reason I have it setup that was is so I can "micro manage" the text in it a little more.
1) You haven't set the cell title. So you won't see any text on the cell. Here you have used a UITableViewCell class. So you will need to add a label to the cell in the storyboard and set outlet to UITableViewCell in your case which is MyCellObject class. Then you will be able to set text to that label.
2) You can just use
MyCellObject *cell = (MyCellObject *)[tableView dequeueReusableCellWithIdentifier:#"cellid"];
Try this..
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
MyCellObject *cell = (MyCellObject *)[tableView dequeueReusableCellWithIdentifier:#"cellid"];
cell.myCustomLabel.text = #"Your text";
return cell;
}
Tutorial I am following: http://www.appcoda.com/ios-programming-tutorial-create-a-simple-table-view-app/
I have created a tableview with 16 cells. When I select a row, it will show checkmark on it.
But when I scroll the tableview, there is also a checkmark showing on another cell further down the list. This repeats for any cell selected.
#import "FlightChecklistViewController.h"
#interface FlightChecklistViewController ()
#end
#implementation FlightChecklistViewController
{
NSArray *tableData;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// Initialize table data
tableData = [NSArray arrayWithObjects:#"Egg Benedict", #"Mushroom Risotto", #"Full Breakfast", #"Hamburger", #"Ham and Egg Sandwich", #"Creme Brelee", #"White Chocolate Donut", #"Starbucks Coffee", #"Vegetable Curry", #"Instant Noodle with Egg", #"Noodle with BBQ Pork", #"Japanese Noodle with Pork", #"Green Tea", #"Thai Shrimp Cake", #"Angry Birds Cake", #"Ham and Cheese Panini", nil];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [tableData count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"SimpleTableItem";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
cell.textLabel.text = [tableData objectAtIndex:indexPath.row];
return cell;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UIAlertView *messageAlert = [[UIAlertView alloc]
initWithTitle:#"Row Selected" message:#"You've selected a row" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
// Display Alert Message
[messageAlert show];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
#end
Any suggestions?
You need to store the information about the rows indexpaths, that were selected, somehow.
And populate your cell according to it.
#import "ViewController.h"
#interface ViewController ()
#property (nonatomic, strong) NSMutableArray *selectedCells;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.selectedCells = [NSMutableArray array];
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 100;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *unifiedID = #"aCellID";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:unifiedID];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:unifiedID];
}
cell.textLabel.text = [NSString stringWithFormat:#"%u", indexPath.row];
//if the indexPath was found among the selected ones, set the checkmark on the cell
cell.accessoryType = ([self isRowSelectedOnTableView:tableView atIndexPath:indexPath]) ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;
return cell;
}
//if a row gets selected, toggle checkmark
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if([self isRowSelectedOnTableView:tableView atIndexPath:indexPath]){
[self.selectedCells removeObject:indexPath];
cell.accessoryType = UITableViewCellAccessoryNone;
} else {
[self.selectedCells addObject:indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
}
-(BOOL)isRowSelectedOnTableView:(UITableView *)tableView atIndexPath:(NSIndexPath *)indexPath
{
return ([self.selectedCells containsObject:indexPath]) ? YES : NO;
}
#end
you will find the complete example code on github
The problem is that cells are reused. So, if you add a checkmark accessory view to a cell further up it'll appear again when the cell is reused further down. You should save which ones are checkmarked in an array somewhere that correlates to the rows of the table when you add/remove a checkmark. Then, when you give the table view a new cell you can determine whether or not it needs a checkmark and set that up.
I had the same issue recently with one of my apps, and I fixed it by doing this:
#property (nonatomic, strong) NSArray *list;
- (void)viewDidLoad
{
[super viewDidLoad];
self.list = [[NSArray alloc] initWithObjects:#"foo", #"bar", nil];
}
- (NSString *)SettingsPlist
{
NSString *paths = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *PlistPath = [paths stringByAppendingPathComponent:#"Settings.plist"];
return PlistPath;
}
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section
{
return [[self list] count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *contentForThisRow = [[self list] objectAtIndex:[indexPath row]];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell"];
if(cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Cell"];
}
NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:[self SettingsPlist]];
NSString *row = [NSString stringWithFormat:#"%d",indexPath.row];
if([[dict objectForKey:row]isEqualToString:#"0"])
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
else
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
[[cell textLabel] setText:contentForThisRow];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSMutableDictionary *plist = [NSMutableDictionary dictionaryWithContentsOfFile:[self SettingsPlist]];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
NSString *row = [NSString stringWithFormat:#"%d",indexPath.row];
if(cell.accessoryType == UITableViewCellAccessoryNone)
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
NSString *on = #"1";
[plist setObject:on forKey:row];
[plist writeToFile:[self SettingsPlist] atomically:YES];
}
else if(cell.accessoryType == UITableViewCellAccessoryCheckmark)
{
cell.accessoryType = UITableViewCellAccessoryNone;
NSString *off = #"0";
[plist setObject:off forKey:row];
[plist writeToFile:[self SettingsPlist] atomically:YES];
}
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
I have an UITableViewCell and I add a subView to a label.
[cell addSubview:stateLabel];
I want to change the label when the user presses a cell.
[tableView indexPathForSelectedRow];
This gives me the pressed indexPath, but can anyone help me how to change the label at that position where the user pressed?
I think I just need a hint and then I can do the rest by myself...
For example, if the user presses cell 8, it changes the stateLabelsubview of cell 8.
This is what I've got so far:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"CellID";
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
stateLabel = [ [UILabel alloc ] initWithFrame:CGRectMake(240,0,100,44)];
stateLabel.textColor = [UIColor redColor];
stateLabel.backgroundColor = [UIColor clearColor];
stateLabel.font = [UIFont fontWithName:#"Arial Rounded MT Bold" size:(13.0)];
stateLabel.text = #"Not applied";
[cell addSubview:stateLabel];
}
cell.textLabel.text = [cheatNames objectAtIndex:indexPath.row];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSIndexPath *selectedRowPath = [tableView indexPathForSelectedRow];
}
Thanks!
you can implement something like this
in your cellForRowatIndexPath: Method before the return cell;
get the indexpath of the selected row for changing the label.
and use
if(indexpath == selected index)
{
// do ur code here
}
as soon as didSelectRow: is called reload the table
this will defintely work.
no reload required IMHO:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSIndexPath *selectedRowPath = [tableView indexPathForSelectedRow];
myString = #"Any Data";
[tableView reloadData];
UITableCellView *cell = [tableView cellAtIndexPath:indexPath];
cell.label.title = myString;
}
Define myString in the .h file as an NSString
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSIndexPath *selectedRowPath = [tableView indexPathForSelectedRow];
myString = #"Any Data";
[tableView reloadData];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"CellID";
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
stateLabel = [ [UILabel alloc ] initWithFrame:CGRectMake(240,0,100,44)];
stateLabel.textColor = [UIColor redColor];
stateLabel.backgroundColor = [UIColor clearColor];
stateLabel.font = [UIFont fontWithName:#"Arial Rounded MT Bold" size:(13.0)];
stateLabel.text = myString;
[cell addSubview:stateLabel];
}
cell.textLabel.text = [cheatNames objectAtIndex:indexPath.row];
return cell;
}
I have a TableView with various entries. Sometimes i need to scroll down, sometimes there are only a few entries, so everything is visible.
I want some settings and filters in my First Cell, but it should not be visible, only when the user scrolls down.
My Trys:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
float rowHeight = [self tableView:self.tableView heightForRowAtIndexPath:indexPath];
self.tableView.contentOffset = CGPointMake(0, rowHeight);
}
and
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTopanimated:NO];
}
Both did not work.
Any advice on my problem?
Are you looking for something like this?
[self.tableView setContentInset:UIEdgeInsetsMake(t,l,b,r)];
this will shift your tableView whatever way you want, but you can definitely scroll back.
Try your logic in the TableView Delegate methods
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
if (indexPath.row == 0) {
//Your filters here
}
else {
//display the cell
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
Also if you dont wish the first cell to be displayed just write
return nil; //for condition of indexpath.row == 0
And also adjust the height for the row in
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
if (section == 0 && isDisplayThisSection) {//first visible
UIView *headerView = [[[UIView alloc] initWithFrame:CGRectMake(0, 5, 320, 25)] autorelease];
UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(17, 10, 300, 25)];
[titleLabel setFont:[UIFont boldSystemFontOfSize:17.0]];
titleLabel.text = #"Temp Test";
[titleLabel setBackgroundColor:[UIColor clearColor]];
[headerView addSubview:titleLabel];
[titleLabel release];
[headerView setBackgroundColor:[UIColor clearColor]];
return headerView;
}
return [[[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, 0)] autorelease];
}
set value to 0
Hope this help!!
Try your logic in the TableView Delegate methods
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
if (indexPath.row == 0) {
//Your filters here
}
else {
//display the cell
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
Also if you dont wish the first cell to be displayed just write
return ; //for condition of indexpath.row == 0
And also adjust the height for the row in
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
set value to 0
And if you wish to implement like Pull_to_Refresh, you would better write your logic in
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section;
Hope this help!!