Android 圆弧形 SeekBar
创始人
2024-05-28 14:04:42
0

效果预览

package com.gcssloop.widget;

import android.annotation.SuppressLint;

import android.content.Context;

import android.content.res.TypedArray;

import android.graphics.Canvas;

import android.graphics.Color;

import android.graphics.Matrix;

import android.graphics.Paint;

import android.graphics.Path;

import android.graphics.PathMeasure;

import android.graphics.RectF;

import android.graphics.Region;

import android.graphics.SweepGradient;

import android.os.Bundle;

import android.os.Parcelable;

import android.util.AttributeSet;

import android.util.TypedValue;

import android.view.GestureDetector;

import android.view.MotionEvent;

import android.view.View;

import com.gcssloop.arcseekbar.R;

import static android.view.MotionEvent.ACTION_CANCEL;

import static android.view.MotionEvent.ACTION_DOWN;

import static android.view.MotionEvent.ACTION_MOVE;

import static android.view.MotionEvent.ACTION_UP;

public class ArcSeekBar extends View {

private static final int DEFAULT_EDGE_LENGTH = 260; // 默认宽高

private static final float CIRCLE_ANGLE = 360; // 圆周角

private static final int DEFAULT_ARC_WIDTH = 40; // 默认宽度 dp

private static final float DEFAULT_OPEN_ANGLE = 120; // 开口角度

private static final float DEFAULT_ROTATE_ANGLE = 90; // 旋转角度

private static final int DEFAULT_BORDER_WIDTH = 0; // 默认描边宽度

private static final int DEFAULT_BORDER_COLOR = 0xffffffff; // 默认描边颜色

private static final int DEFAULT_THUMB_COLOR = 0xffffffff; // 拖动按钮颜色

private static final int DEFAULT_THUMB_WIDTH = 2; // 拖动按钮描边宽度 dp

private static final int DEFAULT_THUMB_RADIUS = 15; // 拖动按钮半径 dp

private static final int DEFAULT_THUMB_SHADOW_RADIUS = 0; // 拖动按钮阴影半径 dp

private static final int DEFAULT_THUMB_SHADOW_COLOR = 0xFF000000; // 拖动按钮阴影颜色

private static final int DEFAULT_SHADOW_RADIUS = 0; // 默认阴影半径 dp

private static final int THUMB_MODE_STROKE = 0; // 拖动按钮模式 - 描边

private static final int THUMB_MODE_FILL = 1; // 拖动按钮模式 - 填充

private static final int THUMB_MODE_FILL_STROKE = 2; // 拖动按钮模式 - 填充+描边

private static final int DEFAULT_MAX_VALUE = 100; // 默认最大数值

private static final int DEFAULT_MIN_VALUE = 0; // 默认最小数值

private static final String KEY_PROGRESS_PRESENT = "PRESENT"; // 用于存储和获取当前百分比

// 可配置数据

private int[] mArcColors; // Seek 颜色

private float mArcWidth; // Seek 宽度

private float mOpenAngle; // 开口的角度大小 0 - 360

private float mRotateAngle; // 旋转角度

private int mBorderWidth; // 描边宽度

private int mBorderColor; // 描边颜色

private int mThumbColor; // 拖动按钮颜色

private float mThumbWidth; // 拖动按钮宽度

private float mThumbRadius; // 拖动按钮半径

private float mThumbShadowRadius;// 拖动按钮阴影半径

private int mThumbShadowColor;// 拖动按钮阴影颜色

private int mThumbMode; // 拖动按钮模式

private int mShadowRadius; // 阴影半径

private int mMaxValue; // 最大数值

private int mMinValue; // 最小数值

private float mCenterX; // 圆弧 SeekBar 中心点 X

private float mCenterY; // 圆弧 SeekBar 中心点 Y

private float mThumbX; // 拖动按钮 中心点 X

private float mThumbY; // 拖动按钮 中心点 Y

private Path mSeekPath;

private Path mBorderPath;

private Paint mArcPaint;

private Paint mThumbPaint;

private Paint mBorderPaint;

private Paint mShadowPaint;

private float[] mTempPos;

private float[] mTempTan;

private PathMeasure mSeekPathMeasure;

private float mProgressPresent = 0; // 当前进度百分比

private boolean mCanDrag = false; // 是否允许拖动

private boolean mAllowTouchSkip = false; // 是否允许越过边界

private GestureDetector mDetector;

private Matrix mInvertMatrix; // 逆向 Matrix, 用于计算触摸坐标和绘制坐标的转换

private Region mArcRegion; // ArcPath的实际区域大小,用于判定单击事件

public ArcSeekBar(Context context) {

this(context, null);

}

public ArcSeekBar(Context context, AttributeSet attrs) {

this(context, attrs, 0);

}

public ArcSeekBar(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

setSaveEnabled(true);

setLayerType(LAYER_TYPE_SOFTWARE, null);

initAttrs(context, attrs);

initData();

initPaint();

}

// 初始化各种属性

private void initAttrs(Context context, AttributeSet attrs) {

TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ArcSeekBar);

mArcColors = getArcColors(context, ta);

mArcWidth = ta.getDimensionPixelSize(R.styleable.ArcSeekBar_arc_width, dp2px(DEFAULT_ARC_WIDTH));

mOpenAngle = ta.getFloat(R.styleable.ArcSeekBar_arc_open_angle, DEFAULT_OPEN_ANGLE);

mRotateAngle = ta.getFloat(R.styleable.ArcSeekBar_arc_rotate_angle, DEFAULT_ROTATE_ANGLE);

mMaxValue = ta.getInt(R.styleable.ArcSeekBar_arc_max, DEFAULT_MAX_VALUE);

mMinValue = ta.getInt(R.styleable.ArcSeekBar_arc_min, DEFAULT_MIN_VALUE);

// 如果用户设置的最大值和最小值不合理,则直接按照默认进行处理

if (mMaxValue <= mMinValue) {

mMaxValue = DEFAULT_MAX_VALUE;

mMinValue = DEFAULT_MIN_VALUE;

}

int progress = ta.getInt(R.styleable.ArcSeekBar_arc_progress, mMinValue);

setProgress(progress);

mBorderWidth = ta.getDimensionPixelSize(R.styleable.ArcSeekBar_arc_border_width, dp2px(DEFAULT_BORDER_WIDTH));

mBorderColor = ta.getColor(R.styleable.ArcSeekBar_arc_border_color, DEFAULT_BORDER_COLOR);

mThumbColor = ta.getColor(R.styleable.ArcSeekBar_arc_thumb_color, DEFAULT_THUMB_COLOR);

mThumbRadius = ta.getDimensionPixelSize(R.styleable.ArcSeekBar_arc_thumb_radius, dp2px(DEFAULT_THUMB_RADIUS));

mThumbShadowRadius = ta.getDimensionPixelSize(R.styleable.ArcSeekBar_arc_thumb_shadow_radius, dp2px(DEFAULT_THUMB_SHADOW_RADIUS));

mThumbShadowColor = ta.getColor(R.styleable.ArcSeekBar_arc_thumb_shadow_color, DEFAULT_THUMB_SHADOW_COLOR);

mThumbWidth = ta.getDimensionPixelSize(R.styleable.ArcSeekBar_arc_thumb_width, dp2px(DEFAULT_THUMB_WIDTH));

mThumbMode = ta.getInt(R.styleable.ArcSeekBar_arc_thumb_mode, THUMB_MODE_STROKE);

mShadowRadius = ta.getDimensionPixelSize(R.styleable.ArcSeekBar_arc_shadow_radius, dp2px(DEFAULT_SHADOW_RADIUS));

ta.recycle();

}

