Quantcast
Channel: 天狐博客
Viewing all 115 articles
Browse latest View live

iOS开发之TextField钱以及小数点的实时限制输入

$
0
0

钱的限制输入条件

1.可以输入小数点后N位

2.第一位是0,第二位不能是0

3.不能以.开始

方法一

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString*)string
{
    NSCharacterSet *characterSet;
    NSUInteger dotLocation = [textField.text rangeOfString:@"."].location;
    
    if ([textField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]].length == 0 && [string isEqualToString:@"."]) {
        textField.text = @"0.";
        return NO;
    }
    if (dotLocation == NSNotFound && range.location != 0) {
        NSMutableCharacterSet *mutableCharacterSet = [NSMutableCharacterSet decimalDigitCharacterSet];
        [mutableCharacterSet addCharactersInString:@"."];
        characterSet = [mutableCharacterSet invertedSet];
    }else {
        characterSet = [[NSCharacterSet decimalDigitCharacterSet] invertedSet];
    }
    
    NSString *filtered = [[string componentsSeparatedByCharactersInSet:characterSet] componentsJoinedByString:@""];
    
    BOOL basicTest = [string isEqualToString:filtered];
    
    if(!basicTest) {
        return NO;
    }
    if (dotLocation != NSNotFound && range.location > dotLocation + 2) {
        return NO;
    }
    return YES;
}

方法二

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString*)string
{
   
  NSMutableString * futureString = [NSMutableString stringWithString:textField.text];
  [futureString insertString:string atIndex:range.location];
   
  NSInteger flag=0;
  const NSInteger limited = 1;
  for (int i = futureString.length-1; i>=0; i--) {

    if([futureString characterAtIndex:i] == '.') {
       
      if (flag > limited) {
        return NO;
      }
       
      break;
    }
    flag++;
  }
   
   return YES;
}

方法三

代码忘了在哪看见的了,之前随手收藏的,提供一个思路吧,observeMoney是UITextFiled category中的一个方法

- (void)observeMoney {
    if (!self.isMoney) {
        return;
    }
    NSString *allText = self.text;
    NSString *newText= allText;
    if (self.correctText) {
        NSRange oldTextRange = [allText rangeOfString:self.correctText];
        newText = [allText substringFromIndex:oldTextRange.length];
    }
    
    NSCharacterSet *set = [[NSCharacterSet characterSetWithCharactersInString:@"0123456789."]invertedSet];
    NSString *filtered = [[newText componentsSeparatedByCharactersInSet:set] componentsJoinedByString:@""];
    if (filtered.length == 0) {
        if ([newText isEqualToString:@""]) {//inputed backSpace
            self.correctText = newText;
        }
        self.text = self.correctText;
        return;
    }
    if ([self.correctText rangeOfString:@"."].length) {
        if ([newText isEqualToString:@"."]) {//only one '.'
            self.text = self.correctText;
            return;
        }
        //2 charactors limited after '.'
        NSArray *array =  [self.correctText componentsSeparatedByString:@"."];
        if (array.count == 2) {
            if ([array[1] length] >= 2) {
                NSArray *newStringArray = [newText componentsSeparatedByString:@"."];
                if (newStringArray.count == 2 && [newStringArray[1] length] == 1) {//inputed backSpace
                    self.correctText= newText;
                }
                self.text = self.correctText;
                return;
            }
        }
        
    } else if (self.correctText.length == 1) {
        if ([newText isEqualToString:@"0"] && [self.correctText isEqualToString:@"0"]) {
            self.text = self.correctText;
            return;
        }
    }
    if (self.correctText.length == 0 && [newText isEqualToString:@"."]) {//"."->"0."
        self.text
        = self.correctText
        = @"0.";
        return;
    }
    if (self.correctText.length == 1 && [self.correctText isEqualToString:@"0"]) {
        if (![newText isEqualToString:@"."] && [newText intValue] > 0) {//'0'->other numbers
            self.text
            = self.correctText
            = newText;
            return;
        }
    }
    self.correctText = allText;
}

 

转载请注明:天狐博客 » iOS开发之TextField钱以及小数点的实时限制输入


Cocoa开发之Cell Based NSTableView中使用NSPopUpButtonCell

$
0
0

Cell Basedd的NSTableView中使用NSPopUpButtonCell,本人示例是动态设置的数据源。然后根据网络来的数据显示选中项。

这个东西坑的确很多,试了好多次才成功,而且没有官方文档。

