@interface DemoLogsView : UIWindow
+ (instancetype)shared;
- (void)setup;
- (void)appendLog:(NSString *)format, ...;
- (void)clearLogs;
@end
@interface DemoLogsView()<UITableViewDelegate, UITableViewDataSource>
@property (strong, nonatomic) UITableView *logsTb;
@property (strong, nonatomic) UIButton *toggleBtn;
@property (strong, nonatomic) UIButton *exportBtn;
@property (strong, nonatomic) UIButton *clearBtn;
@end
@implementation DemoLogsView
{
NSMutableArray *_logsData;
CGRect _toggleBtnOffFrame;
}
#pragma mark - TableView Protocols
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return _logsData.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *RID = @"LogCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:RID];
if(!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:RID];
}
cell.contentView.backgroundColor = UIColor.blackColor;
cell.textLabel.textColor = UIColor.whiteColor;
cell.textLabel.numberOfLines = 0;
cell.textLabel.font = [UIFont fontWithName:@"Courier New" size:13];
cell.textLabel.text = _logsData[indexPath.row];
return cell;
}
static double buttonSize = 40;
- (void)setup {
[self toggleExpand:NO];
[self setHidden:NO];
}
- (CGRect)toggleButtonFrame {
CGFloat y = CGRectGetMaxY(UIScreen.mainScreen.bounds) - buttonSize - 20;
if (@available(iOS 11.0, *)) {
y -= self.safeAreaInsets.bottom;
y += 20;
}
return CGRectMake(20, y, buttonSize, buttonSize);
}
- (void)toggleExpand:(BOOL)expand {
if(CGPointEqualToPoint(_toggleBtnOffFrame.origin, CGPointZero)) {
_toggleBtnOffFrame = [self toggleButtonFrame];
}
else if(expand) {
_toggleBtnOffFrame = self.frame;
}
_logsTb.hidden = !expand;
_exportBtn.hidden = !expand;
_clearBtn.hidden = !expand;
[_toggleBtn setTitle:expand ? @"❌" : @"📝" forState:UIControlStateNormal];
self.frame = expand ? UIScreen.mainScreen.bounds : _toggleBtnOffFrame;
_logsTb.frame = self.bounds;
_toggleBtn.frame = expand ? [self toggleButtonFrame] : self.bounds;
}
+ (NSString *)logDateString {
static dispatch_once_t onceToken;
static NSDateFormatter *df;
dispatch_once(&onceToken, ^{
df = [NSDateFormatter new];
df.dateFormat = @"yyyy-MM-dd HH:mm:ss:SSS";
});
return [df stringFromDate:NSDate.date];
}
- (void)appendLog:(NSString *)format, ...{
if(![format isKindOfClass:NSString.class]) {
format = [NSString stringWithFormat:@"%@",format];
}
va_list args;
va_start(args, format);
NSString *logStr = [[NSString alloc] initWithFormat:format arguments:args];
logStr = [[self.class logDateString] stringByAppendingFormat:@" %@\n",logStr];
va_end(args);
dispatch_async(dispatch_get_main_queue(), ^{
@synchronized (self) {
[self->_logsData addObject:logStr];
NSIndexPath *lastRow = [NSIndexPath indexPathForRow:self->_logsData.count-1 inSection:0];
[self.logsTb insertRowsAtIndexPaths:@[
lastRow
] withRowAnimation:UITableViewRowAnimationNone];
[self.logsTb scrollToRowAtIndexPath:lastRow atScrollPosition:UITableViewScrollPositionBottom animated:NO];
}
});
}
- (void)clearLogs {
dispatch_async(dispatch_get_main_queue(), ^{
@synchronized (self) {
[self->_logsData removeAllObjects];
}
[self.logsTb reloadData];
});
}
+ (instancetype)shared {
static dispatch_once_t onceToken;
static DemoLogsView *obj;
dispatch_once(&onceToken, ^{
obj = [[self alloc] initWithFrame:UIScreen.mainScreen.bounds];
});
return obj;
}
- (instancetype)initWithFrame:(CGRect)frame {
if(self = [super initWithFrame:frame]) {
self.windowLevel = UIWindowLevelStatusBar + 100;
self.backgroundColor = UIColor.clearColor;
[self addSubview:self.logsTb];
[self addSubview:self.toggleBtn];
[self addSubview:self.exportBtn];
[self addSubview:self.clearBtn];
[self setupLogs];
_logsData = @[].mutableCopy;
}
return self;
}
+ (void)load {
[NSUserDefaults.standardUserDefaults setValue:@"1" forKey:@"CCISMessageLogTestSwitch"];
[NSUserDefaults.standardUserDefaults synchronize];
}
- (void)layoutSubviews {
[super layoutSubviews];
{
CGFloat y = 20;
if (@available(iOS 11.0, *)) {
y += self.safeAreaInsets.bottom;
}
_exportBtn.frame = CGRectMake(CGRectGetMaxX(self.bounds)-20-buttonSize, y, buttonSize, buttonSize);
_clearBtn.frame = CGRectMake(CGRectGetMinX(_exportBtn.frame)-buttonSize-15, CGRectGetMinY(_exportBtn.frame), buttonSize, buttonSize);
}
}
- (void)setupLogs {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateLogs:) name:@"CCISLogNotification" object:nil];
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];
[self addGestureRecognizer:pan];
}
- (void)pan:(UIPanGestureRecognizer *)panGestureRecognizer{
if(!_logsTb.hidden) {
return;
}
CGFloat W = UIScreen.mainScreen.bounds.size.width;
CGFloat H = UIScreen.mainScreen.bounds.size.height;
//1、获得拖动位移
CGPoint offsetPoint = [panGestureRecognizer translationInView:panGestureRecognizer.view];
//2、清空拖动位移
[panGestureRecognizer setTranslation:CGPointZero inView:panGestureRecognizer.view];
//3、重新设置控件位置
UIView *panView = panGestureRecognizer.view;
CGFloat newX = panView.center.x+offsetPoint.x;
CGFloat newY = panView.center.y+offsetPoint.y;
if (newX < buttonSize/2) {
newX = buttonSize/2;
}
if (newX > W - buttonSize/2) {
newX = W - buttonSize/2;
}
if (newY < buttonSize/2) {
newY = buttonSize/2;
}
if (newY > H - buttonSize/2) {
newY = H - buttonSize/2;
}
panView.center = CGPointMake(newX, newY);
}
- (void)updateLogs:(NSNotification *)noti{
[self appendLog:noti.userInfo[@"content"]];
}
- (void)closeView {
[self toggleExpand:_logsTb.isHidden];
}
+ (UIButton *)makeRounderButton:(NSString *)title target:(id)target action:(SEL)selector {
UIButton *v = [UIButton buttonWithType:UIButtonTypeCustom];
v.frame = CGRectMake(0, 0, buttonSize, buttonSize);
v.layer.borderColor = UIColor.blackColor.CGColor;
v.layer.borderWidth = 1;
v.layer.cornerRadius = buttonSize/2;
// v.layer.shadowRadius = 5;
// v.layer.shadowOpacity = 0.5;
// v.layer.shadowOffset = CGSizeZero;
// v.layer.shadowColor = UIColor.blackColor.CGColor;
[v addTarget:target action:selector forControlEvents:UIControlEventTouchUpInside];
[v setTitle:title forState:UIControlStateNormal];
return v;
}
- (void)exportLogs:(UIButton *)sender {
// 显示分享
void(^shareLogsFile)(NSURL *file) = ^(NSURL *file){
[self toggleExpand:NO];
UIActivityViewController *avc = [[UIActivityViewController alloc] initWithActivityItems:@[
file
] applicationActivities:nil];
[avc setCompletionWithItemsHandler:^(UIActivityType __nullable activityType, BOOL completed, NSArray * __nullable returnedItems, NSError * __nullable activityError){
if(completed) {
[NSFileManager.defaultManager removeItemAtURL:file error:nil];
}
}];
UIWindow *window = UIApplication.sharedApplication.delegate.window ?: UIApplication.sharedApplication.keyWindow;
UIViewController *vc = window.rootViewController;
if([vc isKindOfClass:UINavigationController.class]) {
vc = ((UINavigationController *)vc).visibleViewController;
}
[vc presentViewController:avc animated:YES completion:nil];
};
// 将日志写到本地沙盒
void(^writeLogsToLocal)(void) = ^{
if(!self || !self->_logsData.count) { return; }
NSMutableString *logs = @"".mutableCopy;
for (id log in self->_logsData) {
[logs appendString:log];
}
NSString *url = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
id logFile = [NSString stringWithFormat:@"%@.log",[self.class logDateString]];
url = [url stringByAppendingPathComponent:logFile];
BOOL written = [[logs dataUsingEncoding:NSUTF8StringEncoding] writeToFile:url atomically:YES];
if(written) {
dispatch_async(dispatch_get_main_queue(), ^{
shareLogsFile([NSURL fileURLWithPath:url]);
});
}
else {
[self appendLog:@"写日志文件到本地失败!"];
}
};
dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{
writeLogsToLocal();
});
}
- (UIButton *)clearBtn {
if(!_clearBtn) {
UIButton *v = [self.class makeRounderButton:@"🗑️" target:self action:@selector(clearLogs)];
_clearBtn = v;
}
return _clearBtn;
}
- (UIButton *)exportBtn {
if(!_exportBtn) {
UIButton *v = [self.class makeRounderButton:@"📤" target:self action:@selector(exportLogs:)];
_exportBtn = v;
}
return _exportBtn;
}
- (UIButton *)toggleBtn {
if(!_toggleBtn) {
UIButton *v = [self.class makeRounderButton:@"" target:self action:@selector(closeView)];
_toggleBtn = v;
}
return _toggleBtn;
}
- (UITableView *)logsTb {
if(!_logsTb) {
UITableView *tv = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
tv.rowHeight = UITableViewAutomaticDimension;
tv.estimatedRowHeight = 44;
tv.delegate = self;
tv.dataSource = self;
tv.allowsSelection = NO;
tv.backgroundColor = UIColor.blackColor;
tv.contentInset = UIEdgeInsetsMake(buttonSize, 0, buttonSize, 0);
_logsTb = tv;
}
return _logsTb;
}
@end
网友评论