android 横向滚动条

/*** * 横向滚动条,修改版,从左向右滚动,支持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

android 横向滚动条的相关文章

Android 横向ScrollView照片浏览器实现(致敬郭神)

因为项目中需要用到所以实现的一个横向的照片浏览器,使用横向SrollView实现. 实现效果如下: 实现思路: 在开始做之前呢,本着有轮子就用轮子的精神,也还是去百度找了很久,诸如"Android横向照片墙"."Android横向照片流"."Android横向照片选择器"-完全没有好咩..查来查去都是那几篇竖向照片瀑布流的,横向的反正我是没找到. 然后,在将郭神的<ndroid瀑布流照片墙实现,体验不规则排列的美感>一文拜读之后(ht

css之超出部分不换行且显示横向滚动条

我不是专业前端,所以折腾了老半天啊QAQ 需求是两个div,内层div不换行且超出时外层div显示横向滚动条 类似以下这种: 刚开始的代码如下: <div class="nowrap"> <div class="item-t"></div> <div class="item-t"></div> <div class="item-t"></div>

移动端禁用横向滚动条

在用bootstrap制作移动开发的时候,发现宽度并未超过屏幕宽度时,依然出现横向滚动条. 问题解决: 1.查看是否在head里面加入 /*等比例缩放*/<meta name="viewport" content="width=device-width, initial-scale=1.0">/*禁止缩放*/<meta name="viewport" content="initial-scale=1, maximum-

WPF:解决DataGrid横向滚动条无法显示的问题

DataGrid的最后一列的宽度设置为“Width=”auto””即可. 如果显示指定长度或者设置为“*”,那么不管怎么拖动列头,或者不管行里面的内容有没有超过DataGrid的显示区域,DataGrid的横向滚动条都不会显示出来. 转载声明:本文转载至http://www.zhoumy.cn,文章链接:http://www.zhoumy.cn/?p=28

table左边固定-底部横向滚动条

是日有需求,曾探讨过table表单头部.尾部固定不动,中间内容随着滚动条的滚动而变化. 整合资料之际,发现有很多表格,表单展现中,横向数据很多.很长,不方便查看. 则,横空霹雳出了,此款:table表单左边固定,底部滚动条左右滑动展现数据demo. 原理很简单:在 table外面嵌套一层div ,并且设置此父div {overflow: auto;}.此举为了出席横向滚动条 对里面的tr设置{position: relative;}相对定位 对tr里面的第一个td设置fixed .fixed {

发掘ListBox的潜力(一):自动调整横向滚动条宽度

<自绘ListBox的两种效果>一文帖出之后,从反馈信息来看,大家对这种小技巧还是很认同.接下来我将继续围绕ListBox写一系列的文章,进一步发掘ListBox的潜力,其中包括:自动调整横向滚动条宽度.即时提示(Tips).拖放插入点提示等,并在最后制作一个在滚动区内的ListBox组. 自动调整横向滚动条宽度 网上可以找到很多让Listbox产生横向滚动条的文章,其中的方法基本一样,就是定义一个函数,遍历Items取得最大的TextWidth值,然后发Listbox发消息LB_SETHOR

android 横向list特效——规格滑动

首先,这个是在github开源项目HorizontalListView上作得修改,这个开源项目的下载地址我忘记了,贴一个引用网址:http://code.eoe.cn/233. 首先来说一下什么叫规格滑动: 上图就是规格滑动的合法状态:恰好显示一定数量的item,并且没有item处于一半显示一半在屏幕外的状态.这样说还不是很清楚,那么再贴一张非法状态: 所谓规格滑动,就是每次滑动结束之后必然停留在合法状态,如果是非法状态,则会自动滑动到最近的合法状态位置上.一次滚动之后ListView要么没有位

IE6下出现横向滚动条问题的解决方案

当我们在css样式设置为html {overflow-y:auto;}时,在ie7以上版本应用时不会有问题,可是在ie6下就会发现垂直滚动条出现会引起横向滚动条出现.究其原因是在ie6下,当内容过多出现垂直滚动条时,此时页面的宽度为其本来宽度加上滚动条的宽度,导致页面宽度超过100%,而出现横向滚动条,在ie7+浏览器中,会自动的识别滚动条,页面宽度为内容的宽度加上滚动条的宽度等于100%,而不会出现滚动条,这相当于是ie的滚动条bug(纯属个人见解,不对的地方还请指出,共同学习交流). 解决上

横向滚动条 根据滚轮滚动而移动 制作 与 问题处理

今天做一个项目的时候要用到 ‘横向滚动条 根据滚轮滚动而移动’ 上网上查了很多资料 还找了一些插件 !  都不是很好用 然后自己大概查了下资料 找到一个大概比较靠谱的 HTML <div style="width: 5000px;">test</div> jQuery $(function() { // 设置每次滚动长度,单位 px var scroll_width = 100; var scroll_events = "mousewheel DOMM