//绑定数据源
-(id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row{
    NSString *identifier = [tableColumn identifier];
 
    NSDictionary *domainDic = [_records jk_objectWithIndex:row];
    
    if([identifier isEqualToString:@"type"]){
        //设置新数据
        NSPopUpButtonCell *popCell = [tableColumn dataCellForRow:row];
        [popCell removeAllItems];
        for(int i=0;i<= [_types count];i++){
            [popCell addItemWithTitle:[_types jk_objectWithIndex:i]?:@""];
        }
        //[popCell selectItemWithTitle:[domainDic jk_stringForKey:@"type"]];
        //NSPopUpButtonCell 要返回index,带入默认选中项
        return [NSNumber numberWithInteger:[popCell indexOfItemWithTitle:[domainDic jk_stringForKey:@"type"]]];
        
    }
    return nil;
}
//更改显示数据
- (void)tableView:(NSTableView *)tableView setObjectValue:(nullable id)object forTableColumn:(nullable NSTableColumn *)tableColumn row:(NSInteger)row{
    NSMutableDictionary *domainDic = [[_records jk_objectWithIndex:row] mutableCopy];
    NSString *identifier = [tableColumn identifier];
    
    if([identifier isEqualToString:@"type"]){
       //注意object为选中的index
        NSPopUpButtonCell *popCell = [tableColumn dataCellForRow:row];
        NSMenuItem *menuItem = [popCell itemAtIndex:[object integerValue]];
        NSLog(@"%@", [menuItem title]); //DEBUG
        [domainDic setObject:[menuItem title] forKey:@"type"];
    }
    [_records replaceObjectAtIndex:row withObject:domainDic];
    
}

 

转载请注明:天狐博客 » Cocoa开发之Cell Based NSTableView中使用NSPopUpButtonCell

做头条号自媒体与个人站长的感悟

$
0
0

之前自己是个人站长,转到今日头条等自媒体的感悟。

个人站长

需要些技术

发文不违法就行了

发送后立即生效

广告收益归自己所有

自己管理服务器

担心流量问题,只能靠分享或者seo来提高排名继而提高流量

看搜索引擎脸色

头条

没多少技术含量

发文要严格受头条限制

所谓机器算法,其实就是个鸡肋,发布个科技文章还能识别成游戏分类去,我也是呵呵了。

每次发布都要审核,所谓新闻讲究的就是时效性,时间稍长些就可能被别人抢先发表。

“别人”有可能是大V,名人。他们的权重高。审核快。

广告收益并不是和流量成正比

不用担心服务器问题

推荐成功不用太担心浏览量问题

看头条脸色,而且遇到问题只能通过网页上提问,还不是即时的,费劲

就这篇文章我准备发布头条的时候,还提示“您发表的内容不适合收录”,呵呵了。。。。

总结

其实任何平台都会在发展阶段跪舔用户,什么都没限制,什么都没多少要求。使用各种诱惑吸引用户。

当平台做的越来越大的时候,用户体量变大的时候,平台就是爹了,平台说什么就是什么,根本没有用户发言权。你投诉都无门。或者反映也是官方统一话术。

而如果类似平台越来越多,为了留住用户,诱惑福利也会变多。如果突然有一天变成垄断平台,想想会很可怕。任人宰割。想玩就苟活,不想玩就没得做。之前的努力都付之东流。

为什么没多少人有自己的独立APP而转向小程序呢,原因很大部分就是各种各样的限制。自己能做一个APP为什么要寄人篱下呢。

这种例子比比皆是,比如滴滴打车,外卖等互联网平台。

 

转载请注明:天狐博客 » 做头条号自媒体与个人站长的感悟

iOS11及Xcode9适配问题汇总

$
0
0

WWDC马上要到来了,不出意外苹果会发布会iOS11Beta版本,与Xcode9beta版本。

iOS11可能需要适配的功能

  • 「DarkMode」暗黑模式
  • iPhone支持分屏
  • 备忘录拖拽
  • 设置默认应用
  • 32bit应用程序彻底被淘汰
  • 新快捷方式
  • 单手模式
  • 画中画视屏小窗口

Xcode9可能需要适配的地方

。。。

尽请期待!

转载请注明:天狐博客 » iOS11及Xcode9适配问题汇总

Xcode 9新特性

$
0
0

Xcode8的改动可以说是重磅,期待Xcode9的新功能。

期待大刀阔斧的改动,不要缝缝补补。

Xcode 9新特性

Xcode 9新特性

Xcode 9新特性

Xcode 9新特性

Xcode 9新特性

Xcode 9新特性

Xcode 9新特性

Xcode 9新特性

Xcode 9新特性

转载请注明:天狐博客 » Xcode 9新特性

iPhone 8屏幕分辨率与适配

$
0
0

iPhone 8屏幕分辨率与适配,iOS开发适配与UI设计问题

“iPhone 8” 5.8 英寸,屏幕分辨率为 1242 x 2800

除去底部固定的功能区,屏幕显示范围的尺寸为 5.15 英寸,分辨率为 1125 x 2436。

iPhone 7 设备渲染后分辨率为 750 x 1334,逻辑分辨率只有 375 x 667。

iPhone 8 设备渲染后分辨率为 1125 x 2436,逻辑分辨率是为 375 x 812。

这就意味着,除去下巴的功能区,iPhone8与7同宽,但是高度多了一截。

就是多了这一截,这一截,在UI设计方面与iOS开发适配方面都会出现或多或少的问题。

。。。。。。。。。。。。。。。。。。适配稍后更新。

此贴必火!

转载请注明:天狐博客 » iPhone 8屏幕分辨率与适配

通过Safari浏览器获取iOS设备IEME(设备串码)

$
0
0

通过Safari浏览器获取iOS设备真实IEME(设备串码)

之前写过一篇文章是获取设备真实UDID的 链接 : 通过Safari浏览器获取iOS设备UDID(设备唯一标识符)

获取设备IEME和UDID方法其实是一样的,就是到最后一步解析数据的时候解析IEME即可。

<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
      <dict>
        <key>IMEI</key>
        <string>12 123456 123456 7</string>
        <key>PRODUCT</key>
        <string>iPhone8,1</string>
        <key>UDID</key>
        <string>b59769e6c28b73b1195009d4b21cXXXXXXXXXXXX</string>
        <key>VERSION</key>
        <string>15B206</string>
      </dict>
    </plist>

参考链接

通过Safari浏览器获取iOS设备UDID(设备唯一标识符)

转载请注明:天狐博客 » 通过Safari浏览器获取iOS设备IEME(设备串码)

Distributing Apple Developer Enterprise Program Apps


Cocoa开发之NSTabView

$
0
0

NSTabView,即选项卡视图组件,属于APPKit.framework,NSTabViewController中也是包含一个NSTabView来实现的ViewController,NSTabView包含N个选项卡(NSTabViewItem)与多个页面,通过每点击一个选项卡(NSTabViewItem)对应一个页面view,每一个页面view也可以关联一个其他Controlller的view。

XIB中直接使用

首先在主界面XIB中拖拽进来一个NSTabView控件,设置好tab数量及标题

因为在xib中不能存在多个Viewcontroller,想关联ViewController要代码关联。如果是Storyboard使用NSTabViewController直接拖拽关联ViewController。

接着为每一个NSTabViewItem创建独立的ViewController和XIB(注意ViewController需继承自NSViewController类型)

最后需要把界面上的TabViewItem关联到ViewController的view上。

@interface AppDelegate ()
@property (weak) IBOutlet NSWindow *window;
@property (weak) IBOutlet NSTabView *tabView;
@property (nonatomic, strong) OneViewController *oneViewController;
@property (nonatomic, strong) TwoViewController *twoViewController;
@end

@implementation AppDelegate

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
    // Insert code here to initialize your application
    NSTabViewItem *tabViewItem1 = [self.tabView.tabViewItems objectAtIndex:0];
    self.oneViewController = [[OneViewController alloc] initWithNibName:@"OneViewController" bundle:nil];
    [tabViewItem1 setView:self.oneViewController.view];
    
    NSTabViewItem *tabViewItem2 = [self.tabView.tabViewItems objectAtIndex:1];
    self.twoViewController = [[TwoViewController alloc] initWithNibName:@"TwoViewController" bundle:nil];
    [tabViewItem2 setView:self.twoViewController.view];

代码创建

当然也可以用代码来创建(通过NSTabView的addTabViewItem来手动加入NSTabViewItem对象)

NSTabViewItem *detailItem = [[NSTabViewItem alloc]init];
detailItem.view = xxview;
[self.tabView addTabViewItem:detailItem];

自定义样式

TabView有几个样式供大家选择

Top Tabs:标签在顶部

Left Tabs:标签在左策

Bottom Tabs:标签在底部

Right Tabs:标签在右侧

Tabless:不显示标签

Tabless with Bezel:不显示标签,view圆角

Tabless with line,不显示标签,显示一条分割线。

自定义TabViewItem与背景

如下图,TabView无边框与背景并且正常显示选项卡。

这种效果其实很简单。把TabView的样式设置为,Tabless:不显示标签。然后在TabView的相应位置增加一个NSSegmentedControl视图。NSSegmentedControl设置下具体多少个选项卡,和相应事件即可。

- (IBAction)segmentControlClicked:(id)segmentControl{
    NSInteger index = [segmentControl selectedSegment];
    [self.tabView selectTabViewItemAtIndex:index];
}

官方文档

https://developer.apple.com/documentation/appkit/nstabview

转载请注明:天狐博客 » Cocoa开发之NSTabView

iOS开发之为App设置正确的设计颜色

$
0
0

你有没有遇到过以下问题:

  • 设计师给你的颜色值在Interface Builder中设置以及代码设置与真机与模拟器显示的颜色不一致,甚至肉眼完全看的出来。
  • 为一个普通的控件设置Color,设置了颜色为XXXXXX。取色工具测的也是正常的XXXXXX,但是模拟器/真机运行起来之后,颜色变色了,用取色工具测,颜色变成了YYYYYY。
  • 为什么当我用颜色吸管工具在Photoshop选择一个颜色的和RGB值,在Xcode中设置后得不到相同的颜色?
  • 为什么真机或者模拟器截图后,用吸管取色后得到的值与Interface Builder中设置的颜色值不一样?
  • 太恶心了,就一个颜色为什么不一样?
  • 我做错了什么吗?

看完这篇文章后,这些问题将会全部消失。

color space

色彩空间,色域。我不会在这里详细介绍, 进一步了解可以阅读: http://www.dpbestflow.org/color/color-space-and-color-profiles  在那里, 你可以找到关于色彩模型, 色彩空间和色彩配置的定义, 以获得更深的理解。我也会稍后再博客中翻译整篇文章。

color profile

色彩配置。我不会在这里详细介绍, 进一步了解可以阅读: http://www.dpbestflow.org/color/color-space-and-color-profiles  在那里, 你可以找到关于色彩模型, 色彩空间和色彩配置的定义, 以获得更深的理解。我也会稍后再博客中翻译整篇文章。

理解苹果的颜色处理

苹果认为相同的RGB值在任何地方都应该显示相同。其实应用一个RGB的组合在不同的设备上不会总是有着相同的颜色,这取决于你使用的是哪一个颜色配置(color profile)。

需要知道是,color profile是展现一个色彩空间中颜色的数值模型(色彩空间,色域(color space)是展现颜色的一个方式, 例如: RGB, CMYK, HSV, 等等),一些色彩配置(color profile)是“设备相关”的,一些色彩配置(color profile)是“设备无关”的。这意味着同样的颜色在不同的设备(“设备无关”)上会展现相同的颜色,其中一些将会根据设备的特点改变颜色(“设备相关”)

同样有趣的是, 当你截图时, 不仅每个像素的 RGB 值都得到了存储, 而且还有关于被截取的设备的互补信息。这样, 苹果可以通过计算不同的 RGB 组合来使颜色在不同的设备中看起来相同, 以最佳的方式使这些颜色与设备的特性和限制相匹配。

说了这么多, 给定一个色彩空间(color space) (例如, RGB), 您将在其中有多个色彩配置 (一般 RGB、Adobe RGB、PAL/SECAM等), 因此你将有多种方法使用不同的 RGB 组合来获得相同的颜色。

Xcode 中的 RGB 色彩配置(color profile)有 Adobe RGB、Apple RGB、Device RGB(设备RGB)、Generic RGB(通用RGB)、Wide Gamut RGB(广域 RGB)。要查看整个色彩配置列表, 可以从 Xcode 的Interface Builder的色彩选择工具中查看。

因此, 当您选择选择了 RGB 值组合,并更改了要使用的色彩配置时, 您将获得相同的颜色,但是会得出不同的RGB值,这是应用颜色时使开发人员非常恼火的主要问题。

例如, 通用RGB (10、80、105) 和设备RGB (0、99、124) 是相同的颜色,但有不同的 RGB 值。如你所见。这就是为什么最终可以有不同的颜色, 即使你使用的是你从别处取色的精确的 RGB 组合 (Photoshop 吸管, 数码测色计(Digital Color Meter)等)。

同样, 如果在不同的色彩配置中使用相同的 RGB 组合, 则会得到不同的颜色。

此外, Photoshop 处理颜色时,使用Photoshop的人与使用RGB值的人不是同一台设备不说,Adobe使用人员Photoshop的色彩空间也未必与开发人员一致 (可能会是Adobe发明的颜色空间), 所以当你试图直接从 Photoshop 中选取它们并将其应用于 Xcode 时, 情况可能会变得更糟。

Photoshop在编辑菜单的颜色设置中可以查看更改色彩配置。

所有这一切都解释了为什么当你使用数码测色计选择一个颜色, 你可能会得到不同的 RGB 值但是是相同的颜色。如果你在不同的显示器 (因为额外的设备信息可以添加到每个像素, 当你选择颜色, 取决于您使用的是与设备相关的色彩配置还是与设备无关的。

你可以猜到,我们要使用一个设备无关的, 如 sRGB (代表标准的 RGB), 所以无论我们将在什么地方显示,我们将得到相同的 RGB 值时。

iOS中代码自定义设置RGB与Interface Builder自定义设置RGB颜色一致。都使用了sRGB色彩配置。

在XIB中的色彩配置

选择颜色后使用sublime等文本编辑器直接打开storyboard或者xib文件。即可看到如下几种结果。

如果色彩配置采用了sRGB ,sb/xib的xml中会这样写,colorSpace="custom" customColorSpace="sRGB" ,一般都是使用颜色选择器自定义RGB后自动选择的sRGB色彩配置

如果色彩配置采用了Display P3, sb/xib的xml中会这样写,colorSpace="custom" customColorSpace="displayP3",

如果色彩配置采用了Generic RGB, sb/xib的xml中会这样写,colorSpace="calibratedRGB" ,一般都是使用颜色选择器自定义RGB后手动选择的Generic RGB色彩配置

如果色彩配置采用了Generic Gray , sb/xib的xml中会这样写,colorSpace="calibratedWhite",一般都是系统默认的灰白颜色。

如果色彩配置采用了Device Gray , sb/xib的xml中会这样写,colorSpace="deviceRGB",,一般都是使用颜色选择器自定义RGB后手动选择的DeviceRGB色彩配置

如果色彩配置采用了Adobe RGB , sb/xib的xml中会这样写,colorSpace="adobeRGB1998",,一般都是使用颜色选择器自定义RGB后手动选择的Adobe RGB色彩配置

最后发现,手动选择的Apple RGB色彩配置,sb/xib的xml中会这样写,colorSpace="sRGB",说明苹果默认统一成了sRGB.

在纯代码中的色彩配置

最新Xcode8测试,以下代码使用sRGB色彩配置

+ (UIColor *)colorWithRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha

类似[UIColor darkGrayColor]使用Generic Gray色彩配置

不信我们log下

CGColorSpaceRef   ref = CGColorGetColorSpace([UIColor colorWithRed:104/255.0 green:104/255.0 blue:104/255.0 alpha:1].CGColor);
NSLog(@"%@",ref);
CGColorSpaceRef   ref2 =  CGColorGetColorSpace([UIColor darkGrayColor].CGColor);
NSLog(@"%@",ref2);

<CGColorSpace 0x60000003f2a0> (kCGColorSpaceICCBased; kCGColorSpaceModelRGB; sRGB IEC61966-2.1; extended range)
<CGColorSpace 0x60800002af20> (kCGColorSpaceICCBased; kCGColorSpaceModelMonochrome; Generic Gray Gamma 2.2 Profile; extended range)

颜色拾取与应用

既然你明白了这件事的 ' 原因 ', 让我们来谈谈技巧。

要选择颜色, 我们将使用苹果系统自带的“数码测色计”应用,你可以在系统的实用工具或者Spotlight找到。这个程序适用于一些色彩配置计算屏幕上的一个像素的RGB值。

Xcode的颜色选择器也支持拾取,但是不能设置指定色彩配置的颜色拾取。只能是sRGB(代表标准的 RGB)。

要应用颜色,我们将使用 Xcode 的Interface Builder, 或者, 我们也可以以代码方式进行。

颜色拾取

打开数码测色计(Digital Color Meter),下拉中选择“以sRGB显示”/ "Display in sRGB", 使用取色吸管取色,shift+cmd+c,快捷键拷贝当前屏幕像素RGB的值.

如果想拷贝16进制颜色,在菜单的显示中可以设置切换。

然后再Xcode的Interface Builder,颜色选择器中选择sRGB(默认也是sRGB),填入取的颜色RGB值。

或者代码设置

self.label.backgroundColor = [UIColor colorWithRed:39/255.0 green:45/255.0 blue:51/255.0 alpha:0];

所以,总结下技巧:

使用取色软件,以sRGB色彩配置,取得RGB 值。

设计最好也使用sRGB色彩配置进行设计。

如果设计要给开发取色要使用sRGB取色。

因为代码初始化UIColor是不能像NSColor一样指定色彩空间的。所以要以不变(sRGB)应万变。

使用 sRGB 在 Xcode Interface Builder(或通过代码) 中应用这些 RGB 值。

参考文章

http://inaka.net/blog/2014/09/05/getting-the-right-colors-in-your-ios-app/

https://developer.apple.com/library/mac/documentation/GraphicsImaging/Conceptual/csintro/csintro_intro/csintro_intro.html

http://www.dpbestflow.org/color/color-space-and-color-profiles

http://stackoverflow.com/questions/14578759/wrong-color-in-interface-builder

转载请注明:天狐博客 » iOS开发之为App设置正确的设计颜色

iOS/Mac开发之为文件增加自定义的扩展属性(NSFileExtendedAttributes)

$
0
0

最近再完善自己的下载器,JKDownloader,我的原则就是只存下载文件缓存,不存任何数据到文件和或者数据库或者userdefault等等区域。

那问题就来了,当app重新打开如何知道文件的下载进度呢?

存在文件名中?或者存在文件内部?

结果最好的方案那就是需要把自定义的一些数据(文件总大小啦,文件下载百分比等等啦)写入到文件的扩展属性中了。

两种不同的方式来实现:

通过NSFileManager一个特殊的AttributeName

- (BOOL)setExtendedAttribute:(NSString*)attribute forKey:(NSString*)key withPath:(NSString*)path{
    NSData *data = [NSPropertyListSerialization dataWithPropertyList:attribute format:NSPropertyListBinaryFormat_v1_0 options:0 error:nil];
    NSError *error;
    BOOL sucess = [[NSFileManager defaultManager] setAttributes:@{@"NSFileExtendedAttributes":@{key:data}}
                                                   ofItemAtPath:path error:&error];
    return sucess;
}
- (id)getExtendedAttributeForKey:(NSString*)key  withPath:(NSString*)path{
    NSError *error;
    NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:path error:&error];
    if (!attributes) {
        return nil;
    }
    NSDictionary *extendedAttributes = [attributes objectForKey:@"NSFileExtendedAttributes"];
    if (!extendedAttributes) {
        return nil;
    }
    NSData *data = [extendedAttributes objectForKey:key];

    id plist = [NSPropertyListSerialization propertyListWithData:data options:0 format:NSPropertyListImmutable error:nil];
    
    return [plist description];
}

通过sys/xattr.h的函数实现

#include <sys/xattr.h>
//为文件增加一个扩展属性
- (BOOL)extended1WithPath:(NSString *)path key:(NSString *)key value:(NSData *)value
{
    ssize_t writelen = setxattr([path fileSystemRepresentation],
                                [key UTF8String],
                                [value bytes],
                                [value length],
                                0,
                                0);
    return writelen==0?YES:NO;
}
//读取文件扩展属性
- (NSData *)extended1WithPath:(NSString *)path key:(NSString *)key
{
    ssize_t readlen = 1024;
    do {
        char buffer[readlen];
        bzero(buffer, sizeof(buffer));
        size_t leng = sizeof(buffer);
        readlen = getxattr([path fileSystemRepresentation],
                           [key UTF8String],
                           buffer,
                           leng,
                           0,
                           0);
        if (readlen < 0){
            return nil;
        }
        else if (readlen > sizeof(buffer)) {
            continue;
        }else{
            NSData *result = [NSData dataWithBytes:buffer length:readlen];
            return result;
        }
    } while (YES);
    return nil;
}

NSFileExtendedAttributes字典对应的是一个NSData,NSData需要用NSPropertyListSerialization解析。

以下是文件所有的属性。

//通过NSFileManager获取文件的属性
NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:path error:NULL];
NSLog(@"%@",attributes);

