Custom Detail Image View from Three20 - iphone

I am pretty new with Three20. I have followed ray wenderlich's nice introduction to three20 and the examples within the three20 framework. When I click on a thumbnail in a thumbnail view (subclass of TTThumbsViewController) to launch a Details view, a standard Details image view (deployed by TTPhotoViewController or its super class). I would like to use my own implementation of a Details View instead of the default. I put the following code when I initiated the subclass of TTThumbsViewController and TTThumbsViewControllerDelegate method:
- (id)initWithDelegate:(id<TTThumbsViewControllerDelegate>)delegate {
[super initWithDelegate:delegate];
return self;
}
- (void)thumbsViewController: (TTThumbsViewController*)controller
didSelectPhoto: (id<TTPhoto>)photo {
[navigationController.pushViewController:photoDetailViewController
animated:Yes];
}
But the default TTPhotoViewController view still prevail. When I put a NSLog in the delegate method. I coud see the method was called. I think there is another delegate someone already set in TTThumViewController? Can someone recommend a way to display my detail photo view? Is there another thumbs view controller I can use? Any suggestion will be greatly appreciated.

I'm really new to all of this (coding, etc.) but I'll share what I've found. By looking up the definition of ttthumbsviewcontroller, I was able to find the following method(wrong term?):-
- (void)thumbsTableViewCell:(TTThumbsTableViewCell*)cell didSelectPhoto:(id<TTPhoto>)photo {
[_delegate thumbsViewController:self didSelectPhoto:photo];
BOOL shouldNavigate = YES;
if ([_delegate respondsToSelector:#selector(thumbsViewController:shouldNavigateToPhoto:)]) {
shouldNavigate = [_delegate thumbsViewController:self shouldNavigateToPhoto:photo];
}
if (shouldNavigate) {
NSString* URL = [self URLForPhoto:photo];
if (URL) {
TTOpenURLFromView(URL, self.view);
} else {
TTPhotoViewController* controller = [self createPhotoViewController];
controller.centerPhoto = photo;
[self.navigationController pushViewController:controller animated:YES];
}
}
}
In the else statement, I've found this calls the creation of the photoviewcontroller. By recalling this method (?) in the actual body of my own code and changing the body in the else statement I was able to add a custom detail view. Further down the definition of the ttthumbsnailviewcontroller, you can find that the creatPhotoViewController calls for an initiation of the PhotoViewController so calling that method(?) in the body of the code and initializing another view also works.
If someone can explain whether or not this is a good method of doing this (I have a feeling that is not), it would be appreciated. Also why does putting the method in the body of the code override the call there.

Related

UIPickerView on Separate Page

I am working on an iPhone app. Initially, I had my pickerview in the same screen so this was just a one page app. After skinning it i realized that i want the pickerview on it's own separate page. So i did that. However, my pickerview originally would update uilabels and other objects on that same page. How can I have my pickerview access those objects from it's new view?
- (IBAction)ShowPickerAction:(id)sender {
if (self.theView == nil) {
theView = [containerView initWithNibName:#"containerView" bundle:nil];
theView.parentView = self;
}
self.theView.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentModalViewController:self.theView animated:YES];
}
That is the method I am using to call my new view. But line 3 of the above code gives me the error "No known class name for selector initWithNibName:bundle". I think that error is related to something that i did wrong in my header file. My new class is called containerView. So i did this in my header:
#interface ViewController : UIViewController {
containerView *theView;
But that gives me the error "Unknown type name containerView" even though i do have a class named containerView!!
Look into uiappdelegate protocol or try passing values to through a static function to the previous page.
Use a delegate to pass information back and forth to the view object that instantiatrd the picker view. You want to keep your code coupling as loose as possible, especially if you might like to drop it into your next project. Using a delegate and/or blocks are some of the best ways.

Adding a button to TTTable View Item

I have been banging my head on adding a button to a cell. This is what I have done.
I subclassed TTTableMessageItem and TTTableMessageItemCell.
I added the following method to the Message Item init :
+ (id)itemWithTitle:(NSString *)title caption:(NSString *)caption text:(NSString *)text timestamp:(NSDate *)timestamp imageURL:(NSString *)imageURL URL:(NSString *)URL target:(id)target action:(SEL)action;
I also added a SEL variable and "id" for action and target.
Under setObject in message Item Cell I added this :
- (void)setObject:(id)object {
if (_item != object) {
[super setObject:object];
TJTableMessageItem* item = object;
if (item.plusAction) {
self.plusAction = item.plusAction;
}
if (item.plusTarget) {
self.plusTarget = item.plusTarget;
}
}
}
I am now able to trigger easily a method inside my datasource for the tableview. But I am not able to find out which cell was pressed. I hope someone can help me, I have spent way to much time figuring out the setObject part.
I would like to know how and add a subview like the Facebook app has, the Like, Comment part. I think I need to be able to run a method inside the view controller. But I can't find anything anywhere. The Cybersam blog has an explanation that doesn't use the TableItem and TableItemCell like Three20 puts things up.
assume that the target is your TableViewController, and the the SEL has an argument named sender, like this:
- (void)likeButtonClicked:(id)sender;
then you can find the Cell View according to sender (sender.superView.....), and use the TableView to find the cell's index, that's all.

How to check if a UIView is a subview of a parent view

I have an app which I add a subview to (and remove the same subview based on user interactions). I am looking for a way to check whether the subview is present or not at any given time.
For example:
In the current view (UIView *viewA) I add a subview (UIView *viewB). I then want a way of checking whether viewB is being displayed at any given time.
Sorry if this isn't very clear, it's quite hard to describe.
an UIView stores its superview and is accessible with the superview-property just try
if([viewB superview]!=nil)
NSLog(#"visible");
else
NSLog(#"not visible");
But the better approach is to use the hidden-property of UIView
I went through the same issue and consulted Apple Documentation and came up with this elegant solution:
if([self.childView isDescendantOfView:self.parentView])
{
// The childView is contained in the parentView.
}
I updated to Swift4, Thanks a lot to #Shinnyx and #thomas.
if viewB.superview != nil{
print("visible")
}
else{
print("not visible")
}
if selfView.isDescendant(of: self.parentView) {
print("visible")
}
else{
print("not visible")
}
func isDescendant(of: UIView)
Returns a Boolean value indicating whether the receiver is a subview of a given view or identical to that view.
Here's a method I put in the appDelegate so that I can display the entire subview hierarchy from any point.
// useful debugging method - send it a view and it will log all subviews
// can be called from the debugger
- (void) viewAllSubviews:(UIView *) topView Indent:(NSString *) indent {
for (UIView * theView in [topView subviews]){
NSLog(#"%#%#", indent, theView);
if ([theView subviews] != nil)
[self viewAllSubviews:theView Indent: [NSString stringWithFormat:#"%# ",indent]];
}
}
call it with a string with one character and it will indent for you. (i.e. [appDelegate viewAllSubviews:self.view Indent:#" "];)
I find it useful to clear the debug pane first, then call this from the debugger, and copy it into a text editor like BBEdit that will show the indents.
You can call it using the mainWindow's view and see everything on your screen.

Multiple UIWebViews question

I'm really not good with these protocols, especially because this is really my first time using them. I have two UIWebViews in the same view: webView and webView2. How do I change this line of code to work for webView2?
-(void)webViewDidStartLoad:(UIWebView *)webView {
I tried changing "webView" to "webView2", but Xcode said that I had the same line twice, so obviously this won't work. What should I do? Thanks for your help!
Btw, I'm thinking I have to add an IF statement within here, but what should it be?
The delegate method passes in a parameter defining which web view it’s coming from for exactly this reason.
- (void)webViewDidStartLoad:(UIWebView *)theWebView
{
if(theWebView == webView)
{
// do something
} else if(theWebView == webView2)
{
// do something else
}
}
Well the same method will be called, but the ref of the webview is passed in,
So you can keep a reference to both your webviews in your delegate and say something like if(webview1==webview) which will evaluate to yes only if the webview ref passed in the delegate method is webview1 so you can figure out which webview is calling the delegate using the if statement
I think you want:
- (void)webViewDidStartLoad:(UIWebView *)webView; {
if(webView == webView1){
// use the first webview here.
}
if(webView == webView2){
// use the second webview here.
}
}
Hope that Helps!

understanding TTNavigator

following situation:
in a TTTableViewController i added some Cells with URLs.
they are opening a class with #"tt://photos" for example. this works quite fine.
the first thing is, i saw some urls in TT Examples like #"tt/photos/1". is it possible to fetch this "1" in my photos class and say, for example okay, please open picture one, ore is this only another URL that was declared in TTNavigatior to open a specific Class?
the other thing is: is it possible to forward an object to the linked class?
clicking a cell opens #"tt://photos" (the linked class in my TTNavigator)
working with normal tableviews i can overwrite my init method and send an object with my initialize method, is this also possible by clicking my TTItems?
thanks!
figured it out myself, for those who need it:
First (passing "subURLs" in your navigator map)
navigating to an URL with #"tt://photos/firstphoto" is possible, you can fetch the "firstphoto" like this:
//Prepare your Navigator Map like this
[map from:#"tt://photos/(initWithNumber:)" toViewController:[PhotoVC class]];
In your PhotoVC you can access this Number:
-(void) initWithNumber: (NSString*)number {
NSLog(#"%#",number);
}
calling your View Controller with this url would look:
PhotoVC* controller = [[PhotoVC alloc] initWithNumber:#"1"];
[navigationController pushViewController:controller animated:YES];
[controller release];
Second (passing objects in an TTTableViewController)
its a bit tricky, but you dont have to Subclass anything.
first, nil the URL in the TableItem
[TTTableLink itemWithText:#"TTTableLink" URL:nil]
in your TTTableViewController write down this method
- (void)didSelectObject:(id)object atIndexPath:(NSIndexPath*)indexPath {
TTURLAction *urlAction = [[[TTURLAction alloc] initWithURLPath:#"tt://photos"] autorelease];
urlAction.query = [NSDictionary dictionaryWithObject:#"firstphoto" forKey:#"photo"];
urlAction.animated = YES;
[[TTNavigator navigator] openURLAction:urlAction];
}
now in your your PhotoVC you need something like this
- (id)initWithNavigatorURL:(NSURL*)URL query:(NSDictionary*)query {
if (self = [super init]) {
NSLog(#"%#",query);
}
return self;
}
and you are done ;)
I was trying to implement choise's answer, learned a lot, and eventually had to get the callouts showing up and keep the implementation with many urls simple, so here's what i did.
Keep URL in the TableItem,
Use this code in the TTTableViewController subclass.
- (void)didSelectObject:(id)object atIndexPath:(NSIndexPath*)indexPath {
NSLog(#"Its url is %#", [object URL]);
TTURLAction *urlAction = [[[TTURLAction alloc] initWithURLPath:(NSString *)[object URL]] autorelease];
urlAction.query = [NSDictionary dictionaryWithObject:self.user forKey:#"user"];
urlAction.animated = YES;
[[TTNavigator navigator] openURLAction:urlAction];
}
- (BOOL)shouldOpenURL:(NSString*)URL {
return NO;
}
That "shouldOpenURL:" was discovered looking through TTTableViewController, I tried it out, and it worked. Now the table view is not opening a duplicate view, and there are callouts!
Thanks choise!
Although choice's answer works for multiple params when u are creating the TTURLAction in code it is not very useful when u want to embed links to view controllers in your TTStyledLabel.One solution to that is to use multiple params in a single string.
<a href='app://view2/param1=value1&param2=value2&...'>LabelName</a>
if you want the code to parse such urls and get the params please feel free to send me a message and I will send you my parser classes.
(or you can build your own with NSScanner!)
Also dont forget to escape the &s otherwise TTStyledLabel would not like it!
You don't need to run this on current version 1.0.6.2 for TTTableViewController. The "URL" option is working as expected. If it's not working for you, then your URL is broken or your are calling the wrong function on your ViewController. The function you have to call through URL must return an id (be a constructor for a ViewController) of a ViewController. Then it'll work as expected.
I'll changed the example form choise to be like TTNavigator expect it to be.
Add a mapping, which TTNavigator will use to navigate:
//Prepare your Navigator Map like this
[map from:#"tt://photos/(initWithNumber:)" toViewController:[PhotoVC class]];
Create a TTTableLink (or TTStyledText, or other) with an URL set, which should mach your map:
[TTTableLink itemWithText:#"TTTableLink" URL:#"tt://photos/1"]
Add this to your PhotoVC to be called by TTNavigator on the given URL
-(id) initWithNumber: (NSString*)number {
if (self = [super init]) {
self.title = #"Some Title";
NSLog(#"%#",number);
}
return self;
}
You don't need to overwrite the function didSelectObject, as the TTNavigator will call your ViewController through defined constructor function tt://photos/(initWithNumber:)