本文主要介绍Android中飞入飞出布局及随机布局的实现方式,具体的效果如下:

实现飞入飞出效果 FlyLayout.java

/** * Created by MG_ZXC on 2018/3/24. */public class FlyLayout extends FrameLayout implements Animation.AnimationListener {    private static final double MAX_VELOCITY_TOUCH_SLOP = 80;    private boolean aninationIsPlaying;    private GestureDetector mGestureDetector;    public FlyLayout(@NonNull Context context) {        this(context, null);    }    public FlyLayout(@NonNull Context context, @Nullable AttributeSet attrs) {        this(context, attrs, 0);    }    public FlyLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        mGestureDetector = new GestureDetector(context,new GestureDetector.SimpleOnGestureListener(){            @Override            public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {                if (!aninationIsPlaying && Math.hypot(velocityX, velocityY) > MAX_VELOCITY_TOUCH_SLOP) {                    playAnimation();                }                return super.onFling(e1, e2, velocityX, velocityY);            }        });    }    private void playAnimation() {        AnimationSet animationSet = new AnimationSet(true);        animationSet.setAnimationListener(this);        ScaleAnimation scaleAnimation = new ScaleAnimation(1.0f, 1.2f, 1.0f, 1.2f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);        AlphaAnimation alphaAnimation = new AlphaAnimation(1, 0);        //渐变动画推迟执行        alphaAnimation.setStartOffset(1000);        animationSet.addAnimation(scaleAnimation);        animationSet.addAnimation(alphaAnimation);        animationSet.setDuration(2000);        animationSet.setFillAfter(true);        View topChildView = getChildAt(getChildCount() - 1);        topChildView.startAnimation(animationSet);    }   //如果单用这个控件只需要改用下面的注释 onTouchEvent    @Override    public boolean onInterceptTouchEvent(MotionEvent ev) {        mGestureDetector.onTouchEvent(ev);        return super.onInterceptTouchEvent(ev);    }   /* @Override    public boolean onTouchEvent(MotionEvent event) {        mGestureDetector.onTouchEvent(event);        return true;    }*/    @Override    public void onAnimationStart(Animation animation) {        aninationIsPlaying = true;    }    //当动画执行完毕切换到下一个页面    // topView.clearAnimation();----->触发动画的监听器的调用----->onAnimationEnd    @Override    public void onAnimationEnd(Animation animation) {        View topView = getChildAt(getChildCount() - 1);        //view的动画执行完毕,下一次再次执行动画需要将之前的动画清除        //解决动画再次执行可能不会执行        animation.setAnimationListener(null);        topView.clearAnimation();        removeView(topView);        addView(topView, 0);        aninationIsPlaying = false;    }    @Override    public void onAnimationRepeat(Animation animation) {    }}

随机布局 RandomLayout.java

/** * Created by MG_ZXC on 2018/3/24. */public class RandomLayout extends FrameLayout {    private static final int MAX_TRY_LAYOUT_COUNT = 30;    public RandomLayout(@NonNull Context context) {        super(context,null);    }    public RandomLayout(@NonNull Context context, @Nullable AttributeSet attrs) {        super(context, attrs,0);    }    public RandomLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);    }    private List mChildViewIndexAreas = new ArrayList<>();    private static class ChildViewIndexArea implements Comparable<ChildViewIndexArea> {        public int childIndex;        public View childView;        public int area;        public ChildViewIndexArea(int childIndex, View childView) {            this.childIndex = childIndex;            this.childView = childView;            area = childView.getMeasuredWidth() * childView.getMeasuredHeight();        }        //安卓控件的面积大小:从大到小排序        @Override        public int compareTo(ChildViewIndexArea another) {            return -(this.area - another.area);        }    }    private Random mRandom = new Random();    // 按照面积从小到大顺序随机摆放,并且每个子控件尝试 30次    @Override    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {        mLayoutedChildViews.clear();        mChildViewIndexAreas.clear();        int measuredWidth = getMeasuredWidth();        int measuredHeight = getMeasuredHeight();        int childCount = getChildCount();        for (int i = 0; i < childCount; i++) {            //将每一个子控件封装成类放入集合中            ChildViewIndexArea childViewIndexArea = new ChildViewIndexArea(i, getChildAt(i));            mChildViewIndexAreas.add(childViewIndexArea);        }        //排序        Collections.sort(mChildViewIndexAreas);        for (ChildViewIndexArea childViewIndexArea : mChildViewIndexAreas) {            View childView = childViewIndexArea.childView;            int childViewMeasuredWidth = childView.getMeasuredWidth();            int childViewMeasuredHeight = childView.getMeasuredHeight();            //随机摆放的高度和宽度            //多次去尝试摆放            int tryLayoutCount = MAX_TRY_LAYOUT_COUNT;            while (tryLayoutCount-- > 0) {                //摆放成功跳出循环                if (tryLayoutChildView(measuredWidth, measuredHeight, childView, childViewMeasuredWidth, childViewMeasuredHeight)) {                    break;                }            }            //摆放失败            if (tryLayoutCount <= 0) {                //重新摆放的时候,如果控件摆放失败,会回到原来的位置                Log.d("RandomLayout", ((TextView) childView).getText().toString() + " 摆放失败");                childView.layout(-1, -1, -1, -1);            }        }    }    //已经摆放好的子控件    private List mLayoutedChildViews = new ArrayList<>();    //这个方法应该多次调用,去尝试摆放的位置    private boolean tryLayoutChildView(int measuredWidth, int measuredHeight, View childView, int childViewMeasuredWidth, int childViewMeasuredHeight) {        int childLeft = mRandom.nextInt(measuredWidth - childViewMeasuredWidth);        int childTop = mRandom.nextInt(measuredHeight - childViewMeasuredHeight);        int childRight = childLeft + childViewMeasuredWidth;        int childBottom = childTop + childViewMeasuredHeight;        //直接摆放了,摆放之前应该判断该位置是否可以摆放        if (canLayout(childLeft, childTop, childRight, childBottom)) {            childView.layout(childLeft, childTop, childRight, childBottom);            mLayoutedChildViews.add(childView);            return true;        }        return false;    }    //每个控件摆放的时候去遍历所有已经摆放的子控件,判断(int childLeft, int childTop, int childRight, int childBottom)    //和每个已经摆放的子控件是否有交点new Rect().intersect()判断两个矩形是否有重合部分    //view---->getHitRect 返回view的left, top, right, botoom    private Rect mLayoutedViewRect = new Rect();    private boolean canLayout(int childLeft, int childTop, int childRight, int childBottom) {        for (View layoutedChildView : mLayoutedChildViews) {            //将摆放的子控件的位置封装到mLayoutedViewRect            layoutedChildView.getHitRect(mLayoutedViewRect);            if (mLayoutedViewRect.intersect(childLeft, childTop, childRight, childBottom)) {                return false;            }        }        return true;    }}

对应布局文件:

<?xml version="1.0" encoding="utf-8"?><mgzxc.cn.demo.FlyLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context=".MainActivity">    <mgzxc.cn.demo.RandomLayout        android:id="@+id/randomlayout1"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:gravity="center"        android:background="#dcdcdc"        android:clickable="true" />    <mgzxc.cn.demo.RandomLayout        android:id="@+id/randomlayout2"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:gravity="center"        android:background="#dcdcdc"        android:clickable="true" />mgzxc.cn.demo.FlyLayout>

MainActivity.java

public class MainActivity extends AppCompatActivity implements View.OnClickListener {    public static final String tags1[] = {            "QQ邮箱会员电脑管家软件",            "微信空间课堂好莱坞腾讯云",            "快报新闻APP自选股体育APP",            "视频手机管家浏览器应用宝",            "LOLCFDNF征途战争雷霆",            "爱玩逆战火影手游火影OL剑侠",            "京东理财通企鹅FMQ币全部"};    public static final String tags2[] = {            "博鳌亚洲论坛 ",            "哈佛商业评论 ",            "财经国家周刊 ",            "每日经济新闻 ",            "中国企业家 ",            "路透中文网 ",            "国际金融报 ",            "中国证券网 ",            "中国经营报 ",            "经济观察报 ",            "中国经济网 ",            "证券市场周刊 ",            "财新网 ",            "华夏时报 ",            "第一财经 ",            "FT中文网 ",            "财经网 ",            "创业家 ",            "福布斯 ",            "美通社 ",            "21世纪经济报道 ",            "华尔街见闻 ",            "中国黄金交易网 ",            "CCTV证券资讯网 ",            "中国发展研究基金会 ",            "证券日报 ",            "中国民族证券 ",            "新财富杂志 ",            "环球企业家 ",            "中国证券报 ",            "证券时报网 ",            "易三板 ",            "中国金融网 ",            "易三板 ",            "未央网 ",            "商学院"};    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        RandomLayout mRandomLayout1 = (RandomLayout) findViewById(R.id.randomlayout1);        RandomLayout mRandomLayout2 = (RandomLayout) findViewById(R.id.randomlayout2);        //随机布局添加标签        for (String tag : tags1) {            mRandomLayout1.addView(createTagView(tag));        }        for (String tag : tags2) {            mRandomLayout2.addView(createTagView(tag));        }    }    private View createTagView(String tag) {        TextView textView = new TextView(this);        textView.setOnClickListener(this);        textView.setText(tag);        textView.setGravity(Gravity.CENTER);        int padding = (int) Utils.dipToPx(this, 4);        textView.setPadding(padding, padding, padding, padding);        //需要指定宽度和高度        textView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));        //通过 GradientDrawable实现textview文本的效果设计        GradientDrawable gradientDrawable = new GradientDrawable();        gradientDrawable.setCornerRadius(Utils.dipToPx(this, 4));        gradientDrawable.setStroke((int) Utils.dipToPx(this, 1), Color.GRAY);        //背景设置随机颜色        int randomColor = geneareRandomColor();        gradientDrawable.setColor(randomColor);        textView.setBackgroundDrawable(gradientDrawable);        //根据背景颜色的深浅来设置字体颜色        textView.setTextColor(generateTextColor(randomColor));        return textView;    }    private int generateTextColor(int randomColor) {        //0~255        int avgColor = (Color.red(randomColor) + Color.blue(randomColor) + Color.blue(randomColor)) / 3;        //背景颜色浅        if (avgColor > 0xff / 2) {            return Color.BLACK;        } else {            return Color.WHITE;        }    }    private Random mRandom = new Random();    private int geneareRandomColor() {        //0~255        return Color.argb(0xff, mRandom.nextInt(0xfff), mRandom.nextInt(0xfff), mRandom.nextInt(0xfff));    }    @Override    public void onClick(View v) {        String tag = ((TextView) v).getText().toString();        Toast.makeText(this, tag, Toast.LENGTH_SHORT).show();    }}

更多相关文章

  1. Android 开关机动画
  2. 完美解决Android Studio在写XML布局的时候没有了控件代码提示的
  3. Android 子控件高度超出父布局的限制
  4. 获取Android屏幕尺寸、控件尺寸、状态栏/通知栏高度、导航栏高度
  5. VideoView控件可以手动改变大小
  6. Android中帧动画在Activity启动时自动运行的几种方式
  7. Android 自动化测试—robotium(五)Spinner控件
  8. Android TextView内容居中和控件居中
  9. Android点赞动画效果 ,点赞后加一,2种方法,①补间动画②位移动画

随机推荐

  1. REDIS从LINUX文件写入批量数据
  2. Android usb client mass-storage 多存储
  3. linux 命令 grep 不使用 正则表达式
  4. 第十章嵌入式Linux调试技术
  5. Linux 上传代码到github
  6. Linux下非root用户能创建新文件,却不能拷
  7. Linux用户和组的操作(一) 用户文件/etc/pas
  8. Linux命令应用大词典-第21章 LVM和RAID管
  9. Linux网络状态工具ss命令使用详解
  10. [置顶] Linux C编程--string.h函