Androd自定义View实现竖直跑马灯效果

Androd自定义View实现竖直跑马灯效果,对其用自定义控件进行包装;实现其点击回调和自定义视图等功能
跑马灯在我们日常使用的app中还是很常见的,以前做外卖app的时候商家公告就使用了此效果,但是它是横向滚动的,横向滚动多适用于单条信息;但凡涉及到多条信息的滚动展示,用纵向滚动效果会有更好的用户体验,今天我们通过自定义View来看看如何实现纵向跑马灯效果。
MarqueeBean类

public class MarqueeBean<E> {
   private String title;
   private E img;

   public String getTitle() {
       return title;
   }

   public void setTitle(String title) {
       this.title = title;
   }

   public E getImg() {
       return img;
   }

   public void setImg(E img) {
       this.img = img;
   }
}
      **VerMarqueeView类**
public class VerMarqueeView extends ViewFlipper {

  private Context mContext;
  private List<MarqueeBean> marquees;
  private boolean isSetAnimDuration = false;
  private OnItemClickListener onItemClickListener;
  private int interval = 2000;//播放时间间隔
  private int animDuration = 500;//动画时长
  private int textSize = 14;//文字大小
  private boolean isImage = true;//是否显示图片
  private boolean isImageResource = true;//是否是图片资源(还是网络图片Url)

  public VerMarqueeView(Context context, AttributeSet attrs) {
      super(context, attrs);
      init(context, attrs, 0);
  }

  private void init(Context context, AttributeSet attrs, int defStyleAttr) {
      this.mContext = context;
      if (marquees == null) {
          marquees = new ArrayList<>();
      }
      TypedArray typedArray = getContext().obtainStyledAttributes(attrs,
              R.styleable.MarqueeViewStyle, defStyleAttr, 0);
      interval = typedArray.getInteger(R.styleable.MarqueeViewStyle_mvInterval, interval);
      isSetAnimDuration = typedArray.hasValue(R.styleable.MarqueeViewStyle_mvAnimDuration);
      animDuration = typedArray.getInteger(R.styleable.MarqueeViewStyle_mvAnimDuration, animDuration);
      if (typedArray.hasValue(R.styleable.MarqueeViewStyle_mvTextSize)) {
          textSize = (int) typedArray.getDimension(R.styleable.MarqueeViewStyle_mvTextSize, textSize);
          textSize = px2sp(mContext, textSize);
      }
      typedArray.recycle();
      setFlipInterval(interval);
  }

  /**
   * @param notice
   * @description: 根据公告字符串启动轮播
   */
  public void startWithText(final String notice) {
      if (TextUtils.isEmpty(notice)) return;
      getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
          @Override
          public void onGlobalLayout() {
              getViewTreeObserver().addOnGlobalLayoutListener(this);
              startWithFixedWidth(notice, getWidth());
          }
      });
  }

  /**
   * @param marquees
   * @description: 根据公告字符串列表启动轮播
   */
  public void startWithList(List<MarqueeBean> marquees) {
      setMarquees(marquees);
      start();
  }

  //

  /**
   * @param notice
   * @description: 根据宽度和公告字符串启动轮播
   */
  private void startWithFixedWidth(String notice, int width) {
      int noticeLength = notice.length();
      int dpW = px2dp(mContext, width);
      int limit = dpW / textSize;
      if (dpW == 0) {
          throw new RuntimeException("Please set MarqueeView width !");
      }
      List list = new ArrayList();
      if (noticeLength <= limit) {
          list.add(notice);
      } else {
          int size = noticeLength / limit + (noticeLength % limit != 0 ? 1 : 0);
          for (int i = 0; i < size; i++) {
              int startIndex = i * limit;
              int endIndex = ((i + 1) * limit >= noticeLength ? noticeLength : (i + 1) * limit);
              list.add(notice.substring(startIndex, endIndex));
          }
      }
      marquees.addAll(list);
      start();
  }

  /**
   * @description 启动轮播
   */
  public boolean start() {
      if (marquees == null || marquees.size() == 0) return false;
      removeAllViews();
      resetAnimation();
      for (int i = 0; i < marquees.size(); i++) {
          final View view = createView(i);
          final int finalI = i;
          view.setOnClickListener(new OnClickListener() {
              @Override
              public void onClick(View v) {
                  if (onItemClickListener != null) {
                      onItemClickListener.onItemClick(finalI, view);
                  }
              }
          });
          addView(view);
      }
      if (marquees.size() > 1) {
          startFlipping();
      } else {
          stopFlipping();
      }
      return true;
  }

  /**
   * @description 重置动画
   */
  private void resetAnimation() {
      clearAnimation();
      Animation animIn = AnimationUtils.loadAnimation(mContext, R.anim.anim_marquee_in);
      if (isSetAnimDuration) animIn.setDuration(animDuration);
      setInAnimation(animIn);

      Animation animOut = AnimationUtils.loadAnimation(mContext, R.anim.anim_marquee_out);
      if (isSetAnimDuration) animOut.setDuration(animDuration);
      setOutAnimation(animOut);
  }

  /**
   * @param position
   * @return
   * @description 创建ViewFlipper下的View
   */
  private View createView(int position) {
      MarqueeBean marquee = marquees.get(position);
      View view = LayoutInflater.from(mContext).inflate(R.layout.view_marquee, null);
      ImageView ivMarquee = view.findViewById(R.id.ivMarquee);
      TextView tvMarquee = view.findViewById(R.id.tvMarquee);
      tvMarquee.setText(marquee.getTitle());
      if (isImage) {
          ivMarquee.setVisibility(VISIBLE);
          if (isImageResource) {
              ivMarquee.setImageResource((Integer) marquee.getImg());
          } else {
              Glide.with(mContext)
                      .load(marquee.getImg())
                      .placeholder(R.mipmap.ic_launcher)
                      .dontAnimate()
                      .into(ivMarquee);
          }
      }
      tvMarquee.setTextSize(textSize);
      view.setTag(position);
      return view;
  }

  public int getPosition() {
      return (int) getCurrentView().getTag();
  }

  public List<MarqueeBean> getMarquees() {
      return marquees;
  }

  public void setMarquees(List<MarqueeBean> marquees) {
      this.marquees = marquees;
  }

  /**
   * @param isImage
   * @description 是否显示图片
   */
  public void setShowImage(boolean isImage) {
      this.isImage = isImage;
  }

  /**
   * @param isImageResource
   * @description 是否是图片资源(还是网络图片Url)
   */
  public void setShowImageResource(boolean isImageResource) {
      this.isImageResource = isImageResource;
  }

  public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
      this.onItemClickListener = onItemClickListener;
  }

  public interface OnItemClickListener {
      void onItemClick(int position, View view);
  }

  public int px2dp(Context context, float pxValue) {
      final float scale = context.getResources().getDisplayMetrics().density;
      return (int) (pxValue / scale + 0.5f);
  }

  public int px2sp(Context context, float pxValue) {
      final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
      return (int) (pxValue / fontScale + 0.5f);
  }

}

         **MainActivity类**