Printing description of attributes:
{
    NSFileCreationDate = "2017-09-07 05:56:38 +0000";
    NSFileExtendedAttributes =     {
        JKDownloaderExpectedFileSize = <62706c69 73743030 58343730 31343130 37080000 00000000 01010000 00000000 00010000 00000000 00000000 00000000 0011>;
    };
    NSFileExtensionHidden = 0;
    NSFileGroupOwnerAccountID = 20;
    NSFileGroupOwnerAccountName = staff;
    NSFileModificationDate = "2017-09-07 06:26:32 +0000";
    NSFileOwnerAccountID = 501;
    NSFilePosixPermissions = 420;
    NSFileReferenceCount = 1;
    NSFileSize = 12432269;
    NSFileSystemFileNumber = 70334415;
    NSFileSystemNumber = 16777217;
    NSFileType = NSFileTypeRegular;
}

是不是很酷?

Done!

转载请注明:天狐博客 » iOS/Mac开发之为文件增加自定义的扩展属性(NSFileExtendedAttributes)

IB Designables: Failed to render and update auto layout status....,no suitable image found

$
0
0

ViewController.xib: error: IB Designables: Failed to render and update auto layout status for UIView (i5M-Pr-FkT): dlopen(Module.framework, 1): no suitable image found.  Did find:
    Module.framework: unknown file type, first eight bytes: 0x21 0x3C 0x61 0x72 0x63 0x68 0x3E 0x0A

