Android自定义ViewGroup实现标签流效果

 更新时间:2022年06月28日 10:29:33   作者:Android师哥  
这篇文章主要为大家详细介绍了Android自定义ViewGroup实现标签流效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
(福利推荐:【腾讯云】服务器最新限时优惠活动,云服务器1核2G仅99元/年、2核4G仅768元/3年,立即抢购>>>:9i0i.cn/qcloud

(福利推荐:你还在原价购买阿里云服务器?现在阿里云0.8折限时抢购活动来啦!4核8G企业云服务器仅2998元/3年,立即抢购>>>:9i0i.cn/aliyun

本文实例为大家分享了Android自定义ViewGroup实现标签流效果的具体代码,供大家参考,具体内容如下

自定义View,一是为了满足设计需求,二是开发者进阶的标志之一。随心所欲就是我等奋斗的目标!!!

效果

实现逻辑

明确需求

1、标签流效果;
2、可以动态添加标签;
3、标签需要有点击效果以及回调;

整理思路

既然要装载标签,就需要自定义ViewGroup ,而自定义ViewGroup 比较复杂的就是onLayout()中对子View的排版。既然是标签,在一行中一定要显示完整,在排版的时候注意这一点,需要添加判断!其次,标签要有点击事件,这里的实现我们可以借助子View的点击事件封装一个接口,实现我们自己的点击事件!

要点

1、对于子View的测量;
2、对于子View的排版;

Ps: 需要注意的是给子View设置背景Drawable的时候不可以设置同一个Drawable,否则会出现错乱情况!见getSonView()方法中完整代码

/**
?* 自定义ViewGroup实现标签流效果
?*
?* @attr customInterval ?//标签之间的间隔
?* @attr customSelectMode ?//标签选项模式
?* @attr customSonBackground ? //标签背景
?* @attr customSonPaddingBottom ? //标签底部内边距
?* @attr customSonPaddingLeft ?//标签左边内边距
?* @attr customSonPaddingRight ?//标签右边内边距
?* @attr customSonPaddingTop ?//标签顶部内边距
?* @attr customSonTextColor ?//标签文字颜色
?* @attr customSonTextSize ?//标签文字尺寸
?*/
public class CustomLableView extends ViewGroup {
? ? private static final String TAG = "CustomLableView";
? ? private int customInterval = 15;
? ? private int customSonPaddingLeft = 20;
? ? private int customSonPaddingRight = 20;
? ? private int customSonPaddingTop = 10;
? ? private int customSonPaddingBottom = 10;
? ? private Drawable customSonBackground = null;
? ? private float customSonTextSize = 0;
? ? private ColorStateList customSonTextColor = ColorStateList.valueOf(0xFF000000);
? ? private ArrayList<String> mSonTextContents = new ArrayList<>();
? ? private ArrayList<TextView> mSonTextViews = new ArrayList<>();
? ? private Context mContext = null;
? ? private OnItemClickListener mOnItemClickListener;
? ? private int customSelectMode;

? ? public CustomLableView(Context context) {
? ? ? ? this(context, null);
? ? }

? ? public CustomLableView(Context context, AttributeSet attrs) {
? ? ? ? this(context, attrs, 0);
? ? }

? ? public CustomLableView(Context context, AttributeSet attrs, int defStyleAttr) {
? ? ? ? super(context, attrs, defStyleAttr);
? ? ? ? this.mContext = context;
? ? ? ? //初始化自定义属性
? ? ? ? initAttrs(context, attrs);
? ? }


? ? @Override
? ? protected void onLayout(boolean changed, int l, int t, int r, int b) {
? ? ? ? int left = customInterval;
? ? ? ? int top = customInterval;
? ? ? ? int mMeasuredWidth = this.getMeasuredWidth();
? ? ? ? //防止重复添加
? ? ? ? CustomLableView.this.removeAllViews();
? ? ? ? for (int i = 0; i < mSonTextViews.size(); i++) {
? ? ? ? ? ? final TextView mTextView = mSonTextViews.get(i);
? ? ? ? ? ? //将当前子View添加到ViewGroup中
? ? ? ? ? ? CustomLableView.this.addView(mTextView);
? ? ? ? ? ? //获取当前子View的宽高
? ? ? ? ? ? int measuredHeight = mTextView.getMeasuredHeight();
? ? ? ? ? ? int measuredWidth = mTextView.getMeasuredWidth();
? ? ? ? ? ? //判断一行是否可显示
? ? ? ? ? ? if ((mMeasuredWidth - left) >= (measuredWidth + customInterval * 2)) {//一行可显示
? ? ? ? ? ? ? ? /**
? ? ? ? ? ? ? ? ?* 1、(mMeasuredWidth - left) X轴剩余空间
? ? ? ? ? ? ? ? ?* 2、(measuredWidth + customInterval * 2) 当前子View和间隔需要的空间
? ? ? ? ? ? ? ? ?*/
? ? ? ? ? ? ? ? mTextView.layout(left, top, left + measuredWidth, top + measuredHeight);
? ? ? ? ? ? ? ? left += (measuredWidth + customInterval);
? ? ? ? ? ? } else {//需要换行显示
? ? ? ? ? ? ? ? //还原X轴的起始位置
? ? ? ? ? ? ? ? left = customInterval;
? ? ? ? ? ? ? ? //Y轴高度增加
? ? ? ? ? ? ? ? top += (measuredHeight + customInterval);
? ? ? ? ? ? ? ? mTextView.layout(left, top, left + measuredWidth, top + measuredHeight);
? ? ? ? ? ? ? ? left += (measuredWidth + customInterval);
? ? ? ? ? ? }
? ? ? ? }
? ? }

? ? @Override
? ? protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
? ? ? ? super.onMeasure(widthMeasureSpec, heightMeasureSpec);
? ? ? ? //控件宽度
? ? ? ? int mMeasureViewWidht = MeasureSpec.getSize(widthMeasureSpec);
? ? ? ? //显示行数
? ? ? ? int line = 1;
? ? ? ? //每行当前宽度
? ? ? ? int lineWidht = customInterval;
? ? ? ? //每行高度(子View的高度)
? ? ? ? int mSonMeasuredHeight = 0;
? ? ? ? mSonTextViews.clear();
? ? ? ? for (int i = 0; i < mSonTextContents.size(); i++) {
? ? ? ? ? ? TextView mSonView = getSonView(i, mSonTextContents.get(i));
? ? ? ? ? ? //对子View进行测量
? ? ? ? ? ? mSonView.measure(0, 0);
? ? ? ? ? ? //获取子View的测量尺寸
? ? ? ? ? ? int mSonMeasuredWidth = mSonView.getMeasuredWidth() + customInterval;
? ? ? ? ? ? mSonMeasuredHeight = mSonView.getMeasuredHeight() + customInterval;
? ? ? ? ? ? //添加到数组中
? ? ? ? ? ? mSonTextViews.add(mSonView);
? ? ? ? ? ? if (mMeasureViewWidht >= mSonMeasuredWidth) {
? ? ? ? ? ? ? ? if ((mMeasureViewWidht - lineWidht) >= mSonMeasuredWidth) {
? ? ? ? ? ? ? ? ? ? lineWidht += mSonMeasuredWidth;
? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? //行数自加1
? ? ? ? ? ? ? ? ? ? line += 1;
? ? ? ? ? ? ? ? ? ? lineWidht = customInterval + mSonMeasuredWidth;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? mSonTextViews.clear();
? ? ? ? ? ? ? ? setMeasuredDimension(0, 0);
? ? ? ? ? ? ? ? return;
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? //设置控件尺寸
? ? ? ? setMeasuredDimension(mMeasureViewWidht, mSonMeasuredHeight * line + customInterval);
? ? }

? ? /**
? ? ?* 设置标签内容集合
? ? ?*
? ? ?* @param sonContent 标签内容
? ? ?*/
? ? public void setSonContent(ArrayList<String> sonContent) {
? ? ? ? if (sonContent != null) {
? ? ? ? ? ? mSonTextContents.clear();
? ? ? ? ? ? mSonTextContents.addAll(sonContent);
? ? ? ? ? ? requestLayout();
? ? ? ? }
? ? }

? ? /**
? ? ?* 添加一个标签
? ? ?*
? ? ?* @param sonContent 标签内容
? ? ?*/
? ? public void addSonContent(String sonContent) {
? ? ? ? if (!TextUtils.isEmpty(sonContent)) {
? ? ? ? ? ? mSonTextContents.add(0, sonContent);
? ? ? ? ? ? requestLayout();
? ? ? ? }
? ? }

? ? /**
? ? ?* 设置标签点击事件
? ? ?*
? ? ?* @param onItemClickListener 回调接口
? ? ?*/
? ? public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
? ? ? ? this.mOnItemClickListener = onItemClickListener;
? ? }

? ? /**
? ? ?* 获取子View
? ? ?*
? ? ?* @return TextView
? ? ?*/
? ? private TextView getSonView(final int i, final String content) {
? ? ? ? if (mContext != null) {
? ? ? ? ? ? TextView mTextView = new TextView(mContext);
? ? ? ? ? ? mTextView.setTextColor(customSonTextColor);
? ? ? ? ? ? mTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, customSonTextSize);
? ? ? ? ? ? //不可以设置相同的Drawable
? ? ? ? ? ? mTextView.setBackgroundDrawable(customSonBackground.getConstantState().newDrawable());
? ? ? ? ? ? mTextView.setText(content);
? ? ? ? ? ? mTextView.setPadding(customSonPaddingLeft, customSonPaddingTop, customSonPaddingRight, customSonPaddingBottom);
? ? ? ? ? ? //消除TextView默认的上下内边距
? ? ? ? ? ? mTextView.setIncludeFontPadding(false);
? ? ? ? ? ? mTextView.setOnClickListener(new OnClickListener() {
? ? ? ? ? ? ? ? @Override
? ? ? ? ? ? ? ? public void onClick(View v) {
? ? ? ? ? ? ? ? ? ? //选择模式
? ? ? ? ? ? ? ? ? ? if (customSelectMode != 102) {
? ? ? ? ? ? ? ? ? ? ? ? for (int j = 0; j < mSonTextViews.size(); j++) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? mSonTextViews.get(j).setSelected(false);
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? v.setSelected(true);
? ? ? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? ? ? v.setSelected(true);
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? if (mOnItemClickListener != null) {
? ? ? ? ? ? ? ? ? ? ? ? mOnItemClickListener.onItemClick(v, i, content);
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? });
? ? ? ? ? ? return mTextView;
? ? ? ? }
? ? ? ? return null;
? ? }

? ? /**
? ? ?* 初始化自定义属性
? ? ?*
? ? ?* @param context
? ? ?* @param attrs
? ? ?*/
? ? private void initAttrs(Context context, AttributeSet attrs) {
? ? ? ? TypedArray mTypedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomLableView);
? ? ? ? customSonBackground = mTypedArray.getDrawable(R.styleable.CustomLableView_customSonBackground);
? ? ? ? customInterval = (int) mTypedArray.getDimension(R.styleable.CustomLableView_customInterval, customInterval);
? ? ? ? customSonPaddingLeft = (int) mTypedArray.getDimension(R.styleable.CustomLableView_customSonPaddingLeft, customSonPaddingLeft);
? ? ? ? customSonPaddingRight = (int) mTypedArray.getDimension(R.styleable.CustomLableView_customSonPaddingRight, customSonPaddingRight);
? ? ? ? customSonPaddingTop = (int) mTypedArray.getDimension(R.styleable.CustomLableView_customSonPaddingTop, customSonPaddingTop);
? ? ? ? customSonPaddingBottom = (int) mTypedArray.getDimension(R.styleable.CustomLableView_customSonPaddingBottom, customSonPaddingBottom);
? ? ? ? customSonTextSize = (int) mTypedArray.getDimension(R.styleable.CustomLableView_customSonTextSize, 0);
? ? ? ? customSonTextColor = mTypedArray.getColorStateList(R.styleable.CustomLableView_customSonTextColor);
? ? ? ? customSelectMode = mTypedArray.getInt(R.styleable.CustomLableView_customSelectMode, 101);
? ? ? ? if (customSonTextSize == 0) {
? ? ? ? ? ? customSonTextSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 14, getResources().getDisplayMetrics());
? ? ? ? }
? ? ? ? mTypedArray.recycle();
? ? }


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

自定义属性

<declare-styleable name="CustomLableView">
? ? ? ? <attr name="customSonBackground" format="reference" />
? ? ? ? <attr name="customInterval" format="dimension" />
? ? ? ? <attr name="customSonPaddingLeft" format="dimension" />
? ? ? ? <attr name="customSonPaddingRight" format="dimension" />
? ? ? ? <attr name="customSonPaddingTop" format="dimension" />
? ? ? ? <attr name="customSonPaddingBottom" format="dimension" />
? ? ? ? <attr name="customSonTextSize" format="dimension" />
? ? ? ? <attr name="customSonTextColor" format="color" />
? ? ? ? <attr name="customSelectMode">
? ? ? ? ? ? <enum name="alone" value="101" />
? ? ? ? ? ? <enum name="multi" value="102" />
? ? ? ? </attr>
</declare-styleable>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持程序员之家。

相关文章

  • Flutter使用Android原生播放器详解

    Flutter使用Android原生播放器详解

    这篇文章主要介绍了Flutter使用Android原生播放器,自己写Flutter也有一段时间了,刚好最近公司的项目想在PC端重写一个,就想着用Flutter实现试一试
    2023-02-02
  • Android动画系列之帧动画和补间动画的示例代码

    Android动画系列之帧动画和补间动画的示例代码

    Android 提供三种动画:帧动画、补间动画和属性动画,本篇文章介绍帧动画以及补间动画的使用,属性动画的使用将在后面的文章中分享,那就来复习一下这两种动画的使用吧
    2020-09-09
  • Android中TextView和ImageView实现倾斜效果

    Android中TextView和ImageView实现倾斜效果

    这篇文章主要为大家详细介绍了Android中TextView和ImageView实现倾斜效果,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-08-08
  • Android自定义倒计时按钮

    Android自定义倒计时按钮

    这篇文章主要为大家详细介绍了Android自定义倒计时按钮,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-05-05
  • Ubuntu中为Android简单介绍硬件抽象层(HAL)

    Ubuntu中为Android简单介绍硬件抽象层(HAL)

    本文主要介绍在Android 的硬件抽象层,学习Android 硬件抽象层(HAL)对理解整个Android都是有非常大的作用,有兴趣的小伙伴可以参考下
    2016-08-08
  • Android线程池控制并发数多线程下载

    Android线程池控制并发数多线程下载

    这篇文章主要为大家详细介绍了Android线程池控制并发数多线程下载,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-01-01
  • Android实现界面左右滑动切换功能

    Android实现界面左右滑动切换功能

    相信大家一定都使用过手机QQ和微信之类的软件,当我们使用时不难发现其界面的切换不仅可以通过点击页标签来实现,还可以通过左右滑动来实现的,下面小编给大家介绍下如何实现这个功能
    2016-12-12
  • 如何为RecyclerView添加分隔线

    如何为RecyclerView添加分隔线

    这篇文章主要为大家详细介绍了如何为RecyclerView添加分隔线,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-12-12
  • Android viewpager无限轮播获取网络图片功能

    Android viewpager无限轮播获取网络图片功能

    这篇文章主要为大家详细介绍了Android viewpager无限轮播获取网络图片功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-09-09
  • Android Walker登录记住密码页面功能实现

    Android Walker登录记住密码页面功能实现

    这篇文章主要为大家详细介绍了Android Walker登录记住密码页面功能的实现,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-05-05

最新评论

?


http://www.vxiaotou.com