// 获取 Arc 颜色数组

private int[] getArcColors(Context context, TypedArray ta) {

int[] ret;

int resId = ta.getResourceId(R.styleable.ArcSeekBar_arc_colors, 0);

if (0 == resId) {

resId = R.array.arc_colors_default;

}

ret = getColorsByArrayResId(context, resId);

return ret;

}

// 根据 resId 获取颜色数组

private int[] getColorsByArrayResId(Context context, int resId) {

int[] ret;

TypedArray colorArray = context.getResources().obtainTypedArray(resId);

ret = new int[colorArray.length()];

for (int i = 0; i < colorArray.length(); i++) {

ret[i] = colorArray.getColor(i, 0);

}

return ret;

}

// 初始化数据

private void initData() {

mSeekPath = new Path();

mBorderPath = new Path();

mSeekPathMeasure = new PathMeasure();

mTempPos = new float[2];

mTempTan = new float[2];

mDetector = new GestureDetector(getContext(), new OnClickListener());

mInvertMatrix = new Matrix();

mArcRegion = new Region();

}

// 初始化画笔

private void initPaint() {

initArcPaint();

initThumbPaint();

initBorderPaint();

initShadowPaint();

}

// 初始化圆弧画笔

private void initArcPaint() {

mArcPaint = new Paint();

mArcPaint.setAntiAlias(true);

mArcPaint.setStrokeWidth(mArcWidth);

mArcPaint.setStyle(Paint.Style.STROKE);

mArcPaint.setStrokeCap(Paint.Cap.ROUND);

}