ViewController.xib: error: IB Designables: Failed to update auto layout status: dlopen(Module.framework, 1): no suitable image found.  Did find:
    Module.framework: unknown file type, first eight bytes: 0x21 0x3C 0x61 0x72 0x63 0x68 0x3E 0x0A

我知道使用 IB_DESIGNABLE,IBInspectable可以实现xib中动态配置属性。

but,最近某个使用IB_DESIGNABLE的类放在了Framework静态库中,xib/storyboard放在了bundle中。结果就报这个错了。google了半天也没解决办法。

下边这些库同样遇到了这个尴尬。

Designable的确是个很好的概念,不过苹果并没有修复和增强他。很遗憾。

https://github.com/CocoaPods/CocoaPods/issues/2792

https://github.com/TTTAttributedLabel/TTTAttributedLabel/issues/460

转载请注明:天狐博客 » IB Designables: Failed to render and update auto layout status....,no suitable image found

iPhone X(10)屏幕分辨率与适配

$
0
0

iPhone X(10)屏幕分辨率与适配,iOS开发适配与UI设计问题。iPhone人机交互指南。

北京时间的9月13日凌晨,美国当地时间的9月12日上午,苹果在发布会上发布了四款产品,本包括全新的Apple Watch Series 3,Apple TV 4K,iPhone 8/8 Plus,和全新iPhone X四款全新产品。其中X是数字10的意思,因此苹果将其读音读作“iPhone Ten”。

