自定义UIActivityIndicatorView

头文件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




自定义UIActivityIndicatorView

上一篇:Jetty 启动 server.join的含义


下一篇:CloudFoundry DEA staging 源码流程