前提,我们是使用Weex以及EROS搭建的框架,具体使用请参考官方文档:
Weex官方文档,EROS官方文档。
长话短说,很晚了,直接上代码:
1、实现类似淘宝的tabbar
需求描述:就是做一个类似淘宝tabbar的效果,tabarItem的第一个图标和标题,在未选择的时候,和其他的一样,有一个图标和名称,当选中的时候,没有名称,只有一个图标,图标尺寸变大。
解决方案:直接对原生的UITabBarItem进行修改,可以修改里面的图片尺寸和大小,文字的颜色等。
文件目录:Benmu-iOS-Library/Source/BMController/BaseVc/BMTabBarController.m
修改代码:
在configItems
方法的最后面加上
//---设置类似淘宝的tababr
UITabBarItem *itemFirst = [self.tabBar.items objectAtIndex:0];
itemFirst.imageInsets = UIEdgeInsetsMake(6, 0, -6, 0);
[itemFirst setTitleTextAttributes:@{NSForegroundColorAttributeName: [UIColor colorWithRed:0 / 255.0 green:0 / 255.0 blue:0 / 255.0 alpha:0]} forState:UIControlStateSelected];
然后下面这个方法进行修改
/** tabbar index change */
- (void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item
{
// WXLogInfo(@"Dealloc >>>>>>>>>>>>>>>>>>>>>>>: %li",self.selectedIndex);
for (int i = 0; i < self.tabBar.items.count; i++) {
UITabBarItem *tmpItem = [self.tabBar.items objectAtIndex:i];
if (item == tmpItem) {
UITabBarItem *itemFirst = [self.tabBar.items objectAtIndex:0];
//---设置类似淘宝的tababr
if (i==0) {
itemFirst.imageInsets=UIEdgeInsetsMake(6, 0, -6, 0);
[itemFirst setTitleTextAttributes:@{NSForegroundColorAttributeName: [UIColor colorWithRed:0 / 255.0 green:0 / 255.0 blue:0 / 255.0 alpha:0]} forState:UIControlStateSelected];
}else{
itemFirst.imageInsets=UIEdgeInsetsMake(0, 0, 0, 0);
}
[BMGlobalEventManager sendGlobalEvent:@"tabarSelected" params:@{@"selectedIndex":@(i)}];
[[NSNotificationCenter defaultCenter] postNotificationName:K_BMTabbarChangeIndex object:@(i)];
return;
}
}
}
实现效果图:
参考资料:
1、更改UITabBarItem图像的高度和宽度 位置调整
2、 tabbarItem字体及图片颜色设置
2、实现类似微博中间加号的tabbar
需求描述:就是做一个类似微博中间加号的tabbar,现在的微博已经改版了,看不到这个效果了,微博起初了一个版本的tabbar是这样的,tabbar中间的tabbarItem,只有一个加号的图标,点击图标,是弹出一个蒙层,上面有几个功能按钮。
Tips:其实这个可以按照我上面的那个方法实现,下面是我另外一种解决方案,大家可参考一下
解决方案:添加一个图片直接覆盖在中间的UITabBarItem上面
文件目录:Benmu-iOS-Library/Source/BMController/BaseVc/BMTabBarController.m
修改代码:
在configItems
方法的for循环里面加上
if(i==2){
CGSize imageSize = CGSizeMake(40, 40);
UIImage *imageCenter =[UIImage imageNamed:@"addImage"];
imageCenter = [self scaleToSize:imageCenter size:imageSize];
item.image= [imageCenter imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
item.selectedImage = [imageCenter imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
item.imageInsets = UIEdgeInsetsMake(6, 0, -6, 0);
// item.imageInsets = UIEdgeInsetsMake(0, -10, -6, -10);
}
代码如图所示:
然后在加入下面的方法
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController{
//---中间的加号
if (viewController == self.viewControllers[2]) {
[BMGlobalEventManager sendGlobalEvent:@"tabarCenter" params:@{@"selectedIndex":@(self.selectedIndex)}];
return NO;
}
return YES;
}
讲点击加号的这个方法发射到Weex中,然后在weex中进行监听这个方法
const globalEvent = weex.requireModule('globalEvent')
/**
* tababr中间加号
* options
*/
// globalEvent.addEventListener('tabarCenter', function (options) {
globalEvent.addEventListener('tabarCenter', async (options) => {
let selectStore = await getCache("selectStore");
console.log('》》》》》》》》tabarCenter' + JSON.stringify(options));
let params = { selectedIndex: options.selectedIndex };
router.open({
url: "/pages/tabarCenter.js",
type: 'PRESENT',
navShow: false,
params: params,
})
});
然后点击加号实现类似微博弹出的一个蒙层页面!
实现效果图:
3、实现weex加载富文本
需求描述:APP中经常会用到加载富文本的问题,但是weex中并没有实现富文本的加载,这个坑就留给咱们自己踩了。我们遇到的是在商品详情页面里的一些商品信息,是后台解决返回的富文本,Weex官网的文档中展示这个的组件。
解决方案:自己封装一个原生组件,加载原生的webview。
新增一个LocalWebPage.h和LocalWebPage.m文件
目录:/Benmu-iOS-Library/Source/CustomerEvent/LocalWebPage.m
代码如下:
LocalWebPage.h
//
// LocalWebPage.h
// WeexDemo
//
// Copyright © 2018年 taobao. All rights reserved.
//
#import
#import "WXComponent.h"
@interface LocalWebPage : WXComponent
@end
LocalWebPage.m
//
// LocalWebPage.m
// WeexDemo
//
// Copyright © 2018年 taobao. All rights reserved.
//
#import "LocalWebPage.h"
#import
#import "WXUtility.h"
#import "WXURLRewriteProtocol.h"
#import "WXSDKEngine.h"
#import "BMMediatorManager.h"
#import "BMGlobalEventManager.h"
@interface LocalWebPage ()
@property (nonatomic, strong) JSContext *jsContext;
@property (nonatomic, strong) UIWebView *webview;
@property (nonatomic, assign) BOOL startLoadEvent;
@property (nonatomic, assign) BOOL finishLoadEvent;
@property (nonatomic, assign) BOOL failLoadEvent;
@property (nonatomic, assign) BOOL notifyEvent;
@property (nonatomic, strong) NSString *url;
@end
@implementation LocalWebPage
WX_EXPORT_METHOD(@selector(goBack))
WX_EXPORT_METHOD(@selector(reload))
WX_EXPORT_METHOD(@selector(goForward))
- (instancetype)initWithRef:(NSString *)ref type:(NSString *)type styles:(NSDictionary *)styles attributes:(NSDictionary *)attributes events:(NSArray *)events weexInstance:(WXSDKInstance *)weexInstance
{
if (self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance]) {
NSLog(@"%@",attributes);
NSString* src = attributes[@"src"];
self.url = src;
_url = src;
NSLog(@"%@",self.url);
}
return self;
}
- (UIView *)loadView
{
return [[UIWebView alloc] init];
}
- (void)viewDidLoad
{
_webview = (UIWebView *)self.view;
_webview.delegate = self;
_webview.allowsInlineMediaPlayback = YES;
_webview.scalesPageToFit = YES;
[_webview setBackgroundColor:[UIColor clearColor]];
// _webview.userInteractionEnabled=NO;
//禁止webView内部的scrollView的滚动
_webview.scrollView.scrollEnabled = NO;
//kvo监听webView内部的scrollView的contentSize
[_webview.scrollView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionNew context:nil];
_webview.opaque = NO;
// _webview.height = 971;
_jsContext = [_webview valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
__weak typeof(self) weakSelf = self;
_jsContext[@"$notifyWeex"] = ^(JSValue *data) {
if (weakSelf.notifyEvent) {
[weakSelf fireEvent:@"notify" params:[data toDictionary]];
}
};
if (_url) {
[self loadURL:_url];
}
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if (object == _webview.scrollView && [keyPath isEqualToString:@"contentSize"]) {
NSLog(@"_webView.scrollView.contentSize %f %f", _webview.scrollView.contentSize.width, _webview.scrollView.contentSize.height);
float height =_webview.scrollView.contentSize.height;
float webHeight = self.webview.height;
self.webview.height = height;
if([self.webview.superview isKindOfClass: NSClassFromString(@"WXScrollerComponentView")]){
UIScrollView* scroll = self.webview.superview;
float scrollHeight = scroll.contentSize.height - webHeight + height;
scroll.contentSize = CGSizeMake(scroll.contentSize.width, scrollHeight);
}
}
}
//3.删除监听
- (void)dealloc
{
[_webview.scrollView removeObserver:self forKeyPath:@"contentSize" ];
}
- (void)updateAttributes:(NSDictionary *)attributes
{
if (attributes[@"src"]) {
self.url = attributes[@"src"];
}
}
- (void)addEvent:(NSString *)eventName
{
if ([eventName isEqualToString:@"pagestart"]) {
_startLoadEvent = YES;
}
else if ([eventName isEqualToString:@"pagefinish"]) {
_finishLoadEvent = YES;
}
else if ([eventName isEqualToString:@"error"]) {
_failLoadEvent = YES;
}
}
- (void)setUrl:(NSString *)url
{
NSString* newURL = [url copy];
WX_REWRITE_URL(url, WXResourceTypeLink, self.weexInstance)
if (!newURL) {
return;
}
if (![newURL isEqualToString:_url]) {
_url = newURL;
if (_url) {
[self loadURL:_url];
}
}
}
- (void)loadURL:(NSString *)url
{
if (self.webview) {
// NSURLRequest *request =[NSURLRequest requestWithURL:[NSURL URLWithString:url]];
// [self.webview loadRequest:request];
[self.webview loadHTMLString:url baseURL:nil];
}
}
- (void)reload
{
[self.webview reload];
}
- (void)goBack
{
if ([self.webview canGoBack]) {
[self.webview goBack];
}
}
- (void)goForward
{
if ([self.webview canGoForward]) {
[self.webview goForward];
}
}
- (void)notifyWebview:(NSDictionary *) data
{
NSString *json = [WXUtility JSONString:data];
NSString *code = [NSString stringWithFormat:@"(function(){var evt=null;var data=%@;if(typeof CustomEvent==='function'){evt=new CustomEvent('notify',{detail:data})}else{evt=document.createEvent('CustomEvent');evt.initCustomEvent('notify',true,true,data)}document.dispatchEvent(evt)}())", json];
[_jsContext evaluateScript:code];
}
#pragma mark Webview Delegate
- (NSMutableDictionary *)baseInfo
{
NSMutableDictionary *info = [NSMutableDictionary new];
[info setObject:self.webview.request.URL.absoluteString ?: @"" forKey:@"url"];
[info setObject:[self.webview stringByEvaluatingJavaScriptFromString:@"document.title"] ?: @"" forKey:@"title"];
[info setObject:@(self.webview.canGoBack) forKey:@"canGoBack"];
[info setObject:@(self.webview.canGoForward) forKey:@"canGoForward"];
return info;
}
- (void)webViewDidStartLoad:(UIWebView *)webView
{
}
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
if (_finishLoadEvent) {
// [self hideHUD];
NSDictionary *data = [self baseInfo];
[self fireEvent:@"pagefinish" params:data domChanges:@{@"attrs": @{@"src":self.webview.request.URL.absoluteString}}];
}
}
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
{
if (_failLoadEvent) {
// [self showHUDText:@"加载失败" withView:self.view];
NSMutableDictionary *data = [self baseInfo];
[data setObject:[error localizedDescription] forKey:@"errorMsg"];
[data setObject:[NSString stringWithFormat:@"%ld", (long)error.code] forKey:@"errorCode"];
NSString * urlString = error.userInfo[NSURLErrorFailingURLStringErrorKey];
if (urlString) {
// webview.request may not be the real error URL, must get from error.userInfo
[data setObject:urlString forKey:@"url"];
if (![urlString hasPrefix:@"http"]) {
return;
}
}
[self fireEvent:@"error" params:data];
}
}
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
if (_startLoadEvent) {
// [self showWaitHint:@"正在加载..."];
NSMutableDictionary *data = [NSMutableDictionary new];
[data setObject:request.URL.absoluteString ?:@"" forKey:@"url"];
[self fireEvent:@"pagestart" params:data];
}
return YES;
}
@end
上面代码中特别注意- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary
这个方法中,进行了监听实时计算webview的高度,这个问题,在安卓中也是有点麻烦,需要实时计算。
这个类需要在BMConfigManager.m
中进行引用
#import "LocalWebPage.h"
需要在+ (void)registerBmComponents
这个方法里面进行注册
@"richweb": NSStringFromClass([LocalWebPage class])
注册完成之后,就可以在weex中直接使用,相当方便
return {
richwebHeight: "1"
};
mounted() {
let that = this
event.on("richWebViewHeight", function(params) {
let viewHeight = weex.config.env.deviceHeight;
let viewWidth = weex.config.env.deviceWidth;
that.richwebHeight = (params.height*750)/viewWidth
});
},
computed: {
//这块ios,其实不需要计算高度,安卓是原生获取高度,传到weex里面,然后在设置富文本的高度。
richwebStyle() {
if (weex.config.env.platform != "android") {
return {
};
} else {
return {
height: this.richwebHeight + "px"
};
}
},
}
methods: {
getFullDescriptionWap() {
if (!this.goodsDetail.fullDescriptionWap) {
return;
}
// this.goodsDetail.fullDescriptionWap= "1、加工工艺性:材料的加工工艺性直接影响到家具的生产。对于木质材料,在加工过程中,要考虑到其受水分的影响而产生的缩胀、各向异裂变性及多孔性等。塑料材料要考虑到其延展性、热塑变形等。玻璃材料要考虑到其热脆性、硬度等。
2、质地和外观质量:材料的质地和肌理决定了产品的外观质量的特殊感受。木材属于天然材料,纹理自然、美观,形象逼真,手感好,且易于加工、着色,是生产家具的上等材料。塑料及其合成材料具有模拟各种天然材料质地的特点,并且具有良好的着色性能,但其易于老化,易受热变形,用此生产家具,其使用寿命和使用范围受到限制。
3、经济性:家具材料的经济性包括材料的价格、材料的加工劳动消耗、材料的利用率及材料来源的丰富性。
4、强度:强度方面要考虑其握着力和抗劈性能及弹性模量。
5、表面装饰性能:一般情况下,表面装饰性能是指对其进行涂饰、胶贴、雕刻、着色、烫、烙等装饰的可行性。
";
// this.goodsDetail.fullDescriptionWap= "
";
// this.goodsDetail.fullDescriptionWap= "";
let temp =
'';
this.fullDescriptionWap =
temp + this.goodsDetail.fullDescriptionWap + "";
},
}
//这块ios,其实不需要计算高度,安卓是原生获取高度,传到weex里面,然后在设置富文本的高度。
在js下的config下面建一个全局的js文件,和原生进行数据传输,仅仅安卓需要或者这个高度,ios不需要
const globalEvent = weex.requireModule('globalEvent')
/**
* 监听点击安卓richWebViewHeight
*/
globalEvent.addEventListener('richWebViewHeight', async (options) => {
// console.log("richWebViewHeight",JSON.stringify(options));
event.emit("richWebViewHeight", { height: options.richWebViewHeight });
});
4、键盘弹出,覆盖输入框
问题描述:在做一个新的项目的时候,需要一个问题,IOS端,键盘弹出,页面不会跟随一起上移动,这样就导致输入框遮挡键盘的问题,这个问题需要在iOS原生里面进行修改
解决方案:
1、文件目录:/Benmu-iOS-Library/Source/BMWeexExtension/WXEditComponent+BMExtend.h
,在WXEditComponent+BMExtend.h
里面新增一个方法- (void)bmEdit_keyboardWillHide:(NSNotification*)notification;
,
,
在 WXEditComponent+BMExtend.m
里面实现这个方法
- (void)bmEdit_keyboardWillHide:(NSNotification*)notification {
if (![self.view isFirstResponder]) {
return;
}
UIView * rootView = self.weexInstance.rootView;
if (!CGRectEqualToRect(self.weexInstance.frame, rootView.frame)) {
[self setViewMovedUp:NO];
}
self.weexInstance.isRootViewFrozen = NO;
if ([[self valueForKey:@"keyboardEvent"] boolValue]) {
[self fireEvent:@"keyboard" params:@{ @"isShow": @NO }];
}
}
2、文件目录/Benmu-iOS-Library/Source/BMWeexExtension/BMMethods.m
,
在 BMMethods.m里面的exchangeWeexEditComponent方法里监听地调用这个方法
+ (void)exchangeWeexEditComponent
{
[self bm_swizzle:[WXEditComponent class] Method:@selector(setAutofocus:) withMethod:@selector(bmEdit_setAutofocus:)];
[self bm_swizzle:[WXEditComponent class] Method:@selector(initWithRef:type:styles:attributes:events:weexInstance:) withMethod:@selector(bmEdit_initWithRef:type:styles:attributes:events:weexInstance:)];
[self bm_swizzle:[WXEditComponent class] Method:@selector(viewDidLoad) withMethod:@selector(bmEdit_viewDidLoad)];
[self bm_swizzle:[WXEditComponent class] Method:@selector(keyboardWasShown:) withMethod:@selector(bmEdit_keyboardWasShown:)];
[self bm_swizzle:[WXEditComponent class] Method:@selector(keyboardWillHide:) withMethod:@selector(bmEdit_keyboardWillHide:)];
}
5、状态栏颜色的修改
问题描述:但我们使用原生的导航栏的时候,我们就会发现这个导航栏的颜色,原生的提供了2种颜色,黑色和白色。在做项目中,我们经常需要修改这个颜色。
解决方案:
文件目录:/Benmu-iOS-Library/Source/BMController/BaseVc/BMNavigationController.m
,在 BMNavigationController.m
的 - (void)setupViews
方法里设置一下:
// 设置 navigationBar 背景颜色
UIColor *setColor = [UIColor colorWithHexString:TK_PlatformInfo().page.navBarColor];
// [self.navigationBar ex_setBackgroundColor:setColor?:K_NAV_BAR_COLOR];
UIImage* image = [self createImageWithColor:setColor];
[self.navigationBar setBackgroundImage:image forBarMetrics:UIBarMetricsDefault];
[self.navigationBar setBackgroundColor:setColor];
- (UIImage *)createImageWithColor:(UIColor *)color
{
CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f);
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [color CGColor]);
CGContextFillRect(context, rect);
UIImage *theImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return theImage;
}
6、实现Tabbar一级页面全屏蒙层的透明色修改
问题描述:其实在weexUI中,提供了蒙层的的组件,但是有一个问题,就是当这个在一级页面的时候,这个蒙层不能遮挡下面的tabar按钮,这个其实是不太合理的。
解决方案:通过present的跳转方式,从下面弹出一个页面,就可以了。但是在实际开发的过程中,有一个问题,就是没有这个新的页面的怎么设置,都不能设置透明色,这块就需要在原生里面进行修改了。
在/Benmu-iOS-Library/Source/BMManager/Mediator/BMMediatorManager.m
目录中,找到这个方法- (void)_openViewControllerWithRouterModel:(BMRouterModel *)routerModel weexInstance:(WXSDKInstance *)weexInstance
,
这个方法里面有一个/* 页面展现方式 */
的判断,里面的这个宏K_ANIMATE_PRESENT
,就是判断的present跳转方式,在这块进行修改一下,设置跳转后的页面是透明色
/* 页面展现方式 */ K_ANIMATE_PRESENT
elseif ([routerModel.typeisEqualToString:K_ANIMATE_PRESENT])
{
// BMNavigationController *navc = [[BMNavigationController alloc] initWithRootViewController:controller];
// [self presentViewController:navc weexInstance:weexInstance];
controller.view.backgroundColor = [UIColor clearColor];
BMNavigationController *navc = [[BMNavigationController alloc] initWithRootViewController:controller];
navc.modalPresentationStyle = UIModalPresentationOverFullScreen;
controller.modalPresentationStyle = UIModalPresentationOverCurrentContext;
[self presentViewController:navc weexInstance:weexInstance];
}