/*** * 横向滚动条,修改版,从左向右滚动,支持html代码和html里面的网络图片 */public class MarqueeView extends LinearLayout { private Context context ; private TextView mTextField; private ScrollView mScrollView; private static final int TEXT_VIEW_VIRTUAL_WIDTH = 2000; private Animation mMoveTextOut = null; //private Animation mMoveTextIn = null; private Paint mPaint; private boolean mMarqueeNeeded = false; private static final String TAG = MarqueeView.class.getSimpleName(); private float mTextDifference; private Drawable drawable ; /** * Control the speed. The lower this value, the faster it will scroll. */ private static final int DEFAULT_SPEED = 60; /** * Control the pause between the animations. Also, after starting this activity. */ private static final int DEFAULT_ANIMATION_PAUSE = 2000; private int mSpeed = DEFAULT_SPEED; private int mAnimationPause = DEFAULT_ANIMATION_PAUSE; private boolean mAutoStart = false; private Interpolator mInterpolator = new LinearInterpolator(); private boolean mCancelled = false; private Runnable mAnimationStartRunnable; private boolean mStarted; private NetworkImageGetter mImageGetter; /** * Sets the animation speed. * The lower the value, the faster the animation will be displayed. * * @param speed Milliseconds per PX. */ public void setSpeed(int speed) { this.mSpeed = speed; } /** * Sets the pause between animations * * @param pause In milliseconds. */ public void setPauseBetweenAnimations(int pause) { this.mAnimationPause = pause; } /** * Sets a custom interpolator for the animation. * * @param interpolator Animation interpolator. */ public void setInterpolator(Interpolator interpolator) { this.mInterpolator = interpolator; } @SuppressWarnings({"UnusedDeclaration"}) public MarqueeView(Context context) { super(context); this.context = context ; init(context); } @SuppressWarnings({"UnusedDeclaration"}) public MarqueeView(Context context, AttributeSet attrs) { super(context, attrs); this.context = context ; init(context); extractAttributes(attrs); } @TargetApi(Build.VERSION_CODES.HONEYCOMB) public MarqueeView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); this.context = context ; init(context); extractAttributes(attrs); } private void extractAttributes(AttributeSet attrs) { if (getContext() == null) { return; } TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.asia_ivity_android_marqueeview_MarqueeView); if (a == null) { return; } mSpeed = a.getInteger(R.styleable.asia_ivity_android_marqueeview_MarqueeView_speed, DEFAULT_SPEED); mAnimationPause = a.getInteger(R.styleable.asia_ivity_android_marqueeview_MarqueeView_pause, DEFAULT_ANIMATION_PAUSE); mAutoStart = a.getBoolean(R.styleable.asia_ivity_android_marqueeview_MarqueeView_autoStart, false); a.recycle(); } private void init(Context context) { // init helper mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setStrokeWidth(1); mPaint.setStrokeCap(Paint.Cap.ROUND); mInterpolator = new LinearInterpolator(); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); if (getChildCount() == 0 || getChildCount() > 1) { throw new RuntimeException("MarqueeView must have exactly one child element."); } if (changed && mScrollView == null) { View v = getChildAt(0); // Fixes #1: Exception when using android:layout_width="fill_parent". There seems to be an additional ScrollView parent. if (v instanceof ScrollView && ((ScrollView) v).getChildCount() == 1) { v = ((ScrollView) v).getChildAt(0); } if (!(v instanceof TextView)) { throw new RuntimeException("The child view of this MarqueeView must be a TextView instance."); } initView(getContext()); prepareAnimation(); if (mAutoStart) { startMarquee(); } } } private String message ; private boolean startScroll = true ; /*** * 开始滚动 * @param _message */ public void startScrollView(String _message){ if(message.equals(_message)) return; this.message = _message ; if(startScroll){ mTextField.setText(Html.fromHtml(message ,mImageGetter ,null)); startMarquee(); } } /** * Starts the configured marquee effect. */ public void startMarquee() { if (mMarqueeNeeded) { startScroll = false ; startTextFieldAnimation(); } mCancelled = false; mStarted = true; } private void startTextFieldAnimation() { mAnimationStartRunnable = new Runnable() { public void run() { mTextField.startAnimation(mMoveTextOut); } }; postDelayed(mAnimationStartRunnable, mAnimationPause); } /** * Disables the animations. */ public void reset() { mCancelled = true; if (mAnimationStartRunnable != null) { removeCallbacks(mAnimationStartRunnable); } mTextField.clearAnimation(); mStarted = false; mTextField.setVisibility(INVISIBLE); mMoveTextOut.reset(); // mMoveTextIn.reset(); // mScrollView.removeView(mTextField);// mScrollView.addView(mTextField); invalidate(); } private void prepareAnimation() { // Measure mPaint.setTextSize(mTextField.getTextSize()); mPaint.setTypeface(mTextField.getTypeface()); final float mTextWidth = mPaint.measureText(mTextField.getText().toString()); // See how much functions are needed at all mMarqueeNeeded = mTextWidth > getMeasuredWidth(); if(drawable != null){ //当html有图片时,不能获取到图片长度,我这里滚动条有15长图片,所以需要单独加上 mTextDifference = Math.abs(mTextWidth) + drawable.getIntrinsicWidth() * 15 + 5; }else { mTextDifference = Math.abs(mTextWidth) + 5; }//获取滚动条长度,根据滚动速度和长度计算滚动时间(滚动动画持续时间) // if (true) {// Log.d(TAG, "mTextWidth : " + mTextWidth);// Log.d(TAG, "measuredWidth : " + getMeasuredWidth());// Log.d(TAG, "mMarqueeNeeded : " + mMarqueeNeeded);// Log.d(TAG, "mTextDifference : " + mTextDifference);// } final int duration = (int) (mTextDifference * mSpeed); mMoveTextOut = new TranslateAnimation(getMeasuredWidth(), -mTextDifference, 0, 0); mMoveTextOut.setDuration(duration); mMoveTextOut.setInterpolator(mInterpolator); mMoveTextOut.setAnimationListener(new Animation.AnimationListener() { public void onAnimationStart(Animation animation) { expandTextView(mTextWidth); mTextField.setVisibility(VISIBLE); } public void onAnimationEnd(Animation animation) { // mTextField.setText(Html.fromHtml(message)); mTextField.setText(Html.fromHtml(message ,mImageGetter ,null)); if (mCancelled) { return; } mTextField.startAnimation(mMoveTextOut); } public void onAnimationRepeat(Animation animation) { } }); } private void initView(Context context) { mImageGetter = new NetworkImageGetter(); // Scroll View LayoutParams sv1lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); sv1lp.gravity = Gravity.CENTER_HORIZONTAL; mScrollView = new ScrollView(context); // Scroll View 1 - Text Field mTextField = (TextView) getChildAt(0); removeView(mTextField); mScrollView.addView(mTextField, new ScrollView.LayoutParams(TEXT_VIEW_VIRTUAL_WIDTH, LayoutParams.WRAP_CONTENT)); mTextField.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) { } @Override public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) { } @Override public void afterTextChanged(Editable editable) { final boolean continueAnimation = mStarted; reset(); prepareAnimation(); cutTextView(); post(new Runnable() { @Override public void run() { if (continueAnimation) { startScroll = true ; startMarquee(); } } }); } }); addView(mScrollView, sv1lp); } private void expandTextView(float width) { ViewGroup.LayoutParams lp = mTextField.getLayoutParams(); if(drawable != null){ //当html有图片时,不能获取到图片长度,我这里滚动条有15长图片,所以需要单独加上 lp.width =(int)width + drawable.getIntrinsicWidth() * 15 +1; }else { lp.width =(int)width +1; }//设置滚动长度,滚动的内部其实是一个textView,滚动其实是textView向左做移动 mTextField.setLayoutParams(lp); } private void cutTextView() { if (mTextField.getWidth() != getMeasuredWidth()) { ViewGroup.LayoutParams lp = mTextField.getLayoutParams(); lp.width = getMeasuredWidth(); mTextField.setLayoutParams(lp); } } /*** * 根据html里面的图片地址获取网络图片存储到本地 */ class NetworkImageGetter implements Html.ImageGetter{ @Override public Drawable getDrawable(String source) { // 封装路径 File file = StorageUtils.getCacheFile(context,"jpg" ,source);//获取图片是否在本地SD卡中 final Uri uri = Uri.parse(file.getAbsolutePath()); final String path = uri.getPath(); drawable = Drawable.createFromPath(path); // 判断是否以http开头 if(source.startsWith("http")) { // 判断路径是否存在 if(file.exists() && file.length() > 0) { // 存在即获取drawable drawable = Drawable.createFromPath(file.getAbsolutePath()); drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); } else { // 不存在即开启异步任务加载网络图片 toastService(context,source ,"jpg"); } } return drawable; } } /** * 本地的下载图片服务 * @param context * @param url * @param extension */ private void toastService(Context context,String url,String extension) { Intent intent = new Intent(context,HtmlCacheService.class); intent.putExtra(HtmlCacheService.DOWN_URL,url); intent.putExtra(HtmlCacheService.EXTENSION,extension); context.startService(intent); } }
时间: 2024-10-29 19:12:08