android 横向滚动条

时间:2022-12-25 02:26:20
/***
* 横向滚动条,修改版,从左向右滚动,支持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); } }

android 横向滚动条的更多相关文章

  1. WPF,解决Listbox,按住ListboxItem向下拖出Listbox,横向滚动条跑到最后。

    类似这种样式的控件,.,在横向滚动条隐藏的情况下有这样的问题.(横向滚动条显示的时候也会,,目前不知道怎么解决.) 因为这个控件偏移是利用ListBox的ItemsPanelTemplate模版里的S ...

  2. jquery横向滚动条

    此代码献给wendy 由于工作太忙,下次再整理成插件调用,先记录下来,欢迎同学们提意见. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Tr ...

  3. 逆天的IE7中,诡异的横向滚动条

    今天老邹我又要吐槽IE7了,这个奇葩浏览器总是不让省心.这回遇到的问题,灰常难发现是怎么回事,不过还是让我发现原因,哈哈,只要原因去干掉这个问题比躲避问题用别的办法绕开要爽的多啊. 首先我还是介绍下, ...

  4. DataGrid横向滚动条无法拖动的问题

    项目中经常遇到一些问题,这些问题可能很简单,但是之前从未遇到,可能经过了一番谷歌,也可能是查阅了MSDN,或是借鉴了大牛博客,逐渐有了些眉目,为了将这些东西落地,也为了将来之不易的东西记录下来,以备今 ...

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

    <自绘ListBox的两种效果>一文帖出之后,从反馈信息来看,大家对这种小技巧还是很认同.接下来我将继续围绕ListBox写一系列的文章,进一步发掘ListBox的潜力,其中包括:自动调整 ...

  6. VB ListBox 添加横向滚动条

    Private Declare Function SendMessage Lib "user32 " Alias "SendMessageA" (ByVal h ...

  7. sub&comma;dl&comma;dt&comma;排版&comma;横向滚动条&comma;浮动元素居中,box-sizing

    1.sub标签 下标 2.dl,dt,dd用的地方通常是具有标题,而标题下对应有若干列表简单的(栏目标题+对应标题列表)和标题对应下面有内容.在使用时候我们能简洁html代码情况下,学会灵活使用dl ...

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

    是日有需求,曾探讨过table表单头部.尾部固定不动,中间内容随着滚动条的滚动而变化. 整合资料之际,发现有很多表格,表单展现中,横向数据很多.很长,不方便查看. 则,横空霹雳出了,此款:table表 ...

  9. easyui datagrid 横向滚动条

    要出现横向滚动条则不能有fitColumns:true/false

随机推荐

  1. &lbrack;LeetCode&rsqb; Optimal Account Balancing 最优账户平衡

    A group of friends went on holiday and sometimes lent each other money. For example, Alice paid for ...

  2. AsyncTask&period;cancel&lpar;&rpar;的结束问题

    实际项目中有这么一个问题,用户进入详情界面,那么我们就要网络加载数据并展现在UI上,这个加载用线程或者异步. 这里就拿项目中统一用异步任务来获取网络数据把. 用户可能会有这么一个操作,它在一个商品(说 ...

  3. Android studio中设置颜色的状态选择器

    <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item andro ...

  4. PHP函数前面的&commat;。

    @是可以屏蔽函数执行过程中遇到问题而产生的一些错误.警告信息,这样用户就看不到程序的出错信息.这样除了用户界面会友好一些外,更重要的是安全性,因为屏蔽了出错文件的路径等信息. 比如说这个: for($ ...

  5. Cocos2d-x 程序是如何开始运行与结束的

    题记:对于技术,我们大可不必挖得那么深,但一定要具备可以挖得很深的能力   问题的由来   怎么样使用 Cocos2d-x 快速开发游戏,方法很简单,你可以看看其自带的例程,或者从网上搜索教程,运行起 ...

  6. &period;NET笔记系列:LAMBDA表达式常用写法

    这里主要是将数据库中的常用操作用LAMBDA表达式重新表示了下,用法不多,但相对较常用,等有时间了还会扩展,并将查询语句及LINQ到时也一并重新整理下: 1.select语句:books.Select ...

  7. Domain Shutdown Error&lpar;JBAS010850&rpar;

    In a manged domain, the shutdown operation is not located in the root resource (i.e. address []). A ...

  8. 文成小盆友python-num17 - django基础

    一.首先了解web应用的本质 对于所有的Web应用,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端. 下面利用socket实现一个简单的web框架: #!/usr/b ...

  9. IP地址分类百科

    IP地址分类介绍 这里讨论IPv4,IP地址分成了A类.B类.C类.C类.E类,如下图所示: 解释: A类以0开头,网络地址有7位,主机地址有24位,举例:A类地址:0 10000000 000000 ...

  10. 汇编指令-MRS&lpar;读&rpar;和MSR&lpar;写&rpar;指令操作CPSR寄存器和SPSR寄存器使用&lpar;1&rpar;

    1.MSR和MRS指令介绍 MRS 指令:  对状态寄存器CPSR和SPSR进行读操作.通过读CPSR可以获得当前处理器的工作状态.读SPSR寄存器可以获得进入异常前的处理器状态(因为只有异常模式下有 ...