android 横向滚动条

Posted 紫檀未灭,我亦未去

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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);

}

}

以上是关于android 横向滚动条的主要内容,如果未能解决你的问题,请参考以下文章

ElementUI Table横向滚动条遇到的问题汇总

JQ 如何判断横向滚动条到最右侧

el-scrollbar隐藏横向滚动条

调整tree-select组件高度及横向滚动条

tab导航栏横向滚动条-tabScroll

请教advStringGrid横向滚动条问题,如何去掉右边那么多空白