// 初始化拖动按钮画笔

private void initThumbPaint() {

mThumbPaint = new Paint();

mThumbPaint.setAntiAlias(true);

mThumbPaint.setColor(mThumbColor);

mThumbPaint.setStrokeWidth(mThumbWidth);

mThumbPaint.setStrokeCap(Paint.Cap.ROUND);

if (mThumbMode == THUMB_MODE_FILL) {

mThumbPaint.setStyle(Paint.Style.FILL_AND_STROKE);

} else if (mThumbMode == THUMB_MODE_FILL_STROKE) {

mThumbPaint.setStyle(Paint.Style.FILL_AND_STROKE);

} else {

mThumbPaint.setStyle(Paint.Style.STROKE);

}

mThumbPaint.setTextSize(56);

}

// 初始化拖动按钮画笔

private void initBorderPaint() {

mBorderPaint = new Paint();

mBorderPaint.setAntiAlias(true);

mBorderPaint.setColor(mBorderColor);

mBorderPaint.setStrokeWidth(mBorderWidth);

mBorderPaint.setStyle(Paint.Style.STROKE);

}

// 初始化阴影画笔

private void initShadowPaint() {

mShadowPaint = new Paint();

mShadowPaint.setAntiAlias(true);

mShadowPaint.setStrokeWidth(mBorderWidth);

mShadowPaint.setStyle(Paint.Style.FILL_AND_STROKE);

}

@Override

protected Parcelable onSaveInstanceState() {

Bundle bundle = new Bundle();

bundle.putParcelable("superState", super.onSaveInstanceState());

bundle.putFloat(KEY_PROGRESS_PRESENT, mProgressPresent);

return bundle;

}

@Override

protected void onRestoreInstanceState(Parcelable state) {

if (state instanceof Bundle) {

Bundle bundle = (Bundle) state;

this.mProgressPresent = bundle.getFloat(KEY_PROGRESS_PRESENT);

state = bundle.getParcelable("superState");

}

if (null != mOnProgressChangeListener) {

mOnProgressChangeListener.onProgressChanged(this, getProgress(), false);

}

super.onRestoreInstanceState(state);

}

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

int ws = MeasureSpec.getSize(widthMeasureSpec); //取出宽度的确切数值

int wm = MeasureSpec.getMode(widthMeasureSpec); //取出宽度的测量模式

int hs = MeasureSpec.getSize(heightMeasureSpec); //取出高度的确切数值

int hm = MeasureSpec.getMode(heightMeasureSpec); //取出高度的测量模

if (wm == MeasureSpec.UNSPECIFIED) {

wm = MeasureSpec.EXACTLY;

ws = dp2px(DEFAULT_EDGE_LENGTH);

} else if (wm == MeasureSpec.AT_MOST) {

wm = MeasureSpec.EXACTLY;

ws = Math.min(dp2px(DEFAULT_EDGE_LENGTH), ws);

}

if (hm == MeasureSpec.UNSPECIFIED) {

hm = MeasureSpec.EXACTLY;

hs = dp2px(DEFAULT_EDGE_LENGTH);

} else if (hm == MeasureSpec.AT_MOST) {

hm = MeasureSpec.EXACTLY;

hs = Math.min(dp2px(DEFAULT_EDGE_LENGTH), hs);

}

setMeasuredDimension(MeasureSpec.makeMeasureSpec(ws, wm), MeasureSpec.makeMeasureSpec(hs, hm));

}

@Override

protected void onSizeChanged(int w, int h, int oldw, int oldh) {

super.onSizeChanged(w, h, oldw, oldh);

// 计算在当前大小下,内容应该显示的大小和起始位置

int safeW = w - getPaddingLeft() - getPaddingRight();

int safeH = h - getPaddingTop() - getPaddingBottom();

float edgeLength, startX, startY;

float fix = mArcWidth / 2 + mBorderWidth + mShadowRadius * 2; // 修正距离,画笔宽度的修正

if (safeW < safeH) {

// 宽度小于高度,以宽度为准

edgeLength = safeW - fix;

startX = getPaddingLeft();

startY = (safeH - safeW) / 2.0f + getPaddingTop();

} else {

// 宽度大于高度,以高度为准

edgeLength = safeH - fix;

startX = (safeW - safeH) / 2.0f + getPaddingLeft();

startY = getPaddingTop();

}

// 得到显示区域和中心的

RectF content = new RectF(startX + fix, startY + fix, startX + edgeLength, startY + edgeLength);

mCenterX = content.centerX();

mCenterY = content.centerY();

// 得到路径

mSeekPath.reset();

mSeekPath.addArc(content, mOpenAngle / 2, CIRCLE_ANGLE - mOpenAngle);

mSeekPathMeasure.setPath(mSeekPath, false);

computeThumbPos(mProgressPresent);

resetShaderColor();

mInvertMatrix.reset();

mInvertMatrix.preRotate(-mRotateAngle, mCenterX, mCenterY);

mArcPaint.getFillPath(mSeekPath, mBorderPath);

mBorderPath.close();

mArcRegion.setPath(mBorderPath, new Region(0, 0, w, h));

}

// 重置 shader 颜色

private void resetShaderColor() {

// 计算渐变数组

float startPos = (mOpenAngle / 2) / CIRCLE_ANGLE;

float stopPos = (CIRCLE_ANGLE - (mOpenAngle / 2)) / CIRCLE_ANGLE;

int len = mArcColors.length - 1;

float distance = (stopPos - startPos) / len;

float pos[] = new float[mArcColors.length];

for (int i = 0; i < mArcColors.length; i++) {

pos[i] = startPos + (distance * i);

}

SweepGradient gradient = new SweepGradient(mCenterX, mCenterY, mArcColors, pos);

mArcPaint.setShader(gradient);

}

// 具体绘制

@Override

protected void onDraw(Canvas canvas) {

canvas.save();

canvas.rotate(mRotateAngle, mCenterX, mCenterY);

mShadowPaint.setShadowLayer(mShadowRadius * 2, 0, 0, getColor());

canvas.drawPath(mBorderPath, mShadowPaint);

canvas.drawPath(mSeekPath, mArcPaint);

if (mBorderWidth > 0) {

canvas.drawPath(mBorderPath, mBorderPaint);

}

if (mThumbShadowRadius > 0) {

mThumbPaint.setShadowLayer(mThumbShadowRadius, 0, 0, mThumbShadowColor);

canvas.drawCircle(mThumbX, mThumbY, mThumbRadius, mThumbPaint);

mThumbPaint.clearShadowLayer();

}

canvas.drawCircle(mThumbX, mThumbY, mThumbRadius, mThumbPaint);

canvas.restore();

}

private boolean moved = false;

private int lastProgress = -1;

@SuppressLint("ClickableViewAccessibility")

@Override

public boolean onTouchEvent(MotionEvent event) {

super.onTouchEvent(event);

int action = event.getActionMasked();

switch (action) {

case ACTION_DOWN:

moved = false;

judgeCanDrag(event);

if (null != mOnProgressChangeListener) {

mOnProgressChangeListener.onStartTrackingTouch(this);

}

break;

case ACTION_MOVE:

if (!mCanDrag) {

break;

}

float tempProgressPresent = getCurrentProgress(event.getX(), event.getY());

if (!mAllowTouchSkip) {

// 不允许突变

if (Math.abs(tempProgressPresent - mProgressPresent) > 0.5f) {

break;

}

}

// 允许突变 或者非突变

mProgressPresent = tempProgressPresent;

computeThumbPos(mProgressPresent);

// 事件回调

if (null != mOnProgressChangeListener && getProgress() != lastProgress) {

mOnProgressChangeListener.onProgressChanged(this, getProgress(), true);

lastProgress = getProgress();

}

moved = true;

break;

case ACTION_UP:

case ACTION_CANCEL:

if (null != mOnProgressChangeListener && moved) {

mOnProgressChangeListener.onStopTrackingTouch(this);

}

break;

}

mDetector.onTouchEvent(event);

invalidate();

return true;

}

// 判断是否允许拖动

private void judgeCanDrag(MotionEvent event) {

float[] pos = {event.getX(), event.getY()};

mInvertMatrix.mapPoints(pos);

if (getDistance(pos[0], pos[1]) <= mThumbRadius * 1.5) {

mCanDrag = true;

} else {

mCanDrag = false;

}

}

private class OnClickListener extends GestureDetector.SimpleOnGestureListener {

@Override

public boolean onSingleTapUp(MotionEvent e) {

// 判断是否点击在了进度区域

if (!isInArcProgress(e.getX(), e.getY())) return false;

// 点击允许突变

mProgressPresent = getCurrentProgress(e.getX(), e.getY());

computeThumbPos(mProgressPresent);

// 事件回调

if (null != mOnProgressChangeListener) {

mOnProgressChangeListener.onProgressChanged(ArcSeekBar.this, getProgress(), true);

mOnProgressChangeListener.onStopTrackingTouch(ArcSeekBar.this);

}

return true;

}

}

// 判断该点是否在进度条上面

private boolean isInArcProgress(float px, float py) {

float[] pos = {px, py};

mInvertMatrix.mapPoints(pos);

return mArcRegion.contains((int) pos[0], (int) pos[1]);

}

// 获取当前进度理论进度数值

private float getCurrentProgress(float px, float py) {

float diffAngle = getDiffAngle(px, py);

float progress = diffAngle / (CIRCLE_ANGLE - mOpenAngle);

if (progress < 0) progress = 0;

if (progress > 1) progress = 1;

return progress;

}

// 获得当前点击位置所成角度与开始角度之间的数值差

private float getDiffAngle(float px, float py) {

float angle = getAngle(px, py);

float diffAngle;

diffAngle = angle - mRotateAngle;

if (diffAngle < 0) {

diffAngle = (diffAngle + CIRCLE_ANGLE) % CIRCLE_ANGLE;

}

diffAngle = diffAngle - mOpenAngle / 2;

return diffAngle;

}

// 计算指定位置与内容区域中心点的夹角

private float getAngle(float px, float py) {

float angle = (float) ((Math.atan2(py - mCenterY, px - mCenterX)) * 180 / 3.14f);

if (angle < 0) {

angle += 360;

}

return angle;

}

// 计算指定位置与上次位置的距离

private float getDistance(float px, float py) {

return (float) Math.sqrt((px - mThumbX) * (px - mThumbX) + (py - mThumbY) * (py - mThumbY));

}

private int dp2px(int dp) {

return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getContext().getResources().getDisplayMetrics());

}

// 计算拖动块应该显示的位置

