标签:orb void center lse phi 特效 决定 char user
控件可以添加文本段列表,每段文本可以设置出现动画和文字渐变颜色,还可以让指定某一段文本重复播放指定的次数。
///
/// 文本跑马灯特效控件
///
[ToolboxItem(true)]
[DefaultProperty("Items")]
[Description("文本跑马灯特效控件")]
public partial class TextCarouselExt : Control
{
public delegate void IndexEventHandler(object sender, IndexEventArgs e);
#region
private event IndexEventHandler indexChanged;
///
/// 当前正在播放文本选项索引更改事件
///
[Description("当前正在播放文本选项索引更改事件")]
public event IndexEventHandler IndexChanged
{
add { this.indexChanged += value; }
remove { this.indexChanged -= value; }
}
private bool active = false;
///
/// 文本轮播激活状态
///
[DefaultValue(false)]
[Description("文本轮播激活状态")]
public bool Active
{
get { return this.active; }
set
{
if (this.active == value)
return;
this.active = value;
this.intervalTimer.Enabled = value;
}
}
private int intervalTime = 100;
///
/// 文本选项轮播的时间间隔
///
[DefaultValue(100)]
[Description("文本选项轮播的时间间隔(默认100毫秒)")]
public int IntervalTime
{
get { return this.intervalTime; }
set
{
if (this.intervalTime == value)
return;
this.intervalTime = value;
}
}
int currentIndex = -1;
///
///当前正在播放文本选项索引
///
[Browsable(false)]
[DefaultValue(-1)]
[Description("当前正在播放文本选项索引")]
public int CurrentIndex
{
get { return this.currentIndex; }
set
{
if (this.currentIndex == value)
return;
this.currentIndex = value;
if (this.indexChanged != null)
this.indexChanged(this, new IndexEventArgs() { Index = this.currentIndex, Item = this.Items[this.currentIndex] });
}
}
private TextItemCollection textItemCollection;
///
/// 文本选项集合
///
[DefaultValue(null)]
[Description("文本选项集合")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public TextItemCollection Items
{
get
{
if (this.textItemCollection == null)
this.textItemCollection = new TextItemCollection(this);
return this.textItemCollection;
}
}
[Editor(typeof(ColorEditorExt), typeof(System.Drawing.Design.UITypeEditor))]
public override Color BackColor
{
get
{
return base.BackColor;
}
set
{
base.BackColor = value;
}
}
protected override Size DefaultSize
{
get
{
return new Size(300, 60);
}
}
///
/// 文本选项轮播的时间间隔累计(-1为动画正在切换中)(-2出现后停留中)
///
private int intervalTimeValue = 0;
///
/// 文本选项播放时间间隔定时器
///
private Timer intervalTimer;
///
/// 文本选项出现后停留时间累计
///
private int remainTimeValue = 0;
///
/// 动画播放定时器
///
private AnimationTimer animationTimer;
#endregion
public TextCarouselExt()
{
SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
SetStyle(ControlStyles.ResizeRedraw, true);
SetStyle(ControlStyles.SupportsTransparentBackColor, true);
InitializeComponent();
this.InitializeTextRectangles();
this.intervalTimer = new Timer();
this.intervalTimer.Interval = 50;
this.intervalTimer.Tick += new EventHandler(this.intervalTimer_Tick);
this.animationTimer = new AnimationTimer(this, new AnimationOptions());
this.animationTimer.AnimationIng += new AnimationTimer.AnimationHandel(this.animationTimer_AnimationIng);
this.animationTimer.AnimationEnding += new AnimationTimer.AnimationHandel(this.animationTimer_AnimationEnding);
}
#region 重写
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
if (this.Items.Count 0 || this.CurrentIndex 0)
return;
Graphics g = e.Graphics;
TextItem textItem = this.Items[this.CurrentIndex];
#region Scroll
if (textItem.Way == AnimationWay.Scroll)
{
if (textItem.TextColorItems.Count 1)
{
SolidBrush text_sb = new SolidBrush(textItem.TextColor);
g.DrawString(textItem.Text, textItem.TextFont, text_sb, textItem.current_rectf);
text_sb.Dispose();
}
else
{
int len = Math.Max(textItem.TextColorItems.Count, 2);
Color[] colors = new Color[len];
float[] interval = new float[len];
for (int i = 0; i )
{
colors[i] = textItem.TextColorItems[i].ShadeColor;
interval[i] = textItem.TextColorItems[i].Shade;
}
if (textItem.TextColorItems.Count == 1)
{
colors[1] = textItem.TextColorItems[0].ShadeColor;
interval[1] = textItem.TextColorItems[0].Shade;
}
//Positions开始值必须为0,结束值必须为1
interval[0] = 0.0f;
interval[textItem.TextColorItems.Count - 1] = 1.0f;
LinearGradientBrush text_lgb = new LinearGradientBrush(textItem.current_rectf, Color.Transparent, Color.Transparent, textItem.ShadeAngle);
text_lgb.InterpolationColors = new ColorBlend() { Colors = colors, Positions = interval };
g.DrawString(textItem.Text, textItem.TextFont, text_lgb, textItem.current_rectf);
text_lgb.Dispose();
}
}
#endregion
#region Speed SpeedSpringback
else if (textItem.Way == AnimationWay.Speed || textItem.Way == AnimationWay.SpeedSpringback)
{
if (textItem.TextColorItems.Count 1)
{
SolidBrush text_sb = new SolidBrush(textItem.TextColor);
for (int i = 0; i )
{
g.DrawString(textItem.TextChar[i], textItem.TextFont, text_sb, textItem.current_char_rectf[i]);
}
text_sb.Dispose();
}
else
{
int len = Math.Max(textItem.TextColorItems.Count, 2);
Color[] colors = new Color[len];
float[] interval = new float[len];
RectangleF text_lgb_rectf = new RectangleF(textItem.current_char_rectf[0].X, textItem.current_char_rectf[0].Y, textItem.current_char_rectf[textItem.TextChar.Length - 1].Right, textItem.current_char_rectf[0].Height);
LinearGradientBrush text_lgb = new LinearGradientBrush(text_lgb_rectf, Color.Transparent, Color.Transparent, textItem.ShadeAngle);
for (int k = 0; k )
{
for (int i = 0; i )
{
colors[i] = textItem.TextColorItems[i].ShadeColor;
interval[i] = textItem.TextColorItems[i].Shade;
}
if (textItem.TextColorItems.Count == 1)
{
colors[1] = textItem.TextColorItems[0].ShadeColor;
interval[1] = textItem.TextColorItems[0].Shade;
}
//Positions开始值必须为0,结束值必须为1
interval[0] = 0.0f;
interval[textItem.TextColorItems.Count - 1] = 1.0f;
text_lgb.InterpolationColors = new ColorBlend() { Colors = colors, Positions = interval };
g.DrawString(textItem.TextChar[k], textItem.TextFont, text_lgb, textItem.current_char_rectf[k]);
}
text_lgb.Dispose();
}
#endregion
}
}
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
this.InitializeTextRectangles();
}
#endregion
#region 动画
///
/// 动画开始事件
///
///
///
private void intervalTimer_Tick(object sender, EventArgs e)
{
#region 第一步检查动画是否为进行中
if (this.intervalTimeValue == -1)//动画进行中
return;
#endregion
#region 第二步检查文本是否为动画完成后停留中
if (this.intervalTimeValue == -2)//停留中
{
this.remainTimeValue += this.intervalTimer.Interval;
if (this.remainTimeValue this.Items[this.CurrentIndex].RemainTime * 1000)
{
return;
}
this.remainTimeValue = 0;
this.intervalTimeValue = 0;
}
#endregion
#region 第三步检查是否要进行重复播放
if (this.CurrentIndex > -1)
{
this.Items[this.CurrentIndex].CurrentRepetition += 1;
if (this.Items[this.CurrentIndex].CurrentRepetition this.Items[this.CurrentIndex].Repetition)
{
goto DH;
}
else
{
this.Items[this.CurrentIndex].CurrentRepetition = 0;
}
}
#endregion
#region 第四步检查下一个文本选项是否禁用,禁用则跳到下下一个文本选项
int index = this.CurrentIndex + 1;
if (index > this.Items.Count - 1)
{
index -= this.Items.Count;
}
if (!this.Items[index].Enabled)
{
this.CurrentIndex++;
if (this.CurrentIndex > this.Items.Count - 1)
{
this.CurrentIndex -= this.Items.Count;
}
}
#endregion
#region 第五步检查是否是时间进入下一个文本选项动画播放
this.intervalTimeValue += this.intervalTimer.Interval;
if (this.intervalTimeValue this.IntervalTime)
{
return;
}
this.intervalTimeValue = -1;
this.CurrentIndex++;
if (this.CurrentIndex > this.Items.Count - 1)
{
this.CurrentIndex -= this.Items.Count;
}
#endregion
#region 播放动画
DH:
TextItem textItem = this.Items[this.CurrentIndex];
this.animationTimer.Options.Data = textItem;
if (textItem.Way == AnimationWay.Scroll)
{
this.animationTimer.AT = AnimationType.UniformMotion;
this.animationTimer.Options.Power = 3;
this.animationTimer.Options.AllTime = 100f * (textItem.Orientation == AnimationOrientation.Right ? (float)textItem.prev_rectf.Width : (float)textItem.prev_rectf.Height);//动画时间由文字长度决定,速度为每个像素使用50毫秒
}
else if (textItem.Way == AnimationWay.Speed)
{
this.animationTimer.AT = AnimationType.EaseOut;
this.animationTimer.Options.AllTime = textItem.TextChar.Length * 100;
this.animationTimer.Options.AllTime = 1000d;
}
else if (textItem.Way == AnimationWay.SpeedSpringback)
{
this.animationTimer.AT = AnimationType.BackOut;
this.animationTimer.Options.Power = 1;
this.animationTimer.Options.AllTime = 1000d;
}
this.animationTimer.Start(true, 0);
#endregion
}
///
/// 动画进行中事件
///
///
///
protected void animationTimer_AnimationIng(object sender, AnimationEventArgs e)
{
TextItem textItem = (TextItem)e.Data;
if (textItem.Way == AnimationWay.Scroll)
{
float x = textItem.prev_rectf.X;
float y = textItem.prev_rectf.Y;
if (textItem.Orientation == AnimationOrientation.Top || textItem.Orientation == AnimationOrientation.Bottom)
{
y = textItem.prev_rectf.Y + (float)((textItem.target_rectf.Y - textItem.prev_rectf.Y) * e.progressTime);
}
else if (textItem.Orientation == AnimationOrientation.Right)
{
x = textItem.prev_rectf.X + (float)((textItem.target_rectf.X - textItem.prev_rectf.X) * e.progressTime);
}
textItem.current_rectf = new RectangleF(x, y, textItem.prev_rectf.Width, textItem.prev_rectf.Height);
}
else if (textItem.Way == AnimationWay.Speed)
{
for (int i = 0; i )
{
float x = textItem.prev_char_rectf[i].X;
float y = textItem.prev_char_rectf[i].Y;
if (textItem.Orientation == AnimationOrientation.Top || textItem.Orientation == AnimationOrientation.Bottom)
{
y = textItem.prev_char_rectf[i].Y + (float)((textItem.target_char_rectf[i].Y - textItem.prev_char_rectf[i].Y) * e.progressTime);
}
else if (textItem.Orientation == AnimationOrientation.Right)
{
x = textItem.prev_char_rectf[i].X + (float)((textItem.target_char_rectf[i].X - textItem.prev_char_rectf[i].X) * e.progressTime);
}
textItem.current_char_rectf[i] = new RectangleF(x, y, textItem.prev_char_rectf[i].Width, textItem.prev_char_rectf[i].Height);
}
}
else if (textItem.Way == AnimationWay.SpeedSpringback)
{
for (int i = 0; i )
{
float x = textItem.prev_char_rectf[i].X;
float y = textItem.prev_char_rectf[i].Y;
if (textItem.Orientation == AnimationOrientation.Top || textItem.Orientation == AnimationOrientation.Bottom)
{
y = textItem.prev_char_rectf[i].Y + (float)((textItem.target_char_rectf[i].Y - textItem.prev_char_rectf[i].Y) * e.progressTime);
}
else if (textItem.Orientation == AnimationOrientation.Right)
{
x = textItem.prev_char_rectf[i].X + (float)((textItem.target_char_rectf[i].X - textItem.prev_char_rectf[i].X) * e.progressTime);
}
textItem.current_char_rectf[i] = new RectangleF(x, y, textItem.prev_char_rectf[i].Width, textItem.prev_char_rectf[i].Height);
}
}
this.Invalidate();
}
///
/// 动画结束时事件
///
///
///
protected void animationTimer_AnimationEnding(object sender, AnimationEventArgs e)
{
this.intervalTimeValue = -2;
}
#endregion
#region 私有
///
/// 初始化播放前每一段文本rect
///
private void InitializeTextRectangles()
{
for (int i = 0; i this.Items.Count; i++)
{
this.InitializeTextRectangle(this.Items[i]);
}
}
///
/// 初始化文本rect
///
///
private void InitializeTextRectangle(TextItem textItem)
{
Rectangle rect = this.ClientRectangle;
Size text_size = TextRenderer.MeasureText(textItem.Text, textItem.TextFont, new Size(), TextFormatFlags.ExternalLeading);
int len = textItem.Text.Length;
int avg_w = len == 0 ? 0 : text_size.Width / len;
#region Scroll
if (textItem.Way == AnimationWay.Scroll)
{
float x = 0;
float y = 0;
float target_x = 0;
float target_y = 0;
if (textItem.Orientation == AnimationOrientation.Top)
{
x = rect.X;
if (textItem.TextCenter)
{
x = rect.X + (rect.Width - text_size.Width) / 2;
if (x rect.X)
x = rect.X;
}
y = rect.Y - text_size.Height;
target_x = x;
target_y = rect.Bottom + text_size.Height;
}
else if (textItem.Orientation == AnimationOrientation.Bottom)
{
x = rect.X;
if (textItem.TextCenter)
{
x = rect.X + (rect.Width - text_size.Width) / 2;
if (x rect.X)
x = rect.X;
}
y = rect.Bottom;
target_x = x;
target_y = rect.Y - text_size.Height;
}
else if (textItem.Orientation == AnimationOrientation.Right)
{
x = rect.Right;
y = (rect.Height - text_size.Height) / 2;
target_x = rect.X - text_size.Width;
target_y = y;
}
textItem.prev_rectf = new RectangleF(x, y, text_size.Width, text_size.Height);
textItem.current_rectf = textItem.prev_rectf;
textItem.target_rectf = new RectangleF(target_x, target_y, text_size.Width, text_size.Height);
}
#endregion
#region Speed
else if (textItem.Way == AnimationWay.Speed)
{
textItem.TextCharAvgWidth = text_size.Width / len;
textItem.TextChar = new string[len];
textItem.prev_char_rectf = new RectangleF[len];
textItem.current_char_rectf = new RectangleF[len];
textItem.target_char_rectf = new RectangleF[len];
for (int i = 0; i )
{
float x = 0;
float y = 0;
float target_x = 0;
float target_y = 0;
if (textItem.Orientation == AnimationOrientation.Top)
{
float tmp_x = rect.X + i * avg_w;
x = tmp_x;
if (textItem.TextCenter)
{
x = tmp_x + (rect.Width - text_size.Width) / 2;
if (x tmp_x)
x = tmp_x;
}
y = rect.Y - i * text_size.Height;
target_x = x;
target_y = (rect.Height - text_size.Height) / 2;
}
else if (textItem.Orientation == AnimationOrientation.Bottom)
{
float tmp_x = rect.X + i * avg_w;
x = tmp_x;
if (textItem.TextCenter)
{
x = tmp_x + (rect.Width - text_size.Width) / 2;
if (x tmp_x)
x = tmp_x;
}
y = rect.Bottom + i * text_size.Height;
target_x = x;
target_y = (rect.Height - text_size.Height) / 2;
}
else if (textItem.Orientation == AnimationOrientation.Right)
{
x = rect.Right + i * rect.Width;
y = (rect.Height - text_size.Height) / 2;
target_x = rect.X + i * avg_w;
target_y = y;
}
textItem.TextChar[i] = textItem.Text.Substring(i, 1);
textItem.prev_char_rectf[i] = new RectangleF(x, y, avg_w, text_size.Height);
textItem.current_char_rectf[i] = textItem.prev_char_rectf[i];
textItem.target_char_rectf[i] = new RectangleF(target_x, target_y, avg_w, text_size.Height);
}
}
#endregion
#region SpeedSpringback
else if (textItem.Way == AnimationWay.SpeedSpringback)
{
textItem.TextCharAvgWidth = text_size.Width / len;
textItem.TextChar = new string[len];
textItem.prev_char_rectf = new RectangleF[len];
textItem.current_char_rectf = new RectangleF[len];
textItem.target_char_rectf = new RectangleF[len];
for (int i = 0; i )
{
float x = 0;
float y = 0;
float target_x = 0;
float target_y = 0;
if (textItem.Orientation == AnimationOrientation.Top)
{
float tmp_x = rect.X + i * avg_w;
x = tmp_x;
if (textItem.TextCenter)
{
x = tmp_x + (rect.Width - text_size.Width) / 2;
if (x tmp_x)
x = tmp_x;
}
y = rect.Y - text_size.Height - text_size.Height - text_size.Height / 2;
target_x = x;
target_y = (rect.Height - text_size.Height) / 2;
}
else if (textItem.Orientation == AnimationOrientation.Bottom)
{
float tmp_x = rect.X + i * avg_w;
x = tmp_x;
if (textItem.TextCenter)
{
x = tmp_x + (rect.Width - text_size.Width) / 2;
if (x tmp_x)
x = tmp_x;
}
y = rect.Bottom + text_size.Height + text_size.Height / 2;
target_x = x;
target_y = (rect.Height - text_size.Height) / 2;
}
else if (textItem.Orientation == AnimationOrientation.Right)
{
x = rect.Right + i * avg_w * 3;
y = (rect.Height - text_size.Height) / 2;
target_x = rect.X + i * avg_w;
target_y = y;
}
textItem.TextChar[i] = textItem.Text.Substring(i, 1);
textItem.prev_char_rectf[i] = new RectangleF(x, y, avg_w, text_size.Height);
textItem.current_char_rectf[i] = textItem.prev_char_rectf[i];
textItem.target_char_rectf[i] = new RectangleF(target_x, target_y, avg_w, text_size.Height);
}
}
#endregion
}
#endregion
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
if (this.intervalTimer != null)
{
this.intervalTimer.Dispose();
}
if (this.animationTimer != null)
{
this.animationTimer.Dispose();
}
}
base.Dispose(disposing);
}
///
/// 文本选项集合
///
[Description("文本选项集合")]
[Editor(typeof(CollectionEditorExt), typeof(UITypeEditor))]
public sealed class TextItemCollection : IList, ICollection, IEnumerable
{
private ArrayList textItemList = new ArrayList();
private TextCarouselExt owner;
public TextItemCollection(TextCarouselExt owner)
{
this.owner = owner;
}
#region IEnumerable
public IEnumerator GetEnumerator()
{
TextItem[] listArray = new TextItem[this.textItemList.Count];
for (int index = 0; index index)
listArray[index] = (TextItem)this.textItemList[index];
return listArray.GetEnumerator();
}
#endregion
#region ICollection
public void CopyTo(Array array, int index)
{
for (int i = 0; i this.Count; i++)
array.SetValue(this.textItemList[i], i + index);
}
public int Count
{
get
{
return this.textItemList.Count;
}
}
public bool IsSynchronized
{
get
{
return false;
}
}
public object SyncRoot
{
get
{
return (object)this;
}
}
#endregion
#region IList
public int Add(object value)
{
TextItem textItem = (TextItem)value;
this.textItemList.Add(textItem);
this.owner.InitializeTextRectangle(textItem);
this.owner.Invalidate();
return this.Count - 1;
}
public void Clear()
{
this.textItemList.Clear();
this.owner.Invalidate();
}
public bool Contains(object value)
{
return this.IndexOf(value) != -1;
}
public int IndexOf(object value)
{
return this.textItemList.IndexOf(value);
}
public void Insert(int index, object value)
{
throw new NotImplementedException();
}
public bool IsFixedSize
{
get { return false; }
}
public bool IsReadOnly
{
get { return false; }
}
public void Remove(object value)
{
if (!(value is TextItem))
return;
this.textItemList.Remove((TextItem)value);
this.owner.Invalidate();
}
public void RemoveAt(int index)
{
this.textItemList.RemoveAt(index);
this.owner.Invalidate();
}
public TextItem this[int index]
{
get
{
return (TextItem)this.textItemList[index];
}
set
{
this.textItemList[index] = (TextItem)value;
this.owner.InitializeTextRectangle((TextItem)value);
this.owner.Invalidate();
}
}
object IList.this[int index]
{
get
{
return (object)this.textItemList[index];
}
set
{
this.textItemList[index] = (TextItem)value;
this.owner.InitializeTextRectangle((TextItem)value);
this.owner.Invalidate();
}
}
#endregion
}
///
/// 渐变颜色选项集合
///
[Description("渐变颜色选项集合")]
[Editor(typeof(CollectionEditorExt), typeof(UITypeEditor))]
public sealed class ShadeColorItemCollection : IList, ICollection, IEnumerable
{
private ArrayList shadeColorItemList = new ArrayList();
public ShadeColorItemCollection()
{
}
#region IEnumerable
public IEnumerator GetEnumerator()
{
ShadeColorItem[] listArray = new ShadeColorItem[this.shadeColorItemList.Count];
for (int index = 0; index index)
listArray[index] = (ShadeColorItem)this.shadeColorItemList[index];
return listArray.GetEnumerator();
}
#endregion
#region ICollection
public void CopyTo(Array array, int index)
{
for (int i = 0; i this.Count; i++)
array.SetValue(this.shadeColorItemList[i], i + index);
}
public int Count
{
get
{
return this.shadeColorItemList.Count;
}
}
public bool IsSynchronized
{
get
{
return false;
}
}
public object SyncRoot
{
get
{
return (object)this;
}
}
#endregion
#region IList
public int Add(object value)
{
ShadeColorItem textItem = (ShadeColorItem)value;
this.shadeColorItemList.Add(textItem);
return this.Count - 1;
}
public void Clear()
{
this.shadeColorItemList.Clear();
}
public bool Contains(object value)
{
return this.IndexOf(value) != -1;
}
public int IndexOf(object value)
{
return this.shadeColorItemList.IndexOf(value);
}
public void Insert(int index, object value)
{
throw new NotImplementedException();
}
public bool IsFixedSize
{
get { return false; }
}
public bool IsReadOnly
{
get { return false; }
}
public void Remove(object value)
{
if (!(value is ShadeColorItem))
return;
this.shadeColorItemList.Remove((ShadeColorItem)value);
}
public void RemoveAt(int index)
{
this.shadeColorItemList.RemoveAt(index);
}
public ShadeColorItem this[int index]
{
get
{
return (ShadeColorItem)this.shadeColorItemList[index];
}
set
{
this.shadeColorItemList[index] = (ShadeColorItem)value;
}
}
object IList.this[int index]
{
get
{
return (object)this.shadeColorItemList[index];
}
set
{
this.shadeColorItemList[index] = (ShadeColorItem)value;
}
}
#endregion
}
///
/// 文本选项
///
[Description("文本选项")]
public class TextItem
{
private bool enabled = true;
///
/// 文本选项是否参与轮播
///
[DefaultValue(true)]
[Description("文本选项是否参与轮播")]
public bool Enabled
{
get { return this.enabled; }
set
{
if (this.enabled == value)
return;
this.enabled = value;
}
}
private AnimationWay way = AnimationWay.Scroll;
///
/// 动画方式
///
[DefaultValue(AnimationWay.Scroll)]
[Description("动画方式")]
public AnimationWay Way
{
get { return this.way; }
set
{
if (this.way == value)
return;
this.way = value;
}
}
private AnimationOrientation orientation = AnimationOrientation.Right;
///
/// 动画出现方向
///
[DefaultValue(AnimationOrientation.Right)]
[Description("动画出现方向")]
public AnimationOrientation Orientation
{
get { return this.orientation; }