头文件XDActivityIndicatorView.h
/* The MIT License (MIT) Copyright (c) 2013 SuXinDe (Email: suxinde2009@126.com) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #import <Foundation/Foundation.h> #import <UIKit/UIKit.h> #import <OpenGLES/EAGL.h> #import <OpenGLES/ES1/gl.h> #import <OpenGLES/ES1/glext.h> #import <QuartzCore/QuartzCore.h> #import <OpenGLES/EAGLDrawable.h> // 这里可以自定义的各种配置 //大小 #define mySize CGSizeMake(37, 37) //内半径 #define INRADIUS 8.0 //外半径 #define OUTRADIUS 17.0 //线宽 #define LINEWIDTH 2.5 //转动动画颜色 #define BeginR 0.0 #define BeginG 0.5 #define BeginB 1.0 //背景动画颜色 #define EndR 1.0 #define EndG 1.0 #define EndB 1.0 @interface XDActivityIndicatorView : UIView { @private // The pixel dimensions of the backbuffer GLint backingWidth; GLint backingHeight; EAGLContext *context; // OpenGL names for the renderbuffer and framebuffers used to render to this view GLuint viewRenderbuffer, viewFramebuffer; // OpenGL name for the depth buffer that is attached to viewFramebuffer, if it exists (0 if it does not exist) GLuint depthRenderbuffer; CADisplayLink * displayLink; NSInteger animationFrameInterval; GLfloat * allLineVertexs; GLfloat * allLineColors; BOOL isAnimationRunning; BOOL hidesWhenStopped; } @property BOOL hidesWhenStopped; - (void)startAnimating; - (void)stopAnimating; - (BOOL)isAnimating; @end
实现文件 XDActivityIndicatorView.mm
/* The MIT License (MIT) Copyright (c) 2013 SuXinDe (Email: suxinde2009@126.com) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #import "XDActivityIndicatorView.h" #define DEGREES_TO_RADIANS(__ANGLE) ((__ANGLE) / 180.0 * M_PI) // 11和12都是由于系统的UIActivityIndicatorView共有12条线 #define kAnimBarCount 11 // 动画显示的条数 #define kBarNumCount 12 // 总条数 @interface XDActivityIndicatorView (PrivateMethods) - (BOOL)createFramebuffer; - (void)destroyFramebuffer; - (void)drawView; - (void)commitInit; @end @implementation XDActivityIndicatorView @synthesize hidesWhenStopped; #pragma mark - Draw //创建正视图 - (void)setupView { glViewport(0,0,backingWidth,backingHeight); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrthof(0, backingWidth, 0 , backingHeight, -1, 1); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } - (void)updateColorWithIndex:(short)index { if(index<0 || index >kAnimBarCount) return; for(short i=0;i<kBarNumCount;i++,index++) { index %= kBarNumCount; //1color rgba allLineColors[index*8+0]=MIN(EndR,BeginR+(1.0/kBarNumCount)*i); allLineColors[index*8+1]=MIN(EndG,BeginG+(1.0/kBarNumCount)*i); allLineColors[index*8+2]=MIN(EndB,BeginB+(1.0/kBarNumCount)*i); allLineColors[index*8+3]=1.0; //2color rgba allLineColors[index*8+4]=MIN(EndR,BeginR+(1.0/kBarNumCount)*i); allLineColors[index*8+5]=MIN(EndG,BeginG+(1.0/kBarNumCount)*i); allLineColors[index*8+6]=MIN(EndB,BeginB+(1.0/kBarNumCount)*i); allLineColors[index*8+7]=1.0; } } //绘制 - (void)drawView { [EAGLContext setCurrentContext:context]; glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glLoadIdentity(); glPushMatrix(); glTranslatef(self.bounds.size.width/2.0,self.bounds.size.height/2.0,0.0); glColorPointer(4, GL_FLOAT,0,allLineColors); glVertexPointer(2,GL_FLOAT,0,allLineVertexs); glDrawArrays(GL_LINES,0,24); glPopMatrix(); // Display the buffer glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer); [context presentRenderbuffer:GL_RENDERBUFFER_OES]; //5帧更新动画 static short FrameCount=0; static short animCount=kAnimBarCount; FrameCount++; if(FrameCount>=5) { FrameCount=0; animCount--; if(animCount<0) animCount=kAnimBarCount; [self updateColorWithIndex:animCount]; } } #pragma mark - LifeCycle + (Class) layerClass { return [CAEAGLLayer class]; } - (void)commitInit { CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer; eaglLayer.opaque = NO; //层是透明的 // In this application, we want to retain the EAGLDrawable contents after a call to presentRenderbuffer. eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithBool:YES], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil]; context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1]; if (!context || ![EAGLContext setCurrentContext:context]) { [self release]; NSAssert(0,@"CAEAGLLayer context error!"); } animationFrameInterval=1; depthRenderbuffer=1; hidesWhenStopped=FALSE; isAnimationRunning=FALSE; //初始化opengles glClearColor(0.0,0.0,0.0,0.0); glShadeModel(GL_SMOOTH); glEnable(GL_DEPTH_TEST); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); glEnable(GL_LINE_SMOOTH); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glLineWidth(LINEWIDTH); //计算所有顶点 allLineVertexs = new GLfloat[kBarNumCount*2*2]; //12条线 24个顶点 allLineColors = new GLfloat[kBarNumCount*2*4]; //24个顶点的颜色 for(int i=0;i<kBarNumCount;i++) { GLfloat x=cosf(DEGREES_TO_RADIANS(i*30)); GLfloat y=sinf(DEGREES_TO_RADIANS(i*30)); allLineVertexs[i*4+0]=INRADIUS*x; allLineVertexs[i*4+1]=INRADIUS*y; allLineVertexs[i*4+2]=OUTRADIUS*x; allLineVertexs[i*4+3]=OUTRADIUS*y; } [self updateColorWithIndex:0]; } - (id)initWithFrame:(CGRect)frame { frame.size.width=mySize.width; frame.size.height=mySize.height; if(self = [super initWithFrame:frame]){ [self commitInit]; } return self; } - (BOOL)isAnimating { return isAnimationRunning; } -(void)startAnimating { displayLink = [NSClassFromString(@"CADisplayLink") displayLinkWithTarget:self selector:@selector(drawView)]; [displayLink setFrameInterval:animationFrameInterval]; [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; isAnimationRunning=TRUE; if(hidesWhenStopped) self.hidden=FALSE; } -(void)stopAnimating { [displayLink invalidate]; displayLink=nil; isAnimationRunning=FALSE; if(hidesWhenStopped) self.hidden=TRUE; } -(void)layoutSubviews { [EAGLContext setCurrentContext:context]; [self destroyFramebuffer]; [self createFramebuffer]; [self setupView]; } - (BOOL)createFramebuffer { // Generate IDs for a framebuffer object and a color renderbuffer glGenFramebuffersOES(1, &viewFramebuffer); glGenRenderbuffersOES(1, &viewRenderbuffer); glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer); glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer); // This call associates the storage for the current render buffer with the EAGLDrawable (our CAEAGLLayer) // allowing us to draw into a buffer that will later be rendered to screen wherever the layer is (which corresponds with our view). [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(id<EAGLDrawable>)self.layer]; glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer); glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth); glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight); if(depthRenderbuffer) { glGenRenderbuffersOES(1, &depthRenderbuffer); glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer); glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, backingWidth, backingHeight); glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer); } if(glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES){ NSLog(@"failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES)); return NO; } return YES; } // Clean up any buffers we have allocated. - (void)destroyFramebuffer { glDeleteFramebuffersOES(1, &viewFramebuffer); viewFramebuffer = 0; glDeleteRenderbuffersOES(1, &viewRenderbuffer); viewRenderbuffer = 0; if(depthRenderbuffer) { glDeleteRenderbuffersOES(1, &depthRenderbuffer); depthRenderbuffer = 0; } } #pragma mark - dealloc - (void) dealloc { [self stopAnimating]; if([EAGLContext currentContext] == context){ [EAGLContext setCurrentContext:nil]; } delete allLineVertexs; delete allLineColors; [context release]; [super dealloc]; } @end