private void computeThumbPos(float present) {

if (present < 0) present = 0;

if (present > 1) present = 1;

if (null == mSeekPathMeasure) return;

float distance = mSeekPathMeasure.getLength() * present;

mSeekPathMeasure.getPosTan(distance, mTempPos, mTempTan);

mThumbX = mTempPos[0];

mThumbY = mTempPos[1];

}

/**

* 获取当前进度的具体颜色

*

* @return 当前进度在渐变中的颜色

*/

public int getColor() {

return getColor(mProgressPresent);

}

/**

* 获取某个百分比位置的颜色

*

* @param radio 取值[0,1]

* @return 最终颜色

*/

private int getColor(float radio) {

float diatance = 1.0f / (mArcColors.length - 1);

int startColor;

int endColor;

if (radio >= 1) {

return mArcColors[mArcColors.length - 1];

}

for (int i = 0; i < mArcColors.length; i++) {

if (radio <= i * diatance) {

if (i == 0) {

return mArcColors[0];

}

startColor = mArcColors[i - 1];

endColor = mArcColors[i];

float areaRadio = getAreaRadio(radio, diatance * (i - 1), diatance * i);

return getColorFrom(startColor, endColor, areaRadio);

}

}

return -1;

}

/**

* 计算当前比例在子区间的比例

*

* @param radio 总比例

* @param startPosition 子区间开始位置

* @param endPosition 子区间结束位置

* @return 自区间比例[0, 1]

*/

private float getAreaRadio(float radio, float startPosition, float endPosition) {

return (radio - startPosition) / (endPosition - startPosition);

}

/**

* 取两个颜色间的渐变区间 中的某一点的颜色

*

* @param startColor 开始的颜色

* @param endColor 结束的颜色

* @param radio 比例 [0, 1]

* @return 选中点的颜色

*/

private int getColorFrom(int startColor, int endColor, float radio) {

int redStart = Color.red(startColor);

int blueStart = Color.blue(startColor);

int greenStart = Color.green(startColor);

int redEnd = Color.red(endColor);

int blueEnd = Color.blue(endColor);

int greenEnd = Color.green(endColor);

int red = (int) (redStart + ((redEnd - redStart) * radio + 0.5));

int greed = (int) (greenStart + ((greenEnd - greenStart) * radio + 0.5));

int blue = (int) (blueStart + ((blueEnd - blueStart) * radio + 0.5));

return Color.argb(255, red, greed, blue);

}

/**

* 设置进度

*

* @param progress 进度值

*/

public void setProgress(int progress) {

System.out.println("setProgress = " + progress);

if (progress > mMaxValue) progress = mMaxValue;

if (progress < mMinValue) progress = mMinValue;

mProgressPresent = (progress - mMinValue) * 1.0f / (mMaxValue - mMinValue);

System.out.println("setProgress present = " + mProgressPresent);

if (null != mOnProgressChangeListener) {

mOnProgressChangeListener.onProgressChanged(this, progress, false);

}

computeThumbPos(mProgressPresent);

postInvalidate();

}

/**

* 获取当前进度数值

*

* @return 当前进度数值

*/

public int getProgress() {

return (int) (mProgressPresent * (mMaxValue - mMinValue)) + mMinValue;

}

/**

* 设置颜色

*

* @param colors 颜色

*/

public void setArcColors(int[] colors) {

mArcColors = colors;

resetShaderColor();

postInvalidate();

}

/**

* 设置最大数值

* @param max 最大数值

*/

public void setMaxValue(int max) {

mMaxValue = max;

}

/**

* 设置最小数值

* @param min 最小数值

*/

public void setMinValue(int min) {

mMinValue = min;

}

/**

* 设置颜色

*

* @param colorArrayRes 颜色资源 R.array.arc_color

*/

public void setArcColors(int colorArrayRes) {

setArcColors(getColorsByArrayResId(getContext(), colorArrayRes));

}

private OnProgressChangeListener mOnProgressChangeListener;

public void setOnProgressChangeListener(OnProgressChangeListener onProgressChangeListener) {

mOnProgressChangeListener = onProgressChangeListener;

}

