您的位置:首页 > 移动开发 > Android开发

Android中自定义控件之飞入飞出布局及随机布局实现方式

2018-03-26 09:29 696 查看
本文主要介绍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<ChildViewIndexArea> 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<View> 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();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