iOS開發UIScrollView的底層實現

起始

做開發也有一段時間了,經歷了第一次完成項目的激動,也經歷了天天調用系統的API的枯燥,于是就有了探索底層實現的想法。

關于scrollView的思考

在iOS開發中我們會大量用到scrollView這個控件,我們使用的tableView/collectionview/textView都繼承自它。scrollView的頻繁使用讓我對它的底層實現產生了興趣,它到底是如何工作的?如何實現一個scrollView?讀完本篇博客,相信你一定也可以自己實現一個簡易的scrollView。

我們首先來思考以下幾個問題:

  • scrollView繼承自誰,它如何檢測到手指滑動?

  • scrollView如何實現滾動?

  • scrollView里的各種屬性是如何實現的?如contentSize/contentOffSet......

通過一步步解決上邊的問題,我們就能實現一個自己的scrollView。

一步一步實現scrollView

1.毫無疑問我們都知道scrollView繼承自UIView,檢測手指滑動應該是在view上放置了一個手勢識別,實現代碼如下:
1 - (instancetype)initWithFrame:(CGRect)frame {
2     self = [super initWithFrame:frame];
3     if (self) {
4         UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] init];
5         [panGesture addTarget:self action:@selector(panGestureAction:)];
6         [self addGestureRecognizer:panGesture];
7     }
8     return self;
9 }
2.要搞清楚第二個問題,首先我們必須理解frame和bounds的概念。

提到它們,大家都知道frame是相對于父視圖坐標系來說自己的位置和尺寸,bounds相對于自身坐標系來說的位置和尺寸,并且origin一般為(0,0)。但是bounds的origin有什么用處?改變它會出現什么效果呢?

當我們嘗試改變bounds的origin時,我們就會發現視圖本身沒有發生變化,但是它的子視圖的位置卻發生了變化,why???其實當我們改變bounds的origin的時候,視圖本身位置沒有變化,但是由于origin的值是基于自身的坐標系,所以自身坐標系的位置被我們改變了。而子視圖的frame正是基于父視圖的坐標系,當我們更改父視圖bounds中origin的時候子視圖的位置就發生了變化,這就是實現scrollView的關鍵點!!!

是不是很好理解?
基于這點我們很容易實現一個簡單的最初級版本的scrollView,代碼如下:

 1 - (void)panGestureAction:(UIPanGestureRecognizer *)pan {
 2     // 記錄每次滑動開始時的初始位置
 3     if (pan.state == UIGestureRecognizerStateBegan) {
 4         self.startLocation = self.bounds.origin;
 5         NSLog(@"%@", NSStringFromCGPoint(self.startLocation));
 6     }
 7 
 8     // 相對于初始觸摸點的偏移量
 9     if (pan.state == UIGestureRecognizerStateChanged) {
10         CGPoint point = [pan translationInView:self];
11         NSLog(@"%@", NSStringFromCGPoint(point));
12         CGFloat newOriginalX = self.startLocation.x - point.x;
13         CGFloat newOriginalY = self.startLocation.y - point.y;
14 
15         CGRect bounds = self.bounds;
16         bounds.origin = CGPointMake(newOriginalX, newOriginalY);
17         self.bounds = bounds;
18     }
19 }
3.理解了上邊內容的關鍵點,下邊我們將對我們實現的scrollView做一個簡單的優化。

通過contentSize限制scrollView的內部空間,實現代碼如下

 1 if (newOriginalX < 0) {
 2     newOriginalX = 0;
 3 } else {
 4     CGFloat maxMoveWidth = self.contentSize.width - self.bounds.size.width;
 5     if (newOriginalX > maxMoveWidth) {
 6         newOriginalX = maxMoveWidth;
 7     }
 8 }
 9 if (newOriginalY < 0) {
10     newOriginalY = 0;
11 } else {
12     CGFloat maxMoveHeight = self.contentSize.height - self.bounds.size.height;
13     if (newOriginalY > maxMoveHeight) {
14         newOriginalY = maxMoveHeight;
15     }
16 }

通過contentOffset設置scrollView的初始偏移量,相信大家已經懂了如何設置偏移量了吧?沒錯我們只需設置view自身bounds的origin是實現代碼如下:

1  - (void)setContentOffset:(CGPoint)contentOffset {
2     _contentOffset = contentOffset;
3     CGRect newBounds = self.bounds;
4     newBounds.origin = contentOffset;
5     self.bounds = newBounds;
6  }

防止scrollView的子視圖超出scrollView

?1 self.layer.masksToBounds = YES;?

總結

UIScrollView還有很多其它強大的功能,以上我們只是完成了一個特別簡單的scrollView,以后如果有時間我會對它進行完善。當然如果你有興趣,你完全可以對它進行擴展,下載地址放在這里。同時我也會繼續研究UIKit中其它控件的底層實現,歡迎您的持續關注!



文/PaulLi哥(簡書作者)
原文鏈接:http://www.jianshu.com/p/a9a1ca54ca54
著作權歸作者所有,轉載請聯系作者獲得授權,并標注“簡書作者”。

UIScrollView 實踐經驗

UIScrollView(包括它的子類?UITableView?和?UICollectionView)是 iOS 開發中最常用也是最有意思的 UI 組件,大部分 App 的核心界面都是基于三者之一或三者的組合實現。UIScrollView?是?UIKit?中為數不多能響應滑動手勢的 view,相比自己用?UIPanGestureRecognizer?實現一些基于滑動手勢的效果,用?UIScrollView?的優勢在于 bounce 和 decelerate 等特性可以讓 App 的用戶體驗與 iOS 系統的用戶體驗保持一致。本文通過一些實例講解?UIScrollView?的特性和實際使用中的經驗。

UIScrollView 和 Auto Layout

iPhone 5 剛出來的時候,大部分不支持橫屏的 App 都不需要做太多的適配工作,因為屏幕寬度沒有變,table view 多個 cell 也不需要加 code。但是在 iPhone 6 和 iPhone 6 Plus 發布以后,多分辨率適配終于不再是 Android 開發的專利了。于是,從 iOS 6 起就存在的 Auto Layout 終于有了用武之地。

關于 Auto Layout 的基本用法不再贅述,可以參考?Ray Wenderlich 上的教程(Part 2)。但?UIScrollView?在 Auto Layout 是一個很特殊的 view,對于?UIScrollView?的 subview 來說,它的 leading/trailing/top/bottom space 是相對于?UIScrollView?的 contentSize 而不是 bounds 來確定的,所以當你嘗試用?UIScrollView?和它 subview 的 leading/trailing/top/bottom 來互相決定大小的時候,就會出現「Has ambiguous scrollable content width/height」的 warning。正確的姿勢是用?UIScrollView?外部的 view 或?UIScrollView?本身的 width/height 確定 subview 的尺寸,進而確定?contentSize。因為?UIScrollView?本身的 leading/trailing/top/bottom 變得不好用,所以我習慣的做法是在?UIScrollView?和它原來的 subviews 之間增加一個 content view,這樣做的好處有:

  • 不會在 storyboard 里留下 error/warning
  • 為 subview 提供 leading/trailing/top/bottom,方便 subview 的布局
  • 通過調整 content view 的 size(可以是 constraint 的?IBOutlet)來調整?contentSize
  • 不需要 hard code 與屏幕尺寸相關的代碼
  • 更好地支持 rotation

Sample 中的?AutoLayout?演示了?UIScrollView?+ Auto Layout 的例子。

UIScrollViewDelegate

UIScrollViewDelegate?是?UIScrollView?的 delegate protocol,UIScrollView?有意思的功能都是通過它的 delegate 方法實現的。了解這些方法被觸發的條件及調用的順序對于使用?UIScrollView?是很有必要的,本文主要講拖動相關的效果,所以 zoom 相關的方法跳過不提,拖動相關的 delegate 方法按調用順序分別是:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView

這個方法在任何方式觸發?contentOffset?變化的時候都會被調用(包括用戶拖動,減速過程,直接通過代碼設置等),可以用于監控?contentOffset?的變化,并根據當前的?contentOffset?對其他 view 做出隨動調整。

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView

用戶開始拖動 scroll view 的時候被調用。

- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset

該方法從 iOS 5 引入,在 didEndDragging 前被調用,當 willEndDragging 方法中?velocity?為?CGPointZero(結束拖動時兩個方向都沒有速度)時,didEndDragging 中的?decelerate?為?NO,即沒有減速過程,willBeginDecelerating 和 didEndDecelerating 也就不會被調用。反之,當?velocity?不為?CGPointZero?時,scroll view 會以?velocity?為初速度,減速直到?targetContentOffset。值得注意的是,這里的?targetContentOffset?是個指針,沒錯,你可以改變減速運動的目的地,這在一些效果的實現時十分有用,實例章節中會具體提到它的用法,并和其他實現方式作比較。

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate

在用戶結束拖動后被調用,decelerate?為?YES?時,結束拖動后會有減速過程。注,在 didEndDragging 之后,如果有減速過程,scroll view 的 dragging 并不會立即置為?NO,而是要等到減速結束之后,所以這個 dragging 屬性的實際語義更接近 scrolling。

- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView

減速動畫開始前被調用。

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView

減速動畫結束時被調用,這里有一種特殊情況:當一次減速動畫尚未結束的時候再次 drag scroll view,didEndDecelerating 不會被調用,并且這時 scroll view 的?dragging?和?decelerating?屬性都是?YES。新的 dragging 如果有加速度,那么 willBeginDecelerating 會再一次被調用,然后才是 didEndDecelerating;如果沒有加速度,雖然 willBeginDecelerating 不會被調用,但前一次留下的 didEndDecelerating 會被調用,所以連續快速滾動一個 scroll view 時,delegate 方法被調用的順序(不含 didScroll)可能是這樣的:

scrollViewWillBeginDragging:  
scrollViewWillEndDragging: withVelocity: targetContentOffset:  
scrollViewDidEndDragging: willDecelerate:  
scrollViewWillBeginDecelerating:  
scrollViewWillBeginDragging:  
scrollViewWillEndDragging: withVelocity: targetContentOffset:  
scrollViewDidEndDragging: willDecelerate:  
scrollViewWillBeginDecelerating:  
...
scrollViewWillBeginDragging: scrollViewWillEndDragging: withVelocity: targetContentOffset: scrollViewDidEndDragging: willDecelerate: scrollViewWillBeginDecelerating: scrollViewDidEndDecelerating: 

雖然很少有因為這個導致的 bug,但是你需要知道這種很常見的用戶操作會導致的中間狀態。例如你嘗試在?UITableViewDataSource?的?tableView:cellForRowAtIndexPath:?方法中基于 tableView 的 dragging 和 decelerating 屬性判斷是在用戶拖拽還是減速過程中的話可能會誤判(見例 1)。

Sample 中的?Delegate?簡單輸出了一些 Log,你可以快速了解這些方法的調用順序。

實例

下面通過一些實例,更詳細地演示和描述以上各 delegate 方法的用途。

1. Table View 中圖片加載邏輯的優化

雖然這種優化方式在現在的機能和網絡環境下可能看似不那么必要,但在我最初看到這個方法是的 09 年(印象中是 Tweetie 作者在 08 年寫的 Blog,可能有誤),遙想 iPhone 3G/3GS 的機能,這個方法為多圖的 table view 的性能帶來很大的提升,也成了我的秘密武器。而現在,在移動網絡環境下,你依然值得這么做來為用戶節省流量。

先說一下原文的思路:

  • 當用戶手動 drag table view 的時候,會加載 cell 中的圖片;
  • 在用戶快速滑動的減速過程中,不加載過程中 cell 中的圖片(但文字信息還是會被加載,只是減少減速過程中的網絡開銷和圖片加載的開銷);
  • 在減速結束后,加載所有可見 cell 的圖片(如果需要的話);

問題 1:

前面提到,剛開始拖動的時候,dragging?為?YESdecelerating?為?NO;decelerate 過程中,dragging?和?decelerating?都為?YES;decelerate 未結束時開始下一次拖動,dragging?和?decelerating?依然都為?YES。所以無法簡單通過 table view 的?dragging?和?decelerating?判斷是在用戶拖動還是減速過程。

解決這個問題很簡單,添加一個變量如?userDragging,在 willBeginDragging 中設為?YES,didEndDragging 中設為?NO。那么?tableView: cellForRowAtIndexPath:?方法中,是否 load 圖片的邏輯就是:

if (!self.userDragging && tableView.decelerating) {  cell.imageView.image = nil; } else { // code for loading image from network or disk } 

問題 2:

這么做的話,decelerate 結束后,屏幕上的 cell 都是不帶圖片的,解決這個問題也不難,你需要一個形如?loadImageForVisibleCells?的方法,加載可見 cell 的圖片:

- (void)loadImageForVisibleCells
{NSArray *cells = [self.tableView visibleCells];for (GLImageCell *cell in cells) { NSIndexPath *indexPath = [self.tableView indexPathForCell:cell]; [self setupCell:cell withIndexPath:indexPath]; } } 

問題 3:

這個問題可能不容易被發現,在減速過程中如果用戶開始新的拖動,當前屏幕的 cell 并不會被加載(前文提到的調用順序問題導致),而且問題 1 的方案并不能解決問題 3,因為這些 cell 已經在屏上,不會再次經過 cellForRowAtIndexPath 方法。雖然不容易發現,但解決很簡單,只需要在?scrollViewWillBeginDragging:?方法里也調用一次?loadImageForVisibleCells?即可。

再優化

上述方法在那個年代的確提升了 table view 的 performance,但是你會發現在減速過程最后最慢的那零點幾秒時間,其實還是會讓人等得有些心急,尤其如果你的 App 只有圖片沒有文字。在 iOS 5 引入了?scrollViewWillEndDragging: withVelocity: targetContentOffset:?方法后,配合?SDWebImage,我嘗試再優化了一下這個方法以提升用戶體驗:

  • 如果內存中有圖片的緩存,減速過程中也會加載該圖片
  • 如果圖片屬于?targetContentOffset?能看到的 cell,正常加載,這樣一來,快速滾動的最后一屏出來的的過程中,用戶就能看到目標區域的圖片逐漸加載
  • 你可以嘗試用類似 fade in 或者 flip 的效果緩解生硬的突然出現(尤其是像本例這樣只有圖片的 App)

核心代碼:

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{self.targetRect = nil; [self loadImageForVisibleCells]; } - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset { CGRect targetRect = CGRectMake(targetContentOffset->x, targetContentOffset->y, scrollView.frame.size.width, scrollView.frame.size.height); self.targetRect = [NSValue valueWithCGRect:targetRect]; } - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { self.targetRect = nil; [self loadImageForVisibleCells]; } 

是否需要加載圖片的邏輯:

BOOL shouldLoadImage = YES;  
if (self.targetRect && !CGRectIntersectsRect([self.targetRect CGRectValue], cellFrame)) { SDImageCache *cache = [manager imageCache]; NSString *key = [manager cacheKeyForURL:targetURL]; if (![cache imageFromMemoryCacheForKey:key]) { shouldLoadImage = NO; } } if (shouldLoadImage) { // load image } 

更值得高興的是,通過判斷是否?niltargetRect?同時起到了原來?userDragging?的作用。本例完整的代碼見 Sample 中的?LazyLoad

LazyLoad

2. 分頁的幾種實現方式

利用 UIScrollView 有多種方法實現分頁,但是各自的效果和用途不盡相同,其中方法 2 和方法 3 的區別也正是一些同類 App 在模仿 Glow 的首頁 Bubble 翻轉效果時跟 Glow 體驗上的的差距所在(但愿他們不會看到本文并且調整他們的實現方式)。本例通過三種方法實現相似的一個場景,你可以通過安裝到手機上來感受三種實現方式的不同用戶體驗。為了區分每個例子的重點,本例沒有重用機制,重用相關內容見例 3。

2.1 pagingEnabled

這是系統提供的分頁方式,最簡單,但是有一些局限性:

  • 只能以 frame size 為單位翻頁,減速動畫阻尼大,減速過程不超過一頁
  • 需要一些 hacking 實現 bleeding 和 padding(即頁與頁之間有 padding,在當前頁可以看到前后頁的部分內容)

Sample 中?Pagination?有簡單實現 bleeding 和 padding 效果的代碼,主要的思路是:

  • 讓 scroll view 的寬度為 page 寬度 + padding,并且設置?clipsToBounds?為?NO
  • 這樣雖然能看到前后頁的內容,但是無法響應 touch,所以需要另一個覆蓋期望的可觸摸區域的 view 來實現類似 touch bridging 的功能

適用場景:上述局限性同時也是這種實現方式的優點,比如一般 App 的引導頁(教程),Calendar 里的月視圖,都可以用這種方法實現。

pagingEnabled

2.2 Snap

這種方法就是在 didEndDragging 且無減速動畫,或在減速動畫完成時,snap 到一個整數頁。核心算法是通過當前 contentOffset 計算最近的整數頁及其對應的 contentOffset,通過動畫 snap 到該頁。這個方法實現的效果都有個通病,就是最后的 snap 會在 decelerate 結束以后才發生,總感覺很突兀。

2.3 修改 targetContentOffset

通過修改?scrollViewWillEndDragging: withVelocity: targetContentOffset:?方法中的?targetContentOffset?直接修改目標 offset 為整數頁位置。其中核心代碼:

- (CGPoint)nearestTargetOffsetForOffset:(CGPoint)offset
{CGFloat pageSize = BUBBLE_DIAMETER + BUBBLE_PADDING;NSInteger page = roundf(offset.x / pageSize); CGFloat targetX = pageSize * page; return CGPointMake(targetX, offset.y); } - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset { CGPoint targetOffset = [self nearestTargetOffsetForOffset:*targetContentOffset]; targetContentOffset->x = targetOffset.x; targetContentOffset->y = targetOffset.y; } 

適用場景:方法 2 和 方法 3 的原理近似,效果也相近,適用場景也基本相同,但方法 3 的體驗會好很多,snap 到整數頁的過程很自然,或者說用戶完全感知不到 snap 過程的存在。這兩種方法的減速過程流暢,適用于一屏有多頁,但需要按整數頁滑動的場景;也適用于如圖表中自動 snap 到整數天的場景;還適用于每頁大小不同的情況下 snap 到整數頁的場景(不做舉例,自行發揮,其實只需要修改計算目標 offset 的方法)。

完整代碼參見?Pagination

targetContentOffset

3. 重用

大部分的 iOS 開發應該都清楚?UITableView?的 cell 重用機制,這種重用機制減少了內存開銷也提高了 performance,UIScrollView?作為?UITableView?的父類,在很多場景中也很適合應用重用機制(其實不只是?UIScrollView,任何場景中會反復出現的元素都應該適當地引入重用機制)。

你可以參照?UITableView?的 cell 重用機制,總結重用機制如下:

  • 維護一個重用隊列
  • 當元素離開可見范圍時,removeFromSuperview?并加入重用隊列(enqueue)
  • 當需要加入新的元素時,先嘗試從重用隊列獲取可重用元素(dequeue)并且從重用隊列移除
  • 如果隊列為空,新建元素
  • 這些一般都在?scrollViewDidScroll:?方法中完成

實際使用中,需要注意的點是:

  • 當重用對象為 view controller 時,記得?addChildeViewController
  • 當 view 或 view controller 被重用但其對應 model 發生變化的時候,需要及時清理重用前留下的內容
  • 數據可以適當做緩存,在重用的時候嘗試從緩存中讀取數據甚至之前的狀態(如 table view 的 contentOffset),以得到更好的用戶體驗
  • 當 on screen 的元素數量可確定的時候,有時候可以提前 init 這些元素,不會在 scroll 過程中遇到因為 init 開銷帶來的卡頓(尤其是以 view controller 為重用對象的時候)

例 2 中的場景很適合以 view 為重用單位,本例新增一個以 view controller 為重用對象的例子,該例子同時演示了聯動效果,具體見下個例子。

完整代碼參見?Reuse

Reuse

4. 聯動/視差滾動

上一個例子里 main scroll view 和 title view 里的 scroll view 就是一個聯動的例子,所謂聯動,就是當 A 滾動的時候,在?scrollViewDidScroll:?里根據 A 的?contentOffset?動態計算 B 的?contentOffset?并設給 B。同樣對于非 scroll view 的 C,也可以動態計算 C 的 frame 或是 transform(Glow 的氣泡為例)實現視差滾動或者其他高級動畫,這在現在許多應用的引導頁面里會被用到。

聯動/視差滾動部分原理上其實比較簡單,不再贅述,寫了個簡單的例子?Parallax。

Parallax

寫在最后

不知不覺就寫了很多關于?UIScrollView?的內容,其實還有很多可寫,由于時間關系只好停筆。在我看來,UIScrollView?就好像提供了一個跳脫二維空間束縛的途徑,如果你有足夠的想象力,它能幫你實現更豐富的跳出平面束縛的用戶體驗。本來還準備寫一個綜合性的例子,但是由于時間關系還沒完成,后面有時間會繼續更新。

此外,例子中可能會有錯誤或可以改進的地方,歡迎在?GitHub?直接提 Issue 或 PR。

轉自:http://tech.glowing.com/cn/

轉載于:https://www.cnblogs.com/oc-bowen/p/5953194.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/394908.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/394908.shtml
英文地址,請注明出處:http://en.pswp.cn/news/394908.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

oracle查看登錄時間黑屏,oracle 11g默認用戶名、密碼解鎖 以及安裝后重啟黑屏問題.doc...

oracle 11g默認用戶名、密碼解鎖 以及安裝后重啟黑屏問題.doc還剩3頁未讀&#xff0c;繼續閱讀下載文檔到電腦&#xff0c;馬上遠離加班熬夜&#xff01;親&#xff0c;喜歡就下載吧&#xff0c;價低環保&#xff01;內容要點&#xff1a;遇的同學&#xff0c;參考一下解決辦法…

第六十二節,html分組元素

html分組元素 學習要點&#xff1a; 1.分組元素總匯 2.分組元素解析 本章主要探討HTML5中分組元素的用法。所謂分組&#xff0c;就是用來組織相關內容的HTML5元素&#xff0c;清晰有效的進行歸類。 一&#xff0e;分組元素總匯 為了頁面的排版需要&#xff0c;HTML5提供了幾種語…

WebSocket 實戰--轉

原文地址&#xff1a;http://www.ibm.com/developerworks/cn/java/j-lo-WebSocket/ WebSocket 前世今生 眾所周知&#xff0c;Web 應用的交互過程通常是客戶端通過瀏覽器發出一個請求&#xff0c;服務器端接收請求后進行處理并返回結果給客戶端&#xff0c;客戶端瀏覽器將信息呈…

python圖形化編程更改內部參數_python-參數化-(3)(替換數據)

一.在讀取excel文件、其他數據來源會遇到一些無法轉換或者特殊標記的字符串等&#xff0c;不能直接使用。這時候需要對數據進行處理&#xff0c;替換為自己需要的數據進行下一步操作&#xff0c;如下&#xff1a; 替換 1.replace() str.replace(old,new[,max]) old -- 將被替換…

css grid布局_如何使用CSS Grid重新創建Medium的文章布局

css grid布局When people think of CSS Grid they normally envision image grid layouts and full web pages. However, CSS Grid is actually a superb technology for laying out articles as well, as it allows you to do things which previously was tricky to achieve.…

2017視頻監控行業應用趨勢與市場發展分析

安防行業的發展&#xff0c;從傳統單一的業務形態到業務多元化與國際化的轉變&#xff0c;是社會安全需求變化與視頻監控技術雙向驅動的結果。在新的行業生態體系下&#xff0c;傳統監控技術與新興技術的融合&#xff0c;跨行業的業務協同&#xff0c;以及以客戶為中心的產業形…

oracle 11.2.4聯機文檔,ORACLE 11G 聯機文檔partition_extended_name的一個錯誤

在看11G聯機文檔的PARTITION EXTENDED NAME限制的時候&#xff0c;測試發現與書上描述不符。Restrictions on Extended Names Currently, the use of partition-extended and subpartition-extended table names has the following restrictions:No remote tables: A partition…

mongodb 安裝、啟動

MongoDB 之 你得知道MongoDB是個什么鬼 MongoDB - 1 最近有太多的同學向我提起MongoDB,想要學習MongoDB,還不知道MongoDB到底是什么鬼,或者說,知道是數據庫,知道是文件型數據庫,但是不知道怎么來用 那么好,所謂千呼萬喚始出來,現在我就拉給你們看: 一.初識MongoDB 之 什么東西都…

python os path_python os.path模塊

os.path.abspath(path) #返回絕對路徑 os.path.basename(path) #返回文件名 os.path.commonprefix(list) #返回list(多個路徑)中&#xff0c;所有path共有的最長的路徑。 os.path.dirname(path) #返回文件路徑 os.path.exists(path) #路徑存在則返回True,路徑損壞返回False os.…

[轉載]PSCAD調用MATLAB/SIMULINK之接口元件設計

原文地址&#xff1a;PSCAD調用MATLAB/SIMULINK之接口元件設計作者&#xff1a;luckyhappier1)接口元件 接口元件包括Graphics&#xff0c;Parameters和Script。注意&#xff1a;變量要與DSDYN要一致&#xff08;PSCAD根據變量名區別變量&#xff09;。 2&#xff09;Circuit 定…

css flexbox模型_Flexbox教程:了解如何使用CSS Flexbox編寫響應式導航欄

css flexbox模型In this article, I’ll explain how to create a navbar which adapts to various screen sizes using Flexbox along with media queries.在本文中&#xff0c;我將解釋如何使用Flexbox和媒體查詢來創建適應各種屏幕尺寸的導航欄。 This tutorial can also b…

oracle數字類型ef映射,Entity Framework 學習中級篇5—使EF支持Oracle9i - ♂風車車.Net - 博客園...

從Code MSDN上下載下來的EFOracleProvider不支持Oracle9i.但是,目前我所使用的還是Oracle9i。為此,對EFOracleProvider修改了以下&#xff0c;以便使其支持Oracle9i.下面說說具體修改地方.(紅色部分為添加或修改的代碼部分)一&#xff0c;修改EFOracleProvider1,修改EFOraclePr…

Oracle 數據庫之最:你見過最高的 SQL Version 是多少?

Oracle數據庫中執行的SQL&#xff0c;很多時候會因為種種原因產生多個不同的執行版本&#xff0c;一個游標的版本過多很容易引起數據庫的性能問題&#xff0c;甚至故障。 有時候一個SQL的版本數量可能多達數萬個&#xff0c;以下是我之前在"云和恩墨大講堂”分享過的一個案…

mybatis傳參問題總結

一、 傳入單個參數 當傳入的是單個參數時&#xff0c;方法中的參數名和sql語句中參數名一致即可 List<User> getUser(int id);<select id"getUser" parameterType"java.lang.Integer" resultType"com.lee.test.pojo.User">select *…

C 怎么讀取Cpp文件_opencv從yaml文件中讀取矩陣(c++)

PS:由于我是新手&#xff0c;因此記錄的比較羅里吧嗦&#xff0c;本文也屬于一個沒有任何技術的編程積累。在SLAM系統中&#xff0c;經常需要從配置文件中讀取參數文件&#xff0c;讀取整型&#xff0c;浮點型都是比較常見的操作&#xff0c;在讀取矩陣卡了一下&#xff0c;記錄…

oracle中的判斷大小,sql語句判斷大小

如何用sql語句查看某個數據庫中的表的大小--讀取庫中的所有表名select name from sysobjects where xtypeu--讀取指定表的所有列名select name from syscolumns where id(select max(id) from sysobjects where xtypeu and name表名)獲取數據庫表名和字段sqlserver中各個系統表…

超越Android:探索Kotlin的應用領域

by Adam Arold亞當阿羅德(Adam Arold) 超越Android&#xff1a;探索Kotlin的應用領域 (Going beyond Android: exploring Kotlin’s areas of application) If you have written something in Kotlin, chances are that you wrote it for Android. Kotlin, however, has other…

3.SFB標準版前端安裝

SFB服務器準備部分&#xff1a;1.修改服務器名稱&#xff0c;sfb加入域&#xff0c;用域管理員賬戶登錄2.配置服務器IP地址&#xff0c;DNS3.安裝Windows組件Add-WindowsFeature NET-Framework-Core, RSAT-ADDS, Windows-Identity-Foundation, Web-Server, Web-Static-Content,…

向spark standalone集群提交任務

文檔鏈接 #切換到spark安裝目錄,執行下面一條命令,192.168.0.10是master的ip, examples/src/main/python/pi.py 是python 文件的路徑 ./bin/spark-submit --master spark://192.168.0.106:7077 examples/src/main/python/pi.py任務已經執行完畢,耗時10秒 轉載于:https://www.c…

SQLite學習手冊

一、聚合函數&#xff1a; SQLite中支持的聚合函數在很多其他的關系型數據庫中也同樣支持&#xff0c;因此我們這里將只是給出每個聚集函數的簡要說明&#xff0c;而不在給出更多的示例了。這里還需要進一步說明的是&#xff0c;對于所有聚合函數而言&#xff0c;distinct關鍵字…