使用StellarMap实现随机显示效果

一 , 首先 我们要导入这个包


使用StellarMap实现随机显示效果_第1张图片
image.png

布局
···

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="com.example.progress.SecondActivity">
android:id="@+id/stellar"
android:layout_width="match_parent"
android:layout_height="match_parent">

  

···
Activity 中代码
···

package com.example.progress;

import android.app.Activity;
import android.graphics.Color;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

import com.example.progress.ui.randomLayout.StellarMap;

import java.util.Random;

/***

  • 布局一定直接间接实现ViewGroup
    *如何在布局中添加子视图
    *1. 直接在布局文件中,以标签形式添加 静态
    1. 在代码中动态添加子视图
  •      ------>addView(...)一个一个的加
    
  •     ------>设置adapter方式,批量的装配数据
    

*/

public class SecondActivity extends Activity {

private StellarMap stellar;
//提供装配的数据
private String[] datas = new String[]{"新手福利计划", "财神道90天计划", "硅谷钱包计划", "30天理财计划(加息2%)", "180天理财计划(加息5%)", "月月升理财计划(加息10%)",
        "中情局投资商业经营", "大学老师购买车辆", "屌丝下海经商计划", "美人鱼影视拍摄投资", "Android培训老师自己周转", "养猪场扩大经营",
        "旅游公司扩大规模", "铁路局回款计划", "屌丝迎娶白富美计划"
};
//声明两个子数组
private String[] oneData=new String[datas.length/2];
private String[] towData=new String[datas.length - datas.length/2];
private Random random=new Random();
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_second);
   init();

}

private void init() {
    stellar = findViewById(R.id.stellar);
    //初始化子数组的数据
    for (int i = 0; i < datas.length; i++) {
        if (i

}

···
效果图:


使用StellarMap实现随机显示效果_第2张图片
image.png

使用StellarMap实现随机显示效果_第3张图片
image.png

---------------------------------------- 1 -----------------------------------------*
···
package com.example.progress.ui.randomLayout;

import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.LinearInterpolator;
import android.view.animation.ScaleAnimation;

public class AnimationUtil {

private static final long MEDIUM = 500;

/**
 * 创建一个淡入放大的动画
 */
public static Animation createZoomInNearAnim() {
    AnimationSet ret;
    Animation anim;
    ret = new AnimationSet(false);
    // 创建一个淡入的动画
    anim = new AlphaAnimation(0f, 1f);
    anim.setDuration(MEDIUM);
    anim.setInterpolator(new LinearInterpolator());
    ret.addAnimation(anim);
    // 创建一个放大的动画
    anim = new ScaleAnimation(0, 1, 0, 1, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
    anim.setDuration(MEDIUM);
    anim.setInterpolator(new DecelerateInterpolator());
    ret.addAnimation(anim);
    return ret;
}

/**
 * 创建一个淡出放大的动画
 */
public static Animation createZoomInAwayAnim() {
    AnimationSet ret;
    Animation anim;
    ret = new AnimationSet(false);
    // 创建一个淡出的动画
    anim = new AlphaAnimation(1f, 0f);
    anim.setDuration(MEDIUM);
    anim.setInterpolator(new DecelerateInterpolator());
    ret.addAnimation(anim);
    // 创建一个放大的动画
    anim = new ScaleAnimation(1, 3, 1, 3, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
    anim.setDuration(MEDIUM);
    anim.setInterpolator(new DecelerateInterpolator());
    ret.addAnimation(anim);
    return ret;
}

/**
 * 创建一个淡入缩小的动画
 */
public static Animation createZoomOutNearAnim() {
    AnimationSet ret;
    Animation anim;
    ret = new AnimationSet(false);
    // 创建一个淡入的动画
    anim = new AlphaAnimation(0f, 1f);
    anim.setDuration(MEDIUM);
    anim.setInterpolator(new LinearInterpolator());
    ret.addAnimation(anim);
    // 创建一个缩小的动画
    anim = new ScaleAnimation(3, 1, 3, 1, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
    anim.setDuration(MEDIUM);
    anim.setInterpolator(new DecelerateInterpolator());
    ret.addAnimation(anim);
    return ret;
}

/**
 * 创建一个淡出缩小的动画
 */
public static Animation createZoomOutAwayAnim() {
    AnimationSet ret;
    Animation anim;
    ret = new AnimationSet(false);
    // 创建一个淡出的动画
    anim = new AlphaAnimation(1f, 0f);
    anim.setDuration(MEDIUM);
    anim.setInterpolator(new DecelerateInterpolator());
    ret.addAnimation(anim);
    // 创建一个缩小的动画
    anim = new ScaleAnimation(1, 0, 1, 0, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
    anim.setDuration(MEDIUM);
    anim.setInterpolator(new DecelerateInterpolator());
    ret.addAnimation(anim);
    return ret;
}

/**
 * 创建一个淡入放大的动画
 */
public static Animation createPanInAnim(float degree) {
    AnimationSet ret;
    Animation anim;
    ret = new AnimationSet(false);
    // 创建一个淡入动画
    anim = new AlphaAnimation(0f, 1f);
    anim.setDuration(MEDIUM);
    anim.setInterpolator(new LinearInterpolator());
    ret.addAnimation(anim);
    // 创建一个放大动画
    final float pivotX = (float) (1 - Math.cos(degree)) / 2;
    final float pivotY = (float) (1 + Math.sin(degree)) / 2;

    anim = new ScaleAnimation(0.8f, 1, 0.8f, 1, Animation.RELATIVE_TO_SELF, pivotX, Animation.RELATIVE_TO_SELF,
            pivotY);
    anim.setDuration(MEDIUM);
    anim.setInterpolator(new DecelerateInterpolator());
    ret.addAnimation(anim);

    return ret;
}

/**
 * 创建一个淡出缩小的动画
 */
public static Animation createPanOutAnim(float degree) {
    AnimationSet ret;
    Animation anim;
    ret = new AnimationSet(false);
    // 创建一个淡出动画
    anim = new AlphaAnimation(1f, 0f);
    anim.setDuration(MEDIUM);
    anim.setInterpolator(new DecelerateInterpolator());
    ret.addAnimation(anim);
    // 创建一个缩小动画
    final float pivotX = (float) (1 + Math.cos(degree)) / 2;
    final float pivotY = (float) (1 - Math.sin(degree)) / 2;
    anim = new ScaleAnimation(1, 0.8f, 1, 0.8f, Animation.RELATIVE_TO_SELF, pivotX, Animation.RELATIVE_TO_SELF,
            pivotY);
    anim.setDuration(MEDIUM);
    anim.setInterpolator(new DecelerateInterpolator());
    ret.addAnimation(anim);

    return ret;
}

}

···
----------------------------------------2----------------------------------------
···
package com.example.progress.ui.randomLayout;

import android.content.Context;
import android.graphics.Rect;
import android.view.View;
import android.view.ViewGroup;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.Set;

public class RandomLayout extends ViewGroup {

private Random mRdm;
/**
 * X分布规则性,该值越高,子view在x方向的分布越规则、平均。最小值为1。
 */
private int mXRegularity;
/**
 * Y分布规则性,该值越高,子view在y方向的分布越规则、平均。最小值为1。
 */
private int mYRegularity;
/**
 * 区域个数
 */
private int mAreaCount;
/**
 * 区域的二维数组
 */
private int[][] mAreaDensity;
/**
 * 存放已经确定位置的View
 */
private Set mFixedViews;
/**
 * 提供子View的adapter
 */
private Adapter mAdapter;
/**
 * 记录被回收的View,以便重复利用
 */
private List mRecycledViews;
/**
 * 是否已经layout
 */
private boolean mLayouted;
/**
 * 计算重叠时候的间距
 */
private int mOverlapAdd = 2;

/**
 * 构造方法
 */
public RandomLayout(Context context) {
    super(context);
    init();
}

/**
 * 初始化方法
 */
private void init() {
    mLayouted = false;
    mRdm = new Random();
    setRegularity(1, 1);
    mFixedViews = new HashSet();
    mRecycledViews = new LinkedList();
}

public boolean hasLayouted() {
    return mLayouted;
}

/**
 * 设置mXRegularity和mXRegularity,确定区域的个数
 */
public void setRegularity(int xRegularity, int yRegularity) {
    if (xRegularity > 1) {
        this.mXRegularity = xRegularity;
    } else {
        this.mXRegularity = 1;
    }
    if (yRegularity > 1) {
        this.mYRegularity = yRegularity;
    } else {
        this.mYRegularity = 1;
    }
    this.mAreaCount = mXRegularity * mYRegularity;//个数等于x方向的个数*y方向的个数
    this.mAreaDensity = new int[mYRegularity][mXRegularity];//存放区域的二维数组
}

/**
 * 设置数据源
 */
public void setAdapter(Adapter adapter) {
    this.mAdapter = adapter;
}

/**
 * 重新设置区域,把所有的区域记录都归0
 */
private void resetAllAreas() {
    mFixedViews.clear();
    for (int i = 0; i < mYRegularity; i++) {
        for (int j = 0; j < mXRegularity; j++) {
            mAreaDensity[i][j] = 0;
        }
    }
}

/**
 * 把复用的View加入集合,新加入的放入集合第一个。
 */
private void pushRecycler(View scrapView) {
    if (null != scrapView) {
        mRecycledViews.add(0, scrapView);
    }
}

/**
 * 取出复用的View,从集合的第一个位置取出
 */
private View popRecycler() {
    final int size = mRecycledViews.size();
    if (size > 0) {
        return mRecycledViews.remove(0);
    } else {
        return null;
    }
}

/**
 * 产生子View,这个就是listView复用的简化版,但是原理一样
 */
private void generateChildren() {
    if (null == mAdapter) {
        return;
    }
    // 先把子View全部存入集合
    final int childCount = super.getChildCount();
    for (int i = childCount - 1; i >= 0; i--) {
        pushRecycler(super.getChildAt(i));
    }
    // 删除所有子View
    super.removeAllViewsInLayout();
    // 得到Adapter中的数据量
    final int count = mAdapter.getCount();
    for (int i = 0; i < count; i++) {
        //从集合中取出之前存入的子View
        View convertView = popRecycler();
        //把该子View作为adapter的getView的历史View传入,得到返回的View
        View newChild = mAdapter.getView(i, convertView);
        if (newChild != convertView) {//如果发生了复用,那么newChild应该等于convertView
            // 这说明没发生复用,所以重新把这个没用到的子View存入集合中
            pushRecycler(convertView);
        }
        //调用父类的方法把子View添加进来
        super.addView(newChild, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
    }
}

/**
 * 重新分配区域
 */
public void redistribute() {
    resetAllAreas();//重新设置区域
    requestLayout();
}

/**
 * 重新更新子View
 */
public void refresh() {
    resetAllAreas();//重新分配区域
    generateChildren();//重新产生子View
    requestLayout();
}

/**
 * 重写父类的removeAllViews
 */
@Override
public void removeAllViews() {
    super.removeAllViews();//先删除所有View
    resetAllAreas();//重新设置所有区域
}

/**
 * 确定子View的位置,这个就是区域分布的关键
 */
@Override
public void onLayout(boolean changed, int l, int t, int r, int b) {
    final int count = getChildCount();
    // 确定自身的宽高
    int thisW = r - l - this.getPaddingLeft() - this.getPaddingRight();
    int thisH = b - t - this.getPaddingTop() - this.getPaddingBottom();
    // 自身内容区域的右边和下边
    int contentRight = r - getPaddingRight();
    int contentBottom = b - getPaddingBottom();
    // 按照顺序存放把区域存放到集合中
    List availAreas = new ArrayList(mAreaCount);
    for (int i = 0; i < mAreaCount; i++) {
        availAreas.add(i);
    }

    int areaCapacity = (count + 1) / mAreaCount + 1;  //区域密度,表示一个区域内可以放几个View,+1表示至少要放一个
    int availAreaCount = mAreaCount; //可用的区域个数

    for (int i = 0; i < count; i++) {
        final View child = getChildAt(i);
        if (child.getVisibility() == View.GONE) { // gone掉的view是不参与布局
            continue;
        }

        if (!mFixedViews.contains(child)) {//mFixedViews用于存放已经确定好位置的View,存到了就没必要再次存放
            LayoutParams params = (LayoutParams) child.getLayoutParams();
            // 先测量子View的大小
            int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(this.getMeasuredWidth(), MeasureSpec.AT_MOST);//为子View准备测量的参数
            int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(this.getMeasuredHeight(), MeasureSpec.AT_MOST);
            child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
            // 子View测量之后的宽和高
            int childW = child.getMeasuredWidth();
            int childH = child.getMeasuredHeight();
            // 用自身的高度去除以分配值,可以算出每一个区域的宽和高
            float colW = thisW / (float) mXRegularity;
            float rowH = thisH / (float) mYRegularity;

            while (availAreaCount > 0) { //如果使用区域大于0,就可以为子View尝试分配
                int arrayIdx = mRdm.nextInt(availAreaCount);//随机一个list中的位置
                int areaIdx = availAreas.get(arrayIdx);//再根据list中的位置获取一个区域编号
                int col = areaIdx % mXRegularity;//计算出在二维数组中的位置
                int row = areaIdx / mXRegularity;
                if (mAreaDensity[row][col] < areaCapacity) {// 区域密度未超过限定,将view置入该区域
                    int xOffset = (int) colW - childW; //区域宽度 和 子View的宽度差值,差值可以用来做区域内的位置随机
                    if (xOffset <= 0) {
                        xOffset = 1;
                    }
                    int yOffset = (int) rowH - childH;
                    if (yOffset <= 0) {
                        yOffset = 1;
                    }
                    // 确定左边,等于区域宽度*左边的区域
                    params.mLeft = getPaddingLeft() + (int) (colW * col + mRdm.nextInt(xOffset));
                    int rightEdge = contentRight - childW;
                    if (params.mLeft > rightEdge) {//加上子View的宽度后不能超出右边界
                        params.mLeft = rightEdge;
                    }
                    params.mRight = params.mLeft + childW;

                    params.mTop = getPaddingTop() + (int) (rowH * row + mRdm.nextInt(yOffset));
                    int bottomEdge = contentBottom - childH;
                    if (params.mTop > bottomEdge) {//加上子View的宽度后不能超出右边界
                        params.mTop = bottomEdge;
                    }
                    params.mBottom = params.mTop + childH;

                    if (!isOverlap(params)) {//判断是否和别的View重叠了
                        mAreaDensity[row][col]++;//没有重叠,把该区域的密度加1
                        child.layout(params.mLeft, params.mTop, params.mRight, params.mBottom);//布局子View
                        mFixedViews.add(child);//添加到已经布局的集合中
                        break;
                    } else {//如果重叠了,把该区域移除,
                        availAreas.remove(arrayIdx);
                        availAreaCount--;
                    }
                } else {// 区域密度超过限定,将该区域从可选区域中移除
                    availAreas.remove(arrayIdx);
                    availAreaCount--;
                }
            }
        }
    }
    mLayouted = true;
}

/**
 * 计算两个View是否重叠,如果重叠,那么他们之间一定有一个矩形区域是共有的
 */
private boolean isOverlap(LayoutParams params) {
    int l = params.mLeft - mOverlapAdd;
    int t = params.mTop - mOverlapAdd;
    int r = params.mRight + mOverlapAdd;
    int b = params.mBottom + mOverlapAdd;

    Rect rect = new Rect();

    for (View v : mFixedViews) {
        int vl = v.getLeft() - mOverlapAdd;
        int vt = v.getTop() - mOverlapAdd;
        int vr = v.getRight() + mOverlapAdd;
        int vb = v.getBottom() + mOverlapAdd;
        rect.left = Math.max(l, vl);
        rect.top = Math.max(t, vt);
        rect.right = Math.min(r, vr);
        rect.bottom = Math.min(b, vb);
        if (rect.right >= rect.left && rect.bottom >= rect.top) {
            return true;
        }
    }
    return false;
}

/**
 * 内部类、接口
 */
public static interface Adapter {

    public abstract int getCount();

    public abstract View getView(int position, View convertView);
}

public static class LayoutParams extends ViewGroup.LayoutParams {

    private int mLeft;
    private int mRight;
    private int mTop;
    private int mBottom;

    public LayoutParams(ViewGroup.LayoutParams source) {
        super(source);
    }

    public LayoutParams(int w, int h) {
        super(w, h);
    }
}

}

···
---------------------------3---------------------------------------------------------
···
package com.example.progress.ui.randomLayout;

import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;

public class ShakeListener implements SensorEventListener {
private static final int FORCE_THRESHOLD = 250;
private static final int TIME_THRESHOLD = 100;
private static final int SHAKE_TIMEOUT = 500;
private static final int SHAKE_DURATION = 1000;
private static final int SHAKE_COUNT = 2;

private SensorManager mSensorMgr;
private float mLastX = -1.0f, mLastY = -1.0f, mLastZ = -1.0f;
private long mLastTime;
private OnShakeListener mShakeListener;
private Context mContext;
private int mShakeCount = 0;
private long mLastShake;
private long mLastForce;

public ShakeListener(Context context) {
    mContext = context;
    resume();
}

public void setOnShakeListener(OnShakeListener listener) {
    mShakeListener = listener;
}

/**
 * 界面可见时候才监听摇晃
 */
public void resume() {
    mSensorMgr = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
    if (mSensorMgr == null) {
        throw new UnsupportedOperationException("Sensors not supported");
    }

    boolean supported = mSensorMgr.registerListener(this, mSensorMgr.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_UI);
    if (!supported) {
        mSensorMgr.unregisterListener(this);
        return;
    }
}

/**
 * 界面不可见时,需要关闭监听
 */
public void pause() {
    if (mSensorMgr != null) {
        mSensorMgr.unregisterListener(this);
        mSensorMgr = null;
    }
}

@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
    System.out.println("accuracy:" + accuracy);
}

@Override
public void onSensorChanged(SensorEvent event) {

    System.out.println("x:" + event.values[SensorManager.DATA_X] + "  y:" + event.values[SensorManager.DATA_Y] + "  z:" + event.values[SensorManager.DATA_Z]);

    if (event.sensor.getType() != Sensor.TYPE_ACCELEROMETER) {
        return;
    }

    long now = System.currentTimeMillis();

    if ((now - mLastForce) > SHAKE_TIMEOUT) {
        mShakeCount = 0;
    }

    if ((now - mLastTime) > TIME_THRESHOLD) {
        long diff = now - mLastTime;
        // 把X,Y,Z方向的距离除以时间,得出速度
        float speed = Math.abs(event.values[SensorManager.DATA_X] + event.values[SensorManager.DATA_Y] + event.values[SensorManager.DATA_Z] - mLastX - mLastY - mLastZ) / diff * 10000;
        if (speed > FORCE_THRESHOLD) {//如果速度大于某个值
            // 先把摇晃的次数+1,再判断是否超过了要换的次数,并且间隙大于特定的值
            if ((++mShakeCount >= SHAKE_COUNT) && (now - mLastShake > SHAKE_DURATION)) {
                mLastShake = now;
                mShakeCount = 0;
                if (mShakeListener != null) {//回调我们的listener
                    mShakeListener.onShake();
                }
            }
            mLastForce = now;
        }
        mLastTime = now;
        mLastX = event.values[SensorManager.DATA_X];
        mLastY = event.values[SensorManager.DATA_Y];
        mLastZ = event.values[SensorManager.DATA_Z];
    }
}

public interface OnShakeListener {
    public void onShake();
}

}

···
----------------------4-----------------------------------
···
package com.example.progress.ui.randomLayout;

import android.content.Context;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.widget.FrameLayout;

public class StellarMap extends FrameLayout implements AnimationListener, OnTouchListener, OnGestureListener {

private RandomLayout mHidenGroup;

private RandomLayout mShownGroup;

private Adapter mAdapter;
private RandomLayout.Adapter mShownGroupAdapter;
private RandomLayout.Adapter mHidenGroupAdapter;

private int mShownGroupIndex;// 显示的组
private int mHidenGroupIndex;// 隐藏的组
private int mGroupCount;// 组数

/**
 * 动画
 */
private Animation mZoomInNearAnim;
private Animation mZoomInAwayAnim;
private Animation mZoomOutNearAnim;
private Animation mZoomOutAwayAnim;

private Animation mPanInAnim;
private Animation mPanOutAnim;
/**
 * 手势识别器
 */
private GestureDetector mGestureDetector;

/**
 * 构造方法
 */
public StellarMap(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    init();
}

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

public StellarMap(Context context) {
    super(context);
    init();
}

/**
 * 初始化方法
 */
private void init() {
    mGroupCount = 0;
    mHidenGroupIndex = -1;
    mShownGroupIndex = -1;
    mHidenGroup = new RandomLayout(getContext());
    mShownGroup = new RandomLayout(getContext());

    addView(mHidenGroup, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
    mHidenGroup.setVisibility(View.GONE);
    addView(mShownGroup, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));

    mGestureDetector = new GestureDetector(this);
    setOnTouchListener(this);
    //设置动画
    mZoomInNearAnim = AnimationUtil.createZoomInNearAnim();
    mZoomInNearAnim.setAnimationListener(this);
    mZoomInAwayAnim = AnimationUtil.createZoomInAwayAnim();
    mZoomInAwayAnim.setAnimationListener(this);
    mZoomOutNearAnim = AnimationUtil.createZoomOutNearAnim();
    mZoomOutNearAnim.setAnimationListener(this);
    mZoomOutAwayAnim = AnimationUtil.createZoomOutAwayAnim();
    mZoomOutAwayAnim.setAnimationListener(this);
}

/**
 * 设置隐藏组和显示组的x和y的规则
 */
public void setRegularity(int xRegularity, int yRegularity) {
    mHidenGroup.setRegularity(xRegularity, yRegularity);
    mShownGroup.setRegularity(xRegularity, yRegularity);
}

private void setChildAdapter() {
    if (null == mAdapter) {
        return;
    }
    mHidenGroupAdapter = new RandomLayout.Adapter() {
        //取出本Adapter的View对象给HidenGroup的Adapter
        @Override
        public View getView(int position, View convertView) {
            return mAdapter.getView(mHidenGroupIndex, position, convertView);
        }

        @Override
        public int getCount() {
            return mAdapter.getCount(mHidenGroupIndex);
        }
    };
    mHidenGroup.setAdapter(mHidenGroupAdapter);

    mShownGroupAdapter = new RandomLayout.Adapter() {
        //取出本Adapter的View对象给ShownGroup的Adapter
        @Override
        public View getView(int position, View convertView) {
            return mAdapter.getView(mShownGroupIndex, position, convertView);
        }

        @Override
        public int getCount() {
            return mAdapter.getCount(mShownGroupIndex);
        }
    };
    mShownGroup.setAdapter(mShownGroupAdapter);
}

/**
 * 设置本Adapter
 */
public void setAdapter(Adapter adapter) {
    mAdapter = adapter;
    mGroupCount = mAdapter.getGroupCount();
    if (mGroupCount > 0) {
        mShownGroupIndex = 0;
    }
    setChildAdapter();
}

/**
 * 设置显示区域
 */
public void setInnerPadding(int paddingLeft, int paddingTop, int paddingRight, int paddingBottom) {
    mHidenGroup.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
    mShownGroup.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
}

/**
 * 给指定的Group设置动画
 */
public void setGroup(int groupIndex, boolean playAnimation) {
    switchGroup(groupIndex, playAnimation, mZoomInNearAnim, mZoomInAwayAnim);
}

/**
 * 获取当前显示的group角标
 */
public int getCurrentGroup() {
    return mShownGroupIndex;
}

/**
 * 给Group设置动画入
 */
public void zoomIn() {
    final int nextGroupIndex = mAdapter.getNextGroupOnZoom(mShownGroupIndex, true);
    switchGroup(nextGroupIndex, true, mZoomInNearAnim, mZoomInAwayAnim);
}

/**
 * 给Group设置出动画
 */
public void zoomOut() {
    final int nextGroupIndex = mAdapter.getNextGroupOnZoom(mShownGroupIndex, false);
    switchGroup(nextGroupIndex, true, mZoomOutNearAnim, mZoomOutAwayAnim);
}

/**
 * 给Group设置动画
 */
public void pan(float degree) {
    final int nextGroupIndex = mAdapter.getNextGroupOnPan(mShownGroupIndex, degree);
    mPanInAnim = AnimationUtil.createPanInAnim(degree);
    mPanInAnim.setAnimationListener(this);
    mPanOutAnim = AnimationUtil.createPanOutAnim(degree);
    mPanOutAnim.setAnimationListener(this);
    switchGroup(nextGroupIndex, true, mPanInAnim, mPanOutAnim);
}

/**
 * 给下一个Group设置进出动画
 */
private void switchGroup(int newGroupIndex, boolean playAnimation, Animation inAnim, Animation outAnim) {
    if (newGroupIndex < 0 || newGroupIndex >= mGroupCount) {
        return;
    }
    //把当前显示Group角标设置为隐藏的
    mHidenGroupIndex = mShownGroupIndex;
    //把下一个Group角标设置为显示的
    mShownGroupIndex = newGroupIndex;
    // 交换两个Group
    RandomLayout temp = mShownGroup;
    mShownGroup = mHidenGroup;
    mShownGroup.setAdapter(mShownGroupAdapter);
    mHidenGroup = temp;
    mHidenGroup.setAdapter(mHidenGroupAdapter);
    //刷新显示的Group
    mShownGroup.refresh();
    //显示Group
    mShownGroup.setVisibility(View.VISIBLE);

    //启动动画
    if (playAnimation) {
        if (mShownGroup.hasLayouted()) {
            mShownGroup.startAnimation(inAnim);
        }
        mHidenGroup.startAnimation(outAnim);
    } else {
        mHidenGroup.setVisibility(View.GONE);
    }
}

// 重新分配显示区域
public void redistribute() {
    mShownGroup.redistribute();
}

/**
 * 动画监听
 */
@Override
public void onAnimationStart(Animation animation) {
    // 当动画启动
}

@Override
public void onAnimationEnd(Animation animation) {
    // 当动画结束
    if (animation == mZoomInAwayAnim || animation == mZoomOutAwayAnim || animation == mPanOutAnim) {
        mHidenGroup.setVisibility(View.GONE);
    }
}

@Override
public void onAnimationRepeat(Animation animation) {
    // 当动画重复
}

/**
 * 定位
 */
@Override
public void onLayout(boolean changed, int l, int t, int r, int b) {
    //用以判断ShownGroup是否onLayout的变量
    boolean hasLayoutedBefore = mShownGroup.hasLayouted();
    super.onLayout(changed, l, t, r, b);
    if (!hasLayoutedBefore && mShownGroup.hasLayouted()) {
        mShownGroup.startAnimation(mZoomInNearAnim);//第一次layout的时候启动动画
    } else {
        mShownGroup.setVisibility(View.VISIBLE);
    }
}

/**
 * 重写onTouch事件,把onTouch事件分配给手势识别
 */
@Override
public boolean onTouch(View v, MotionEvent event) {
    return mGestureDetector.onTouchEvent(event);
}

/**
 * 消费掉onDown事件
 */
@Override
public boolean onDown(MotionEvent e) {
    return true;
}

/**
 * 空实现
 */
@Override
public void onShowPress(MotionEvent e) {
}

@Override
public boolean onSingleTapUp(MotionEvent e) {
    return false;
}

@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
    return false;
}

@Override
public void onLongPress(MotionEvent e) {

}

@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
    int centerX = getMeasuredWidth() / 2;
    int centerY = getMeasuredWidth() / 2;

    int x1 = (int) e1.getX() - centerX;
    int y1 = (int) e1.getY() - centerY;
    int x2 = (int) e2.getX() - centerX;
    int y2 = (int) e2.getY() - centerY;

    if ((x1 * x1 + y1 * y1) > (x2 * x2 + y2 * y2)) {
        zoomOut();
    } else {
        zoomIn();
    }
    return true;
}

/**
 * 内部类、接口
 */
public static interface Adapter {
    public abstract int getGroupCount();

    public abstract int getCount(int group);

    public abstract View getView(int group, int position, View convertView);

    public abstract int getNextGroupOnPan(int group, float degree);

    public abstract int getNextGroupOnZoom(int group, boolean isZoomIn);
}

}

···

你可能感兴趣的:(使用StellarMap实现随机显示效果)