你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發基礎 >> Xcode插件: MMNavigatorFont

Xcode插件: MMNavigatorFont

編輯:IOS開發基礎

作者:裡脊串 授權本站轉載。

前言

上周聽了@makezl的插件開發直播介紹之後 萌生了寫個插件的想法 目的就是為了解決一直以來讓我很糾結的一個東西

Xcode的文件管理窗口的字體不等寬的問題

也就是這個東西

字體不等寬很難受有木有? 以前嘗試過用TinkerTool 但是問題多多

趁著這周有時間 所以花了點時間做了個插件MMNavigatorFont來解決這個問題

插件效果大概是這個樣子

1.gif

如何開發插件 這裡就不介紹了 喵神的入門文章已經很好了

下面介紹一下開發過程中遇到的幾個問題以及解決辦法

問題

問題1 如何找到需要修改的對象

blob.png

如圖 很明顯我是要修改圖中每一個控件的字體 但是我如何找到它呢?

首先想到的是監控所有的NSNotification 找出需要的通知

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(allNotitication:)
                                             name:nil
                                           object:nil];

但是找了半天 都沒找到 這時候我想 要是有一款跟Reveal功能類似 可以查看OS X上的App結構的工具就好了 不過沒找到(有知道的朋友可以推薦一下)

這時我想起了chisel 除了調試iOS的應用 也可以調試OS X的應用 試了一下 果然可以

blob.png

獲取pviews命令打印出來的結構文本 搜索對應的關鍵字 就能找到我所需的view class了 這裡我需要的就是這個DVTTableCellViewOneLine 再根據Xcode的頭文件就可以知道 DVTTableCellViewOneLine是基於DVTTableCellView的 而DVTTableCellView中有如下兩個成員

@interface DVTTableCellView : NSTableCellView
{
    ...
    ...
    DVTTableCellViewTextField *_titleTextField;
    DVTTableCellViewTextField *_subtitleTextField;
    ...
    ...
}

這就是我們需要修改字體的NSTextFiled

問題2 如何選擇字體

因為不熟悉Cocoa 所以我也在網上一番搜索以及請教了@劍指人心以後 得到了如下的代碼

- (void)actionChoose
{
    [[NSFontManager sharedFontManager] setDelegate:self];
    [[NSFontManager sharedFontManager] setTarget:self];
    [[NSFontManager sharedFontManager] orderFrontFontPanel:nil];
}
- (void)changeFont:(id)sender 
{
    self.selectedFont = [sender convertFont:self.selectedFont];
}

但是運行以後卻有問題 字體選擇框是彈出來了 但是始終獲取不到選擇的字體 而且changeFont中的sender(即[NSFontManager sharedFontManager])不為nil

經過一番嘗試之後發現 必須為NSFontManager指定一個初始字體才可以

[[NSFontManager sharedFontManager] setSelectedFont:self.selectedFont?:[NSFont systemFontOfSize:13] isMultiple:NO];

不過這裡我仍有一個疑問

在10.11中 NSFontManager的delegate已經被聲明為deprecated了 但是我查了官方文檔 也沒有找到替代的東西 是否有同學知道如何在10.11中正確的使用NSFontManager呢 :)

blob.png

問題3 如何設置勾子

在cocoa中掛勾子肯定也是要用到Runtime的 這裡我學習BBUFullIssueNavigator直接使用Aspects來hook

Aspects使用起來很簡單 比如我在嘗試了幾次之後 發現在DVTTableCellViewOneLine的awakeFromNib方法執行之後對字體進行替換是最好的 那麼只需要這樣寫即可

[objc_getClass("DVTTableCellViewOneLine") aspect_hookSelector:@selector(awakeFromNib)
                                                  withOptions:AspectPositionAfter
                                                   usingBlock:fontBlock
                                                        error:nil];

問題4 如何立即預覽修改字體的效果

因為鉤子是掛在awakeFromNib上的 所以當初始化完成之後 便無法再修改字體了 所以當字體發生變化的時候 需要遍歷所有的DVTTableCellViewOneLine並修改其中的字體

這倒不是難事 關鍵在於如何保存包含這些DVTTableCellViewOneLine的容器 不然每次都要遍歷整個Xcode的窗口 效率也未免太低了

經過對結構的觀察 發現IDENavigatorOutlineView是比較合適保存的 但是IDENavigatorOutlineView會因為切換而重新生成 不能保存強引用 所以這裡我定義了一個weak的NSView來保存它

@property (nonatomic, weak)   NSView *outlineView;

並且在viewDidMoveToSuperview中hook住

[objc_getClass("IDENavigatorOutlineView") aspect_hookSelector:@selector(viewDidMoveToSuperview)
                                                  withOptions:AspectPositionAfter
                                                   usingBlock:controlBarBlock
                                                        error:nil];

這樣 在修改了字體之後 只要遞歸遍歷其subviews並修改對應字體就好了

- (void)refreshFont
{
    if ( self.outlineView )
    {
        [self refreshFontInView:self.outlineView];
    }
}
- (void)refreshFontInView:(NSView*)view
{
    for ( NSView *v in view.subviews )
    {
        [self refreshFontInView:v];
    }
    
    if ( [view isKindOfClass:NSClassFromString(@"DVTTableCellViewOneLine")] )
    {
        [self applyFont:view];
    }
}

問題5 如何還原默認字體

為了怕用戶不喜歡修改過的字體 所以我設置了一個啟用狀態 當用戶禁用的時候 會將所有字體還原成默認字體 這裡就需要記錄一下默認字體 很簡單 我用Category為NSView添加了兩個property

@interface NSView (MMNavigatorFont)
@property (nonatomic, strong) NSFont *originalTitleFont;
@property (nonatomic, strong) NSFont *originalSubtitleFont;
@end

然後在的hook函數中記錄一下默認字體即可

NSView *view = info.instance;
if ( !view.originalTitleFont )
{
    NSTextField *titleTextFiled = [view valueForKey:@"_titleTextField"];
    NSTextField *subtitleTextFiled = [view valueForKey:@"_subtitleTextField"];
    
    view.originalTitleFont = titleTextFiled.font;
    view.originalSubtitleFont = subtitleTextFiled.font;
}

好了 至此一個功能完整的插件就完成了 如果你感興趣 趕緊用一下吧 現在用alcatraz可以搜索得到了

blob.png

小結

一個功能簡單的Xcode插件就這麼誕生了 歷時一天半的樣子 雖然整個過程中也都是在摸石頭過河 不過因為cocoa和cocoa touch開發起來確實有很多相似的地方 所以開發起來也不是非常的困難(也是因為功能簡單的原因啦) 以後可能還會根據我自己的需求來開發更多的插件 XD

有同學說能不能改變Xcode的顏色 比如像我用的主題Monokai一樣弄個暗色的主題 其實你完全可以自己開發一個插件來做這個事情 說不定還會火哦~


  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved