PS:写博客真的好麻烦,很多思路自己理解了,但是写起来就很累,写的差各位别介意;还有博客新版页面不知道怎么传图片,只能口述想法
1.需求:需要实现在登录页,有一个大图缓慢滚动
2.思路:大图本身是几千像素的宽度,不可能直接加载,会OOM报错;所以应该是切成同样高度和宽度的较小的图片(尽量)
3.资料(转载文章):https://www.jianshu.com/p/f36f68c3de46,这篇文章算是思路对的了,但是跑出来的效果不是我想要的,所以需要做魔改~
4.魔改(开玩笑~)
我先说下上面那个大佬写的文章里我遇到的问题和解决办法(拜托先去看下我上面发的那个博客,不然下面我说的改动地方可能看不懂),最后会贴上我自己的代码,GIF不会弄,但是我已经在自己的APP上实现了这个效果,应该是可以的
(1)MarqueeView里的addViewInQueue方法
我希望的拉伸处理办法是高度要拉伸到和屏幕高度一致,图片宽度也要按照这个比例拉伸,所以肯定要改这个lp参数,不能是wrap.下面是我的改动:
public void addImageInQueue(int drawable){ //在不加载图片的前提下获得图片的宽高,否则很容易OOM BitmapFactory.Options options = new BitmapFactory.Options(); /** * 最关键在此,把options.inJustDecodeBounds = true; * 这里再decodeFile(),返回的bitmap为空,但此时调用options.outHeight时,已经包含了图片的高了 * decodeResource道理也是一样的 */ options.inJustDecodeBounds = true; Bitmap bitmap = BitmapFactory.decodeResource(getResources(), drawable,options);// 此时返回的bitmap为null /** *options.outHeight为原始图片的高 */ int height = options.outHeight; int width = options.outWidth; int imageWidth = width*screenHeight/height;//将图片的高度拉伸到和屏幕高度一样,然后获取等比拉伸后图片应该的宽度 LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(imageWidth, screenHeight); ImageView view = new ImageView(getContext()); view.setLayoutParams(lp); /*view.setImageResource(drawable);*/ Glide.with(getContext()).load(drawable).placeholder(R.color.white).into(view); view.setScaleType(ImageView.ScaleType.FIT_XY);//设置图片填充满控件 mainLayout.addView(view); viewWidth = viewWidth + imageWidth; }
BitmapFactory.Options 非常好用,因为如果直接通过Bitmap获取图片的宽高,很容易OOM,用option的话实际上bitmap还为null,没有非内存造成压力,特别是图多的时候
(2).MarqueeView里startScroll()和重写的run()方法
要改这两个方法,是因为我要实现2个效果:
从左往右滑,拼起来的图应该先显示最右边的那部分,然后往右划,一直滑到最左边的图,所以起始的currentX应该是图片总长度减去屏幕宽度,
从右往左滑,一开始就直接显示最左边图的就行了全额,所以起始的currentX应该是0
需要说明的是,这里
mainLayout.scrollTo(currentX, 0);
这个方法,currentX如果为正:图片起始左下角x轴是0,滚动到正数,图片左边有部分不显示
current为负,正好相反,图片右边有部分不显示
从左往右的时候,起始currentX是正数,然后递减1个像素,,看起来图片就是从左往右移了
负数原理相反
我觉得这个才是这个自定义View的精髓,感谢原作者的分析
(3)scroll_content的布局是有问题的,里面没有设置orientation
android:orientation="horizontal"
贴下我改了之后的代码,里面设置了初始值,可以去掉,我这是自己要用
//开始滚动 public void startScroll(){ removeCallbacks(this); //必须要保证所有图片拉伸后总宽度大于屏幕宽度 if(viewWidth > screenWidth){ viewWidth = viewWidth - screenWidth; currentX = (scrollDirection == LEFT_TO_RIGHT ? viewWidth : 0); if(isSetFirtsX) currentX = firtsX;//如果设置了起始值,就使用起始值 post(this); } }
@Override public void run() { switch (scrollDirection){ case LEFT_TO_RIGHT: mainLayout.scrollTo(currentX, 0); currentX --; if (currentX == 0) { mainLayout.scrollTo(viewWidth, 0); currentX = viewWidth; } break; case RIGHT_TO_LEFT: mainLayout.scrollTo(currentX, 0); currentX ++; if (currentX == viewWidth) { mainLayout.scrollTo(0, 0); currentX = 0; } break; default: break; }然后我贴下完整的代码
public class MarqueeView extends HorizontalScrollView implements Runnable { private Context context; private LinearLayout mainLayout;//跑马灯滚动部分 private int scrollSpeed = 5;//滚动速度 private int scrollDirection = LEFT_TO_RIGHT;//滚动方向 private int currentX;//当前x坐标 private int viewMargin = 20;//View间距 private int viewWidth;//View总宽度 private int screenWidth;//屏幕宽度 private int screenHeight;//屏幕高度 public static final int LEFT_TO_RIGHT = 1; public static final int RIGHT_TO_LEFT = 2; private boolean isSetFirtsX = false;//true的时候使用起始值 public boolean isSetFirtsX() { return isSetFirtsX; } public MarqueeView setSetFirtsX(boolean setFirtsX) { isSetFirtsX = setFirtsX; return this; } private int firtsX;//起始值,可以设置负数和0,根据isSetFirtsX是否为true判断是否使用 public int getFirtsX() { return firtsX; } public void setFirtsX(int firtsX) { this.firtsX = firtsX; } public int getCurrentX() { return currentX; } public void setCurrentX(int currentX) { this.currentX = currentX; } public MarqueeView(Context context) { this(context, null); } public MarqueeView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public MarqueeView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); this.context = context; initView(); } void initView() { WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE); screenWidth = wm.getDefaultDisplay().getWidth(); screenHeight = wm.getDefaultDisplay().getHeight(); mainLayout = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.scroll_content, null); this.addView(mainLayout); } public void addImagesInQueue(List<Integer> drawables){ for (int drawable : drawables){ addImageInQueue(drawable); } } public void addImageInQueue(int drawable){ //在不加载图片的前提下获得图片的宽高,否则很容易OOM BitmapFactory.Options options = new BitmapFactory.Options(); /** * 最关键在此,把options.inJustDecodeBounds = true; * 这里再decodeFile(),返回的bitmap为空,但此时调用options.outHeight时,已经包含了图片的高了 * decodeResource道理也是一样的 */ options.inJustDecodeBounds = true; Bitmap bitmap = BitmapFactory.decodeResource(getResources(), drawable,options);// 此时返回的bitmap为null /** *options.outHeight为原始图片的高 */ int height = options.outHeight; int width = options.outWidth; int imageWidth = width*screenHeight/height;//将图片的高度拉伸到和屏幕高度一样,然后获取等比拉伸后图片应该的宽度 LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(imageWidth, screenHeight); ImageView view = new ImageView(getContext()); view.setLayoutParams(lp); /*view.setImageResource(drawable);*/ Glide.with(getContext()).load(drawable).placeholder(R.color.white).into(view); view.setScaleType(ImageView.ScaleType.FIT_XY);//设置图片填充满控件 mainLayout.addView(view); viewWidth = viewWidth + imageWidth; } //开始滚动 public void startScroll(){ removeCallbacks(this); //必须要保证所有图片拉伸后总宽度大于屏幕宽度 if(viewWidth > screenWidth){ viewWidth = viewWidth - screenWidth; currentX = (scrollDirection == LEFT_TO_RIGHT ? viewWidth : 0); if(isSetFirtsX) currentX = firtsX;//如果设置了起始值,就使用起始值 post(this); } } //停止滚动 public void stopScroll(){ removeCallbacks(this); } //设置View间距 public void setViewMargin(int viewMargin){ this.viewMargin = viewMargin; } //设置滚动速度 public void setScrollSpeed(int scrollSpeed){ this.scrollSpeed = scrollSpeed; } //设置滚动方向 默认从左向右 public void setScrollDirection(int scrollDirection){ this.scrollDirection = scrollDirection; } @Override public void run() { switch (scrollDirection){ case LEFT_TO_RIGHT: mainLayout.scrollTo(currentX, 0); currentX --; if (currentX == 0) { mainLayout.scrollTo(viewWidth, 0); currentX = viewWidth; } break; case RIGHT_TO_LEFT: mainLayout.scrollTo(currentX, 0); currentX ++; if (currentX == viewWidth) { mainLayout.scrollTo(0, 0); currentX = 0; } break; default: break; } postDelayed(this, 50 / scrollSpeed); } @Override public boolean onTouchEvent(MotionEvent ev) { return false; } }调用代码也很简单
private void initMarqueeView(){ List<Integer> list = new ArrayList<>(); list.add(R.drawable.bg_first_01); list.add(R.drawable.bg_first_02); list.add(R.drawable.bg_first_03); list.add(R.drawable.bg_first_04); list.add(R.drawable.bg_first_05); list.add(R.drawable.bg_first_06); marquee_view.addImagesInQueue(list); marquee_view.setScrollSpeed(8); marquee_view.setScrollDirection(MarqueeView.RIGHT_TO_LEFT); marquee_view.startScroll(); }
scroll_content布局的代码
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent"> </LinearLayout>
到此结束,希望对大家有帮助,GIF真的不会搞,见谅