在屏幕上,iPhone X搭载了一块2436×1125分辨率的OLED显示屏,苹果将之称为Super Retina Display。它有着iPhone史上最大的458ppi,,支持HDR、3D Touch和True Tone显示。这款 OLED 屏拥有极佳的对比度、超高的分辨率、极薄的厚度、优越的亮度、宽广的色域、以及优秀的色准,3D Touch, True Tone等等功能。

苹果还引入了 Animoji(emoji 动画升级版),让你可以将乐趣延伸到日常生活中,可以直接实时映射脸部表情的动画版EMOJI。

 屏幕尺寸

“iPhone X”, 5.8 英寸,屏幕分辨率为 1242 x 2800

除去底部固定的功能区,屏幕显示范围的尺寸为 5.15 英寸,458ppi。

  • 竖屏尺寸:1125px × 2436px(375pt × 812pt @3x)
  • 横屏尺寸:2436px × 1125px(812pt × 375pt @3x)

iPhone 7 设备渲染后分辨率为 750 x 1334,逻辑分辨率只有 375 x 667。

iPhone X 设备渲染后分辨率为 1125 x 2436,逻辑分辨率是为 375 x 812。

这就意味着,除去下巴的功能区,iPhone X与 4.7 寸的7同宽,但是高度多了一截。145pt,导致多出了大约 20%的垂直高度。

就是多了这一截,这一截,在UI设计方面与iOS开发适配方面都会出现或多或少的问题。

齐刘海设计也需要适配。

Layout设计适配

在针对iPhone X设计效果时,必须确保布局填满屏幕,不被设备的圆角,传感器区域(留海),或访问主屏幕的指示器挡住。

大多数应用程序使用标准的,系统提供的UI元素,比如导航栏、表视图、和集合视图自动适应设备的新形式因素。

背部材料延伸到显示的边缘, 并且 UI 元素被适当地插入和定位。

对于具有自定义布局的应用程序, 支持 iPhone X 也应该相对容易, 特别是当您的应用程序使用自动布局并遵守安全区域(safe area)和边界布局参考线(margin layout guides)。

预览你的应用程序在iPhone X上

你可以使用Xcode的模拟器去预览app并且检查剪裁和其他布局问题,有一些特性,如广域色,最好在实际设备上预览。

提供全屏体验

确保背景延伸到显示的边缘, 并且垂直滚动的布局 (如tableview和collectionview) 一直延伸到底部。

内容留边距防止剪切

一般情况下, 内容应居中并间距对称, 因此它在任何方向上看起来都很棒, 并且不被拐角或设备的传感器区域剪裁, 或者被用于访问主屏幕的指示器遮挡。为获得最佳效果, 请使用标准的、系统提供的界面元素和自动布局来构建您的界面。所有应用程序都应遵循 UIKit 定义的安全区域(safe area)和布局边距(layout margins), 从而确保基于设备和上下文的适当的间距。安全区域还可以防止内容从状态栏、导航栏、工具栏和标签栏底部漏出来。

注意状态栏的高度

在 iPhone X 上, 状态栏比其他 iPhone 要高。如果您的应用程序假定了一个固定的状态栏高度,在状态栏下相对定位内容, 则必须更新应用程序以根据用户的设备动态定位内容。请注意, 当后台任务 (如录音和定位) 处于活动状态时, iPhone X 上的状况栏不会改变高度。

如果你的应用目前隐藏状态栏,重新考虑下iPhone X再决定

在iPhone X上的显示高度比4.7寸的iPhone手机提供更多的垂直空间内容,屏幕的状态栏面积可能不会被应用程序充分利用。状态栏显示给人们有用的信息。只有在交换附加值时候才能被隐藏。e。

注意纵横比差异

iPhone X与4.7寸iPhone比例不同,因此, 全屏 4.7 寸iPhone图显示在iPhone X时出现裁剪或上下加框, 同样的全屏iPhone X 图显示在4.7寸iPhone上,出现裁剪或左右加框。确保重要的视觉内容在两个显示大小的视图中保持不变。

避免将控件放置于屏幕最底部或者角落

人们使用显示屏底部边缘的滑动手势来访问主屏幕和应用程序切换器, 这些手势可能会取消您在该区域实现的自定义手势。屏幕的最远的角落可能是人能接触到的最困难区域。

不要掩盖关键的显示特性

不要企图隐藏设备的圆角,传感器区域,或用于访问主屏幕的指示器。视图放在黑条屏幕的顶部和底部。不要使用像括号、挡板、形状或教学文本这样的视觉修饰来特别标示这些区域。

自动隐藏的指示器

当自动隐藏开启的时候,如果用户没有触碰屏幕几秒钟,指示器会淡出。当用户触摸屏幕时重新出现。此行为应仅对被动查看体验 (如播放视频或照片幻灯片) 启用。。

Layout开发适配

Layout Guides and Safe Area

Layout guides定义的矩形区域实际上在屏幕上不可见, 但可以帮助定位、对齐和内容间距。系统包括预定义的layout guides, 使其易于在内容周围应用标准边距, 并限制文本的宽度以获得最佳可读性。还可以定义自定义 layout guides。