public class MainActivity extends AppCompatActivity {
  private VerMarqueeView vmText, vmTextImgResource, vmTextImgUrl;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      initView();
      showTextMarquee();
      showTextImgResourceMarquee();
      showTextImgUrlMarquee();
  }

  private void showTextImgResourceMarquee() {
      List<MarqueeBean> marquees = new ArrayList<>();
      for (int i = 0; i < 3; i++) {
          MarqueeBean marquee = new MarqueeBean();
          marquee.setImg(R.drawable.head_man);
          marquee.setTitle("我是本地图片和文字的跑马灯" + i);
          marquees.add(marquee);
      }
      vmTextImgResource.setShowImage(true);
      vmTextImgUrl.setShowImageResource(true);
      vmTextImgResource.startWithList(marquees);
  }

  private void initView() {
      vmText = findViewById(R.id.vm_main_text);
      vmTextImgResource = findViewById(R.id.vm_main_text_img_resource);
      vmTextImgUrl = findViewById(R.id.vm_main_text_img_url);
  }

  private void showTextImgUrlMarquee() {
      String[] imgs = new String[]{
              "https://ws1.sinaimg.cn/large/610dc034ly1fhovjwwphfj20u00u04qp.jpg",
              "https://ws1.sinaimg.cn/large/610dc034ly1fhnqjm1vczj20rs0rswia.jpg",
              "https://ws1.sinaimg.cn/large/610dc034ly1fhj5228gwdj20u00u0qv5.jpg"};
      List<MarqueeBean> marqueeBeanList = new ArrayList<>();
      for (int i = 0; i < 3; i++) {
          MarqueeBean marquee = new MarqueeBean();
          marquee.setImg(imgs[i]);
          marquee.setTitle("我是网络图片和文字的跑马灯" + i);
          marqueeBeanList.add(marquee);
      }
      vmTextImgUrl.setShowImage(true);
      vmTextImgUrl.setShowImageResource(false);
      vmTextImgUrl.startWithList(marqueeBeanList);
      vmTextImgUrl.setOnItemClickListener(new VerMarqueeView.OnItemClickListener() {
          @Override
          public void onItemClick(int position, View textView) {
              Toast.makeText(MainActivity.this, "======" + position, Toast.LENGTH_SHORT).show();
          }
      });
  }

  private void showTextMarquee() {
      List<MarqueeBean> marqueeBeanList = new ArrayList<>();
      for (int i = 0; i < 3; i++) {
          MarqueeBean marquee1 = new MarqueeBean();
          marquee1.setTitle("我是没有图片的跑马灯" + i);
          marqueeBeanList.add(marquee1);
      }
      vmText.setShowImage(false);
      vmText.startWithList(marqueeBeanList);
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值