自定义ViewGroup实现随机泡泡效果
来源:互联网 发布:白蜡杆 淘宝 编辑:程序博客网 时间:2024/05/01 20:16
因为项目需要,去学习了自定义ViewGroup,第一次写自定义控件,算是给自己记个笔记,也希望可以帮到有需要的朋友,如果有写的不好的地方,还请大神指导。有问题可以加群:421448830 交流。
1、先看看效果图
2、自定义ViewGroup的代码:因为我们项目需求最多是四个,所以我只写了四个的情况,如果有其他的需求,可在此基础上修改,不过这个不建议过多数量的子布局,少量可以使用。且计算时要注意当出现最多子view的数量的时候,父布局的宽高要能放的下所有的子view。
public class MyViewGroup extends ViewGroup { private static final String TAG = "My_ViewGroup"; public MyViewGroup(Context context) { super(context); } public MyViewGroup(Context context, AttributeSet attrs) { super(context, attrs); } @Override public LayoutParams generateLayoutParams(AttributeSet attrs) { return new MarginLayoutParams(getContext(), attrs); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { /** * 获得此ViewGroup上级容器为其推荐的宽和高,以及计算模式 */ int widthMode = MeasureSpec.getMode(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int sizeWidth = MeasureSpec.getSize(widthMeasureSpec); int sizeHeight = MeasureSpec.getSize(heightMeasureSpec); // 计算出所有的childView的宽和高 measureChildren(widthMeasureSpec, heightMeasureSpec); /** * 记录如果是wrap_content是设置的宽和高 */ int width = 0; int height = 0; int cCount = getChildCount(); int cWidth = 0; int cHeight = 0; MarginLayoutParams cParams = null; // 用于计算左边两个childView的高度 int lHeight = 0; // 用于计算右边两个childView的高度,最终高度取二者之间大值 int rHeight = 0; // 用于计算上边两个childView的宽度 int tWidth = 0; // 用于计算下面两个childiew的宽度,最终宽度取二者之间大值 int bWidth = 0; /** * 根据childView计算的出的宽和高,以及设置的margin计算容器的宽和高,主要用于容器是warp_content时 */ for (int i = 0; i < cCount; i++) { View childView = getChildAt(i); cWidth = childView.getMeasuredWidth(); cHeight = childView.getMeasuredHeight(); cParams = (MarginLayoutParams) childView.getLayoutParams(); // 上面两个childView if (i == 0 || i == 1) { tWidth += cWidth + cParams.leftMargin + cParams.rightMargin; } if (i == 2 || i == 3) { bWidth += cWidth + cParams.leftMargin + cParams.rightMargin; } if (i == 0 || i == 2) { lHeight += cHeight + cParams.topMargin + cParams.bottomMargin; } if (i == 1 || i == 3) { rHeight += cHeight + cParams.topMargin + cParams.bottomMargin; } } width = Math.max(tWidth, bWidth); height = Math.max(lHeight, rHeight); /** * 如果是wrap_content设置为我们计算的值 * 否则:直接设置为父容器计算的值 */ setMeasuredDimension((widthMode == MeasureSpec.EXACTLY) ? sizeWidth : width, (heightMode == MeasureSpec.EXACTLY) ? sizeHeight : height); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { int marginTop = 0; //最大的marginTop值 int cCount = getChildCount(); int cWidth = 0; int cHeight = 0; MarginLayoutParams cParams = null; int top_one = 0; int top_two = 0; int top_three = 0; /** * 遍历所有childView根据其宽和高,以及margin进行布局 */ for (int i = 0; i < cCount; i++) { View childView = getChildAt(i); cWidth = childView.getMeasuredWidth(); cHeight = childView.getMeasuredHeight(); cParams = (MarginLayoutParams) childView.getLayoutParams(); int cl = 0, ct = 0, cr = 0, cb = 0; switch (cCount) { case 1: marginTop = getHeight() - cHeight - cParams.bottomMargin; break; case 2: marginTop = (getHeight() / 2) - cHeight - cParams.bottomMargin; break; case 3: marginTop = (getHeight() / 3) - cHeight - cParams.bottomMargin; break; case 4: marginTop = (getHeight() / 4) - cHeight - cParams.bottomMargin; break; } switch (i) { case 0: top_one = (int) (Math.random() * marginTop); cl = (int) (Math.random() * (getWidth() - cWidth - cParams.rightMargin)); ct = top_one; break; case 1: top_two = top_one + cHeight + (int) (Math.random() * marginTop); cl = (int) (Math.random() * (getWidth() - cWidth - cParams.rightMargin)); ct = top_two; break; case 2: top_three = top_two + cHeight + (int) (Math.random() * marginTop); cl = (int) (Math.random() * (getWidth() - cWidth - cParams.rightMargin)); ct = top_three; break; case 3: cl = (int) (Math.random() * (getWidth() - cWidth - cParams.rightMargin)); ct = top_three + cHeight + (int) (Math.random() * marginTop); break; } cr = cl + cWidth; cb = cHeight + ct; childView.layout(cl, ct, cr, cb); } }}
3、activity_main.xml布局:使用这个自定义控件,其宽高最好给固定值或者match_parent,因为每一次出现的子布局数量不定,需要根据父布局的宽高决定其位置的随机数。
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#FFFFFF" android:orientation="vertical"> <com.xiaoxiao.myviewgroup.MyViewGroup android:id="@+id/my_viewgroup" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_above="@+id/btn_start"/> <Button android:id="@+id/btn_start" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentRight="true" android:layout_marginRight="10dp" android:text="开始" /></RelativeLayout>
4、每一个随机冒出的泡泡的布局,item_viewgroup_paopao.xml布局,这个可以根据自己的需要去写。其中CircleImageView是圆形头像的自定义控件。
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content"> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginLeft="-20dp" android:layout_toRightOf="@+id/img_head" android:background="@drawable/shape_paopao_background" android:orientation="vertical"> <TextView android:id="@+id/tv_get_task_nick" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="25dp" android:text="ID:2***3" android:textColor="#ef4359" android:textSize="12sp" /> <TextView android:id="@+id/tv_get_task_type" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="25dp" android:text="冒出一个快乐泡泡" android:textColor="#4A4A4B" android:textSize="12sp" /> </LinearLayout> <com.xiaoxiao.myviewgroup.CircleImageView android:id="@+id/img_head" android:layout_width="40dp" android:layout_height="40dp" android:layout_centerVertical="true" android:scaleType="centerCrop" android:src="@drawable/default_head" /></RelativeLayout>
5、MainActivity的代码,PaopaoBean是一个实体类,用来存放数据,可以根据具体情况去写。
public class MainActivity extends AppCompatActivity implements View.OnClickListener { private final static String TAG = "ViewGroupActivity"; List<PaopaoBean> mList = new ArrayList<>(); private RelativeLayout relativeLayout; private boolean isStart = true; private AlphaAnimation alphaAnimation; MyViewGroup my_viewgroup; Button btn_start; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); my_viewgroup = (MyViewGroup) findViewById(R.id.my_viewgroup); btn_start = (Button) findViewById(R.id.btn_start); btn_start.setText("开始"); btn_start.setOnClickListener(this); } private void showDate() { mList.clear(); Random random = new Random(); int count = random.nextInt(4) + 1; Log.e(TAG, "count==" + count); int id_front; int id_after; int task_type; String task_name = ""; for (int i = 0; i < count; i++) { task_type = random.nextInt(3); id_front = random.nextInt(9) + 1; id_after = random.nextInt(10); switch (task_type) { case 0: task_name = "开心"; break; case 1: task_name = "快乐"; break; case 2: task_name = "幸福"; break; } mList.add(new PaopaoBean("ID:" + id_front + "***" + id_after, "冒出一个" + task_name + "泡泡")); } getPaopao(mList, my_viewgroup); } private void getPaopao(List<PaopaoBean> paopao, MyViewGroup viewgroup) { viewgroup.removeAllViews(); for (int i = 0; i < paopao.size(); i++) { relativeLayout = (RelativeLayout) LayoutInflater.from(this).inflate(R.layout.item_viewgroup_paopao, my_viewgroup, false); ImageView img_head = (ImageView) relativeLayout.findViewById(R.id.img_head); TextView tv_nick = (TextView) relativeLayout.findViewById(R.id.tv_get_task_nick); TextView tv_type = (TextView) relativeLayout.findViewById(R.id.tv_get_task_type); viewgroup.addView(relativeLayout); Glide.with(this).load(R.drawable.default_head).into(img_head); tv_nick.setText(paopao.get(i).getTv_nick()); tv_type.setText(paopao.get(i).getTv_type()); } generateAlphaAnimation(); } //渐变动画 private void generateAlphaAnimation() { Log.e(TAG, "222"); alphaAnimation = new AlphaAnimation(1f, 0); //渐变动画 alphaAnimation.setDuration(1500); alphaAnimation.setStartOffset(1500); alphaAnimation.start(); my_viewgroup.startAnimation(alphaAnimation); alphaAnimation.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { if (!isStart) { alphaAnimation.cancel(); my_viewgroup.clearAnimation(); mList.clear(); my_viewgroup.removeAllViews(); relativeLayout.removeAllViews(); new Handler().postDelayed(new Runnable() { @Override public void run() { if (!isStart) { showDate(); } } }, 2000); } } @Override public void onAnimationRepeat(Animation animation) { } }); } @Override public void onClick(View v) { if (isStart) { btn_start.setText("停止"); isStart = false; showDate(); } else { alphaAnimation.cancel(); my_viewgroup.clearAnimation(); mList.clear(); my_viewgroup.removeAllViews(); btn_start.setText("开始"); relativeLayout.removeAllViews(); isStart = true; } }}
6、PaopaoBean 类:
public class PaopaoBean { private String tv_nick; private String tv_type; public PaopaoBean( String tv_nick, String tv_type) { this.tv_nick = tv_nick; this.tv_type = tv_type; } public String getTv_nick() { return tv_nick; } public void setTv_nick(String tv_nick) { this.tv_nick = tv_nick; } public String getTv_type() { return tv_type; } public void setTv_type(String tv_task) { this.tv_type = tv_task; }}
源码地址:http://blog.csdn.net/miaoxiaomo/article/details/52936832
6 0
- 自定义ViewGroup实现随机泡泡效果
- 自定义ViewGroup实现瀑布流效果
- 自定义ViewGroup实现进度动态更新效果
- 自定义ViewGroup实现标签云效果。
- 自定义ViewGroup实现ViewPager的滑动效果
- 自定义ViewGroup实现弹性滑动效果
- 自定义viewGroup实现点击动画效果
- 自定义 ViewGroup 实现子 View 层叠效果
- 自定义ViewGroup实现左滑效果
- 自定义ViewGroup 实现拖动跟快速滚动的效果
- 自定义ViewGroup 实现拖动跟快速滚动的效果
- 自定义ViewGroup 实现拖动跟快速滚动的效果
- 自定义ViewGroup实现类似ViewPager的滑动效果
- 自定义ViewGroup 实现拖动跟快速滚动的效果
- 自定义ViewGroup实现多个单页面上下滑动效果
- 自定义ViewGroup 实现拖动跟快速滚动的效果
- android 自定义viewGroup实现网易左侧菜单效果
- 自定义ViewGroup之QQ5.0侧滑效果实现
- SNMP监控一些常用OID的总结
- hadoop命令详解
- php数据类型转换
- spring整合redis详解
- Windows下Git Bash中文乱码
- 自定义ViewGroup实现随机泡泡效果
- find命令之xargs
- Android studio中预览布局错误:Missing styles. Is the correct theme chosen for this layou
- JAVA基础(12)——反射
- Hibernate——初步认识
- Android按home键之后,再次点击程序图标避免再次重启程序
- 概率论1
- spark 2.0 遇到java.net.URISyntaxException: Relative path in absolute URI
- pandas 常用操作