遵守 UIKit 定义的安全区域和布局边距所有应用程序都应遵循 UIKit 定义的安全区域(safe area)和布局边距(layout margins), 从而确保基于设备和上下文的适当的间距。安全区域还可以防止内容从状态栏、导航栏、工具栏和标签栏底部漏出来。

从iOS 7以来,我们在整个操作系统中都有半透明的bars,苹果鼓励我们通过这些bars绘制内容,我们是通过viewController 的edgesForExtendedLayout属性来做这些的。

iOS 7 开始,在 UIViewController中引入的 topLayoutGuide和 bottomLayoutGuide 在 iOS 11 中被废弃了,取而代之的就是UIView的safeArea的概念,UIView的safeArea是描述你的视图部分不被任何内容或者bars遮挡的方法。 它提供两种方式:safeAreaInsets或safeAreaLayoutGuide来提供给你safeArea的参照值,即 insets 或者 layout guide

Xib/Storyboard中开启

蓝色区域即为safeArea

Top/Bottom Layout Guide VS Safe Arae Layout Guide

修复一个相对于导航栏为0的约束

-  equalTo: view.topAnchor,
-  constant: 64
+  equalTo: view.safeAreaLayoutGuide.topAnchor

iPhone X机型判断

目前还不知道iPhone X的Devive Model,可以拿分辨率来判断。

#define iPhoneX ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(1125, 2436), [[UIScreen mainScreen] currentMode].size) : NO)

SDK兼容

使用新API时,要从编译时与运行时同事判断。才是彻底的SDK兼容。

//__IPHONE_11_0 判断最好直接使用数值,使用低版本SDK的时候,__IPHONE_11_0未必在系统中存在
// 编译时判断:检查SDK版本
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000
    // 运行时判断:检查当前系统版本
    if ([UIDevice currentDevice].systemVersion.floatValue > 11.0f) {
         self.view.safeAreaLayoutGuide;
    } else {
        // 用旧的代替
        self.topLayoutGuide;
    }
#else
    // 用旧的代替
    self.topLayoutGuide;
#endif
}

点击查看更多iOS开发之SDK兼容性指南

原生控件frame变化

在iPhone X系统会自动修改StatusBar与Tabbar的高度,Tabbar从49pt变为83pt。StatusBar由20pt变为了44pt

举个例子。原生的Tabbar高度为49pt.当iPhone X时候自动变为了83pt,自动拉伸了34pt。有很多反人类但是必须得做的需求是,需要把tabbar。高度改为非原生值,比如改成写死值55.

这时候iPhonex 中就有问题了。所以要换个方法,不要写死值。要么加变化量。要么单独判断下。iPhone X不变高度。

812pt-667pt = 145pt,145pt-状态栏增加的20pt-tabbar增加的34pt = 91pt,意味着全使用原生bars的app,如果不是tableview那种页面。有91pt的空白距离要设计上来做处理。

安全区域扩展到包括自定义视图 additionalSafeAreaInsets

自定义insets修改视图的安全区域。

您的容器视图控制器可以通过嵌入式子视图控制器的视图显示自己的内容视图。 在这种情况下,请更新子视图控制器的安全区域,以排除容器视图控制器内容视图覆盖的区域。 UIKit容器视图控制器已经调整其子视图控制器的安全区域来解释内容视图。 例如,导航控制器可以扩展其子视图控制器的安全区域,以便导航栏。

要扩展嵌入式子视图控制器的安全区域,请修改additionalSafeAreaInsets属性。 假设您定义一个容器视图控制器,可以在屏幕的底部和右侧边缘显示自定义视图,如图所示。由于子视图控制器的内容位于自定义视图下方,因此必须扩展子对象的底部和右侧插入。

在容器视图控制器的viewDidAppear方法进行修改,因为视图添加到视图层次结构中,视图的安全区域inset不正确。

override func viewDidAppear(_ animated: Bool) {
   var newSafeArea = view.safeAreaInsets

   // Adjust the safe area to accommodate 
   //  the width of the side view.
   if let sideViewWidth = sideView?.bounds.size.width {
      newSafeArea.right += sideViewWidth
   }

   // Adjust the safe area to accommodate 
   //  the height of the bottom view.
   if let bottomViewHeight = bottomView?.bounds.size.height {
      newSafeArea.bottom += bottomViewHeight
   }

   // Adjust the safe area insets of the 
   //  embedded child view controller.
   let child = self.childViewControllers[0]
   child.additionalSafeAreaInsets = newSafeArea
}

 

Color适配

iPhone X支持P3色彩空间,从而产生更丰富,比sRGB更饱和的颜色。

使用广域色来增强视觉体验

在此之前,大多数捕获的照片都是 sRGB 色域。由于 sRGB 色域与大多数显示器能很好地兼容,因此它也成为网络上共享图像的标准。虽然 sRGB 在大多数时候都能很好地表现显示器的色彩,但是随着显示器和相机技术的提高,sRGB 开始显现它的不足。

使用广域色的照片和视频更加逼真, 使用广域色的可视化数据和状态指示器更具影响力。请参阅色彩管理

 

通常在开发上通常我们使用sRGB来设置颜色,因为sRGB兼容性是最好的。

早在iOS10也已经提供了P3色彩空间与设置方法

+ (UIColor *)colorWithDisplayP3Red:(CGFloat)displayP3Red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha NS_AVAILABLE_IOS(10_0); 
- (UIColor *)initWithDisplayP3Red:(CGFloat)displayP3Red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha NS_AVAILABLE_IOS(10_0);

Gestures

iPhone X使用屏幕边缘手势提供访问home屏幕功能,app切换,通知中心和控制中心。

避免干扰系统的屏幕边缘手势

人们依靠这些手势在每个应用程序中工作。在极少数情况下, 像游戏这样的沉浸式应用程序可能需要自定义屏幕边缘手势, 优先于系统的手势, 第一次swipe调用应用程序特定的手势, 第二swipe调用系统手势。此行为 (称为边缘保护) 应谨慎实施, 因为它使人们更难访问系统级操作。参考章节Gestures.

额外的设计考虑

引用正确的验证方式

iPhone X 使用Face ID 进行验证。如果您的应用程序集成了苹果支付或其他系统认证功能, 不要在 iPhone X上引用Touch ID验证, 同样的请确保您的应用程序不在支持Touch ID 的设备上引用 "Face ID"。参考章节 Authentication.

不要重复提供键盘功能

在iPhone X中,Emoji/Globe 按钮和 Dictation 按钮也自动显示在键盘的下方,即使使用自定义键盘。你的应用程序不能影响这些按钮,所以避免引起混乱,不要在你的键盘再次添加他们。

参考章节 Custom Keyboards.

扩展阅读

UILayoutGuide, layoutMarginsGuide, readableContentGuide, and safeAreaLayoutGuide.

人机交互指南iPhone X:https://developer.apple.com/ios/human-interface-guidelines/overview/iphone-x/