public interface OnProgressChangeListener {

/**

* 进度发生变化

*

* @param seekBar 拖动条

* @param progress 当前进度数值

* @param isUser 是否是用户操作, true 表示用户拖动, false 表示通过代码设置

*/

void onProgressChanged(ArcSeekBar seekBar, int progress, boolean isUser);

/**

* 用户开始拖动

*

* @param seekBar 拖动条

*/

void onStartTrackingTouch(ArcSeekBar seekBar);

/**

* 用户结束拖动

*

* @param seekBar 拖动条

*/

void onStopTrackingTouch(ArcSeekBar seekBar);

}

}

attrs.xml代码:

相关内容

热门资讯

祝寿主持词 祝寿主持词  主持词要尽量增加文化内涵、寓教于乐,不断提高观众的文化知识和素养。在人们积极参与各种活...
回门宴主持词 让你的回门宴顺... 回门宴主持词 让你的回门宴顺利完成  篇一:新婚回门宴主持词  亲爱的各位来宾,各位亲朋好友,先生们...
结婚新郎致辞 结婚新郎致辞(15篇)  在学习、工作、生活中,说到致辞,大家肯定都不陌生吧,致辞具有能伸能缩,可以...
庆中秋迎国庆联欢晚会主持词(...   (念8条短信)  男:我们的驻外营销健儿发来的每一条祝福都是那么的感人。由于时间关系,我们不能一...
重庆森林经典台词 重庆森林经典台词  《重庆森林》由两个基本不相干的故事构成。两个故事之间的关系,就像擦身而过的金城武...
歌曲奔跑主持词串词 歌曲奔跑主持词串词范文  借鉴诗词和散文诗是主持词的一种写作手法。在如今这个中国,主持成为很多活动不...
年会老板感谢员工精彩致辞 年会老板感谢员工精彩致辞(通用16篇)  在日复一日的学习、工作或生活中,大家都用到过致辞吧,致辞具...
六一文艺汇演主持词 六一文艺汇演主持词(通用10篇)  主持词要根据活动对象的不同去设置不同的主持词。在人们积极参与各种...
文艺晚会主持稿   男:今晚,我们再次欢聚一堂  女:满载丰收的喜悦,用歌舞表达内心最真挚的情感  男:朋友们,古往...
最新公司年会主持词 最新公司年会主持词  主持词已成为各种演出活动和集会中不可或缺的一部分。在当下的社会中,主持词的实用...
毕业晚会主持词结束语 毕业晚会主持词结束语  以下是由应届毕业生网PQ小编为大家整理出来的2016年毕业晚会主持词结束语,...
启动会主持词 启动会主持词  利用在中国拥有几千年文化的诗词能够有效提高主持词的感染力。在现在的社会生活中,主持人...
七十大寿祝寿主持词最新 七十大寿祝寿主持词最新  根据活动对象的不同,需要设置不同的主持词。在当下的中国社会,主持词的实用频...
十一国庆节晚会主持词 十一国庆节晚会主持词  在国庆节需要举办相关的晚会,那么晚会的主持词应该怎么写呢?下面是小编分享给大...
中学秋季开学典礼主持词串词 中学秋季开学典礼主持词串词  暑假如同一部赏心悦目的电影,看完了,请你把美好的记忆珍藏在心中,开学日...
适合父亲节的歌曲 适合父亲节的歌曲适合父亲节的歌曲推荐Eric Clapton的.My Father's Eyes,很...
我们的节日端午主持稿 我们的节日端午主持稿(通用12篇)  在当下社会,很多地方都会使用到主持稿,主持稿具有语言过度自然、...
婚礼主持词开场白   第一篇:  尊敬的各位来宾,  很高兴接受一对新人的委托,主持今天这场爱情的盛典,我是主持人张 ...
幸福额度简介及台词 幸福额度简介及台词  《幸福额度》简介  《幸福额度》由陈正道执导,林志玲、陈坤、廖凡主演的爱情电影...
舞蹈大赛主持词 舞蹈大赛主持词集合七篇  利用在中国拥有几千年文化的诗词能够有效提高主持词的感染力。在人们积极参与各...