Designing for iPhone X:https://developer.apple.com/videos/play/fall2017/801/

Adaptivity and Layou:https://developer.apple.com/ios/human-interface-guidelines/visual-design/adaptivity-and-layout/

Positioning Content Relative to the Safe Area :https://developer.apple.com/documentation/uikit/uiview/positioning_content_relative_to_the_safe_area?language=objc

iPhone X UI 设计模板 :https://developer.apple.com/design/resources/#ios-apps

iOS开发之SDK兼容性指南

转载请注明:天狐博客 » iPhone X(10)屏幕分辨率与适配

Xcode Framework not found FileProvider for architecture x86_64/arm64

$
0
0

升级了Xcode9,有Framework是给第三方来用的,但是第三方用的是Xcode8,这时候Xcode9打出来的Framework放进Xcode8会报错

Framework not found FileProvider for architecture x86_64/arm64.

查阅资料发现,Xcode9的

/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/

目录中多了个FileProvider,而Xcode8并没有

解决方法就是复制Xcode9的 FileProvider到Xcode8中。

 

参考

ios之Linker command failed with exit code(use -v to see invocation)

 

转载请注明:天狐博客 » Xcode Framework not found FileProvider for architecture x86_64/arm64

iOS开发之UITabBarControllerd的viewcontrollers预加载

$
0
0

喃们都知道,UITabBarController作为ViewController容器的时候,TabBarController显示后,只会默认load TabBarController的第一个ViewController(或者selectedViewController)的View

只有在点击tabbar或者设置selectedViewController,selectedIndex时候,才会调用想用的ViewController的loadView与viewDidLoad。

不难理解,苹果做了一个self.view延迟加载。

最近遇到一个需求,要所有的TabBarController的viewControllers都要直接加载self.view,调用viewDidLoad等方法进行逻辑处理。

解决办法很简单,调用loadViewIfNeeded方法加载View,或者强制调用下loadView,访问viewControlle的view即可立即loadView。

for(UIViewController *viewController in  _tabBarController.viewControllers){
        [viewController loadViewIfNeeded];
//      __unused  UIView *view =  viewController.view;
    }

 

转载请注明:天狐博客 » iOS开发之UITabBarControllerd的viewcontrollers预加载


iOS开发基于Objective-C的Framework中使用CommonCrypto

$
0
0

在Swift中我们引用CommonCrypto的时候会创建一个.modulemap间接引用CommonCrypto.framework,Objective-C中是可以直接#import <CommonCrypto/CommonCryptor.h>的。

但是最近更新了Xcode发现自己的JKCategories Framework类库中引用CommonCrypto后打包Framework文件,或者集成到CocoaPods都会报错。

/Users/runlin/Desktop/TestJKCategoriesPod/Pods/JKCategories/JKCategories/Foundation/NSData/NSData+JKEncrypt.h:11:9: Include of non-modular header inside framework module 'JKCategories.NSData_JKEncrypt': '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator11.2.sdk/usr/include/CommonCrypto/CommonCryptor.h'

调试发现将要Define Module设置为NO问题即消失。

如果想保留Define Module为YES。同样效仿Swift配置个modulemap即可。

Xcode工程中新建文件夹与文件CommonCrypto/module.modulemap,经过不断尝试内容为

module CommonCrypto [system] {
    header "/usr/include/CommonCrypto/CommonCrypto.h"
    export *
}

framework module JKCategories {
}

JKCategories Framework target =>build settings=>module map file 设置为$(SRCROOT)/CommonCrypto/module.modulemap

到这一步JKCategories Framework的target就可以直接生成Framework了。

CocoaPods配置Module Map

CocoaPods配置module map file 是在JKCategories.podspec中,添加以下配置

s.module_map = "CommonCrypto/module.modulemap"

Push podspec即可。

 

 

 

 

转载请注明:天狐博客 » iOS开发基于Objective-C的Framework中使用CommonCrypto

iOS开发之Charts柱状图设置最大可见量,X轴数据过长左右滑动查看

$
0
0

Charts,BarChartView,默认情况下,如果x轴数据过多,会自动缩小单个柱状图宽度,造成数据都挤在一起。底部柱状图的名称也显示不全。

需要当X轴数据多时, 柱形图柱状条的宽度定值,滑动X轴左右查看其它数据。

设置一页显示的数据条数,超出的数量需要滑动查看:

[self.barChartView setVisibleXRangeMaximum:7];

/// Sets the size of the area (range on the x-axis) that should be maximum visible at once (no further zooming out allowed).
/// If this is e.g. set to 10, no more than a range of 10 values on the x-axis can be viewed at once without scrolling.
/// If you call this method, chart must have data or it has no effect.
- (void)setVisibleXRangeMaximum:(double)maxXRange;

最重要的事情是,如果需要调用此方法,需要BarChartView有数据,否则不会生效。一般在 self.barChartView.data = data; 之后调用即可。

转载请注明:天狐博客 » iOS开发之Charts柱状图设置最大可见量,X轴数据过长左右滑动查看

Android开发之图片写入到Sqlite读取崩溃

$
0
0

最近写个本地App blob,需要把图片放到android的sqlite中就行读写。测试发现,有的图可以正常保存显示,有的图保存后,select会导致app崩溃。崩溃原因为:

java.lang.IllegalStateException: Couldn't read row 0, col 0 from CursorWindow. Make sure the Cursor is initialized correctly before accessing data from it.

谷歌了很多,发现导致导致Cursor的原因就几个,列不存在,Cursor错误,CursorWindow size问题。

研究一番发现,Android SQLite CursorWindow指定了一个最大为2MB的config_cursorWindowSize值。

在Android源码中config_cursorWindowSize值定义如下:
sdk\platforms\android-23\data\res\values\configs.xml:

<!-- When a database query is executed, the results retuned are paginated in pages of size (in KB) indicated by this value -->
<integer name="config_cursorWindowSize">2048</integer>

 

显然这个值是写死的,不能通过app配置其大小,所以 要么改变别人 要么改变自己。。乖乖压缩下图片存储。终于正常了。

 

网上随手搜了个图片压缩类,改了改。

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;

public class ImageCompresser {
    /**
     * 压缩图片到指定宽高,并进行质量压缩,最终大小保持在maxDiskSize K以下
     *
     * @param sourceBm
     * @param targetWidth
     * @param targetHeight
     * @return
     */
    public static Bitmap compressImage(Bitmap sourceBm, float targetWidth, float targetHeight,float maxDiskSize) {
        BitmapFactory.Options newOpts = new BitmapFactory.Options();
        // 开始读入图片,此时把options.inJustDecodeBounds 设回true了
        newOpts.inJustDecodeBounds = true;
        // 可删除
        newOpts.inPurgeable = true;
        // 可共享
        newOpts.inInputShareable = true;
        // 转成数组
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        sourceBm.compress(Bitmap.CompressFormat.JPEG, 100, baos);
        byte[] temp = baos.toByteArray();
        // 此时返回bm为空
        Bitmap bitmap = BitmapFactory.decodeByteArray(temp, 0, temp.length, newOpts);
        newOpts.inJustDecodeBounds = false;
        int w = newOpts.outWidth;
        int h = newOpts.outHeight;
        // 现在主流手机比较多是800*480分辨率,所以高和宽我们设置为
        float hh = targetHeight;
        float ww = targetWidth;
        // 缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可
        int be = 1;// be=1表示不缩放
        // 如果宽度大的话根据宽度固定大小缩放
        if (w > h && w > ww) {
            be = (int) (newOpts.outWidth / ww);
        } else if (w < h && h > hh) {
            // 如果高度高的话根据宽度固定大小缩放
            be = (int) (newOpts.outHeight / hh);
        }
        if (be <= 0) {
            be = 1;
        }
        // 设置缩放比例
        newOpts.inSampleSize = be;
        // 重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了
        bitmap = BitmapFactory.decodeByteArray(temp, 0, temp.length, newOpts);
        // 压缩好比例大小后再进行质量压缩
        return compressImageWitDisksize(bitmap,maxDiskSize);
    }
    /**
     * @Description 质量压缩方法
     * @param image
     * @param maxDiskSize 最大kb尺寸
     * @return
     */
    public static Bitmap compressImageWitDisksize(Bitmap image,float maxDiskSize) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        // 质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中
        image.compress(Bitmap.CompressFormat.JPEG, 100, baos);
        int options = 100;
        // 循环判断如果压缩后图片是否大于100kb,大于继续压缩
        while (baos.toByteArray().length / 1024 > maxDiskSize) {
            // 重置baos即清空baos
            baos.reset();
            // 这里压缩options%,把压缩后的数据存放到baos中
            image.compress(Bitmap.CompressFormat.JPEG, options, baos);
            // 每次都减少10
            options -= 10;
        }
        // 把压缩后的数据baos存放到ByteArrayInputStream中
        ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());
        // 把ByteArrayInputStream数据生成图片
        Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);
        return bitmap;
    }
    /**
     * 只进行分辨率压缩,不进行图片的质量压缩
     *
     * @param sourceBm
     * @param targetWidth
     * @param targetHeight
     * @return
     */
    public static Bitmap compressImageWithResolution(Bitmap sourceBm, float targetWidth, float targetHeight) {
        BitmapFactory.Options newOpts = new BitmapFactory.Options();
        // 开始读入图片,此时把options.inJustDecodeBounds 设回true了
        newOpts.inJustDecodeBounds = true;
        // 可删除
        newOpts.inPurgeable = true;
        // 可共享
        newOpts.inInputShareable = true;
        // 转成数组
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        sourceBm.compress(Bitmap.CompressFormat.JPEG, 100, baos);
        byte[] temp = baos.toByteArray();
        // 此时返回bm为空
        Bitmap bitmap = BitmapFactory.decodeByteArray(temp, 0, temp.length, newOpts);
        newOpts.inJustDecodeBounds = false;
        int w = newOpts.outWidth;
        int h = newOpts.outHeight;
        // 现在主流手机比较多是800*480分辨率,所以高和宽我们设置为
        float hh = targetHeight;
        float ww = targetWidth;
        // 缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可
        // be=1表示不缩放
        int be = 1;
        if (w > h && w > ww) {
            // 如果宽度大的话根据宽度固定大小缩放
            be = (int) (newOpts.outWidth / ww);
        } else if (w < h && h > hh) {
            // 如果高度高的话根据宽度固定大小缩放
            be = (int) (newOpts.outHeight / hh);
        }
        if (be <= 0) {
            be = 1;
        }
        // 设置缩放比例
        newOpts.inSampleSize = be;
        // 重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了
        bitmap = BitmapFactory.decodeByteArray(temp, 0, temp.length, newOpts);
        // 压缩好比例大小后再进行质量压缩
        return bitmap;
    }
}

goods.goods_picture = ImageCompresser.compressImage(bitmap,180,90,200);

先进行像素尺寸压缩,在进行磁盘质量压缩!完美。

 

转载请注明:天狐博客 » Android开发之图片写入到Sqlite读取崩溃

Error Domain=com.apple.CallKit.error.calldirectorymanager Code

$
0
0

CallKit error枚举

typedef NS_ERROR_ENUM(CXErrorDomainCallDirectoryManager, CXErrorCodeCallDirectoryManagerError) {
    CXErrorCodeCallDirectoryManagerErrorUnknown = 0,
    CXErrorCodeCallDirectoryManagerErrorNoExtensionFound = 1,
    CXErrorCodeCallDirectoryManagerErrorLoadingInterrupted = 2,
    CXErrorCodeCallDirectoryManagerErrorEntriesOutOfOrder = 3,
    CXErrorCodeCallDirectoryManagerErrorDuplicateEntries = 4,
    CXErrorCodeCallDirectoryManagerErrorMaximumEntriesExceeded = 5,
    CXErrorCodeCallDirectoryManagerErrorExtensionDisabled = 6,
    CXErrorCodeCallDirectoryManagerErrorCurrentlyLoading API_AVAILABLE(ios(10.3)) = 7,
    CXErrorCodeCallDirectoryManagerErrorUnexpectedIncrementalRemoval API_AVAILABLE(ios(11.0)) = 8,
} API_AVAILABLE(ios(10.0));

MEMBER NAME DESCRIPTION
CurrentlyLoading
DuplicateEntries
EntriesOutOfOrder
ExtensionDisabled The directory extension was disabled.
LoadingInterrupted The loading of the directory extension was interrupted.
MaximumEntriesExceeded The maximum number of directory entries was exceeded.
NoExtensionFound The extension could not be found.
UnexpectedIncrementalRemoval
Unknown An unknown error occured.

转载请注明:天狐博客 » Error Domain=com.apple.CallKit.error.calldirectorymanager Code

iOS开发之SQLite按数字字符串大小排序

$
0
0

最近弄了下iOS的CallKit,进行来电识别。addIdentificationEntryWithNextSequentialPhoneNumber 方法进行添加电话号。

我们知道,sql排序一个order by asc/desc即可。

but,当你把数字 比如手机号和电话号以text方式存入数据库,再order by,顺序并不是按照数字大小排序。

原因是因为字段虽然存储了数字值,但是它是一个字符型,而字符型的 电话开头的'2'等字符都 比手机的开头字符 '1'要大 。因为是从第一个字母开始比较的。

所以解决办法:

1.更改表结构,更改类型为int、integer

2.更改sql结构。  "select * from Contact order by mobile+0 asc";

后边加个0,强转成int比较即可。

转载请注明:天狐博客 » iOS开发之SQLite按数字字符串大小排序

Viewing all 115 articles
Browse latest View live