必威体育Betway必威体育官网
当前位置:首页 > IT技术

【Android - 个人项目】— 地震管家(全球地震信息)

时间:2019-08-16 04:42:06来源:IT技术作者:seo实验室小编阅读:66次「手机版」
 

实时地震查询

EarthQuakeAPP.zip

地震信息查询App,这是我在大二寒假时间开发的,使用了volly+jsoup+MPAndroidChart+bottom-navigation-bar等第三方开源库,数据来源是:中国地震台网,jsoup解析xml,该App内还有天气查询的功能,数据来源是:和风天气,还有百度地图功能,定位功能等。是一款综合性比较强的Android案例,需要的下载去学习,情况本人博客中的演示效果:https://blog.csdn.net/smile_Running/article/details/94502113(大伙觉得不错的给个赞和评论哦,您的点赞和评论就是写作的动力!)

立即下载

博主声明:

转载请在开头附加本文链接及作者信息,并标记为转载。本文由博主 威威喵 原创,请多支持与指教。

本文首发于此   博主:威威喵  |  博客主页:https://blog.csdn.net/smile_running

这是一款地震信息查询App,说是地震信息查询,但我又结合了天气查询百度地图定位等功能。这是在2018年那个大二寒假期间开发的,主要是当初回到家里没事情干,就随手写了一个Demo,由于比赛集训的原因,我的寒假被压缩只剩半个月,后来到学校就去比赛了,忙着比赛的事情,就无暇顾及这个 App 的工作进度,导致很多功能都没有实现。希望以后我有时间再去完善吧!

下面我把已经实现的功能及运用到 Android 技术点介绍一下。

项目使用到的技术(开源框架):

  • bottom-navigation-bar
  • okhttp
  • volley
  • tosaty
  • glide
  • MPAndroidChart
  • nineoldandroids
  • gson
  • jsoup
  • baiduMap SDk

本项目数据来源与感谢:

中国地震台网

和风天气

之前对 Android 的学习与了解比较浅,也是在 Android 刚入门时候编写的此项目,所以本项目有很多不足的地方,代码冗余、程序没有优化,但给予初学者的帮助还是足够多了,需要的可以下载本项目,或者可以作为 Android 课程的作业,也足够了,哈哈!

项目下载地址:地震信息查询App

介绍完了本项目的开发背景,下面我们来看看这个 App 到底有什么功能,我们来看截图吧!

首先,一打开项目,就是我们的主页面了,主页面包含四个 Fragment 和一个侧拉导航 drawerlayout ,DrawerLayout 是常见的功能,类似于 QQ 的侧拉个人信息一样。

主页下面底部按钮使用的就是 bottom-navigation-bar 来创建的四个底部按钮,头部是一个 spinner 控件,中间是用于显示地震信息的 recyclerview 控件。数据是使用 jsoup 爬取 中国地震台网 的数据,解析 xml 标签得到一条一套的数据再显示,在recyclerview 往下滑动的时候,会开启一个滑动的缩放动画,并且滑倒一定数据量是,有一个 top 的返回到顶部的功能。

动态效果图:

在适配器中加入动画效果代码:

            ObjectAnimator scaleX = ObjectAnimator.ofFloat(holder.itemView, "scaleX", 0.5f, 1f);
            scaleX.start();
            mLastPosition = holder.getLayoutPosition();

第二个 Fragment 是百度地图的显示功能,可以根据当前定位信息来显示对应的地图,因为模拟器的原因,自己可以放手机上尝试。这里要注意一点,如果你把项目重新编译运行后,要记得修改自己的百度地图密钥,否则无法显示地图!

动态效果图:

这里有一个问题要解决,就是 viewpager 与 百度地图的   控件会发生事件冲突,所以在 MapView 这个页面时,我将ViewPager 的滑动事件交与 MapView 处理,我重写了 ViewPager 的 canscroll 事件,判断当前的 View 是否是 MapView,如果是,ViewPager 禁止滑动事件,由 MapView 去消费。

    @Override
    protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
        if (v.getClass().getName().equals("com.baidu.mapapi.map.MapView")) {
            return true;
        } else {
            return super.canScroll(v, checkV, dx, x, y);
        }
    }

然后,我们接着来看侧拉导航里面的菜单,实现了定位与显示功能,相机功能,天气信息显示功能与天气模块。

动态效果图:

我们来看看【我的位置】这个菜单功能,进入这个页面,就是单纯的使用 TextView 显示当前的定位信息与地址,默认位置是北京

动态效果图:

可以看到这里的 ScrollView 的滑动,当滑倒顶部与底部的时候,内容都会随着手指滑动出屏幕以外的区域,然后松开的时候会自动的回弹到原先的位置,这也是一个自定义的 ScrollView ,重写了 onTouchEvent 事件,我是通过获取 ScrollView 中子 View 的实例,通过计算手指滑动时 View 的滑动距离来重新布局,调用 view.layout() 方法,改变 View 的位置来达到目的。

public class BaseScrollView extends ScrollView {
    private View inner;// 孩子View

    private float y;// 点击时y坐标

    private Rect normal = new Rect();// 矩形(这里只是个形式,只是用于判断是否需要动画.)

    private boolean isCount = false;// 是否开始计算

    public BaseScrollView(context context, AttributeSet attrs) {
        super(context, attrs);
    }

    /***
     * 根据 XML 生成视图工作完成.该函数在生成视图的最后调用,在所有子视图添加完之后. 即使子类覆盖了 onfinishinflate
     * 方法,也应该调用父类的方法,使该方法得以执行.
     */
    @Override
    protected void onFinishInflate() {
        if (getChildCount() > 0) {
            inner = getChildAt(0);
        }
    }

    /***
     * 监听touch
     */
    @Override
    public boolean onTouchEvent(motionevent ev) {
        if (inner != null) {
            commOnTouchEvent(ev);
        }

        return super.onTouchEvent(ev);
    }

    /***
     * 触摸事件
     *
     * @param ev
     */
    public void commOnTouchEvent(MotionEvent ev) {
        int action = ev.getAction();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                break;
            case MotionEvent.ACTION_UP:
                // 手指松开.
                if (isNeedAnimation()) {
                    animation();
                    isCount = false;
                }
                break;
            /***
             * 排除出第一次移动计算,因为第一次无法得知y坐标, 在MotionEvent.ACTION_DOWN中获取不到,
             * 因为此时是MyScrollView的touch事件传递到到了listview的孩子item上面.所以从第二次计算开始.
             * 然而我们也要进行初始化,就是第一次移动的时候让滑动距离归0. 之后记录准确了就正常执行.
             */
            case MotionEvent.ACTION_MOVE:
                final float preY = y;// 按下时的y坐标
                float nowY = ev.getY();// 时时y坐标
                int deltaY = (int) (preY - nowY);// 滑动距离
                if (!isCount) {
                    deltaY = 0; // 在这里要归0.
                }

                y = nowY;
                // 当滚动到最上或者最下时就不会再滚动,这时移动布局
                if (isNeedMove()) {
                    // 初始化头部矩形
                    if (normal.isempty()) {
                        // 保存正常的布局位置
                        normal.set(inner.getLeft(), inner.getTop(),
                                inner.getRight(), inner.getBottom());
                    }
                    // 移动布局
                    inner.layout(inner.getLeft(), inner.getTop() - deltaY / 2,
                            inner.getRight(), inner.getBottom() - deltaY / 2);
                }
                isCount = true;
                break;

            default:
                break;
        }
    }

    /***
     * 回缩动画
     */
    public void animation() {
        // 开启移动动画
        translateanimation ta = new TranslateAnimation(0, 0, inner.getTop(),
                normal.top);
        ta.setDuration(200);
        inner.startAnimation(ta);
        // 设置回到正常的布局位置
        inner.layout(normal.left, normal.top, normal.right, normal.bottom);
        normal.setEmpty();
    }

    // 是否需要开启动画
    public boolean isNeedAnimation() {
        return !normal.isEmpty();
    }

    /***
     * 是否需要移动布局 inner.getmeasuredHeight():获取的是控件的总高度
     * <p>
     * getHeight():获取的是屏幕的高度
     *
     * @return
     */
    public boolean isNeedMove() {
        int offset = inner.getMeasuredHeight() - getHeight();
        int scrollY = getScrollY();
        // 0是顶部,后面那个是底部
        if (scrollY == 0 || scrollY == offset) {
            return true;
        }
        return false;
    }
}

接下来是【气象中心】菜单按钮,这里接入的是 和风天气 api,但是由于之前写的比较早,和风天气 api 现在已经做了升级了,有写 Json 数据返回被删除或修改了,已经获取不到数据值了,会报空指针异常,这里我也不做多的修改了。

实现的功能有这些,中间区域的 小时预报 是用了 MPAndroidChart 开源库来绘制了一条温度的曲线图,由于 api 的原因,导致现在数据显示不出来了。还有用到了 ViewPager + 切换的缩放动画效果,背景是必应每日一图,这个天气是参考郭霖大佬的《第一行代码》书籍里面的酷欧天气写的,但界面被我完全的修改了,改成自己设计的一套界面。

动态效果图

这里用了两个 ViewPager 切换动画的封装,一种是缩放动画,另一种是旋转动画。

public class ViewPagerTrans_Zoom implements PageTransformer {
	public static final float MIN_SCALE = 0.85f;
	public static final float MIN_ALPHA = 0.5f;
	@Override
	public void transformPage(View view, float position) {
		int pageWidth = view.getWidth();
		int pageHeight = view.getHeight();
		if (position < -1) {
			view.setAlpha(0);
		} else if (position <= 1) {
			float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position));
			float vertMargin = pageHeight * (1 - scaleFactor) / 2;
			float horzMargin = pageWidth * (1 - scaleFactor) / 2;
			if (position < 0) {
				view.setTranslationX(horzMargin - vertMargin / 2);
			} else {
				view.setTranslationY(vertMargin - horzMargin / 2);
			}
			view.setScaleX(scaleFactor);
			view.setScaleY(scaleFactor);
			view.setAlpha(MIN_ALPHA + (scaleFactor - MIN_SCALE)
					/ (1 - MIN_SCALE) * (1 - MIN_ALPHA));
		} else {
			view.setAlpha(0);
		}
	}
}
public class ViewPagerTrans_Rotate implements PageTransformer {
	private static final float ROT_MAX = 20.0f;
	private float mRot;
	@Override
	public void transformPage(View view, float position) {
		if (position < -1) {
			ViewHelper.setRotation(view, 0);
		} else if (position <= 1) {
			if (position < 0) {
				mRot = (ROT_MAX * position);
				ViewHelper.setPivotX(view, view.getMeasuredWidth() * 0.5f);
				ViewHelper.setPivotY(view, view.getMeasuredHeight());
				ViewHelper.setRotation(view, mRot);
			} else {
				mRot = (ROT_MAX * position);
				ViewHelper.setPivotX(view, view.getMeasuredWidth() * 0.5f);
				ViewHelper.setPivotY(view, view.getMeasuredHeight());
				ViewHelper.setRotation(view, mRot);
			}
		} else {
			ViewHelper.setRotation(view, 0);
		}
	}
}

看上面 ViewPager 切换时底部会有一个小圆点也跟着切换,这个是 ViewPagerIndicator(指示器),其实可以把它看作一个横向的 LinearLayout ,然后动态的往里面添加 ImageView 并设置不同的图片,根据 ViewPager 提供的 onPageChangeListener 接口来监听当前 ViewPager 所显示的页面来动态的设置 ImageView 的图片。

public class MyViewpagerIndicator implements ViewPager.OnPageChangeListener {
    private Context mContext;
    private int mPageCount;
    private LinearLayout mLinearLayout;
    private int imgSelect, imgUnselect;
    private int imgSize;
    private List<ImageView> imgList;

    /**
     * @context 上下文
     * @linearLayout 父容器
     * @pageCount 页面数
     * @imgSize 图片大小
     * @imgSelect 选中时的图片
     * @imgUnselect 未选中时的图片
     */
    public MyViewpagerIndicator(Context context, LinearLayout linearLayout,
                                int pageCount, int imgSize, int imgSelect, int imgUnselect) {
        imgList = new ArrayList<>();
        this.mContext = context;
        this.mLinearLayout = linearLayout;
        this.mPageCount = pageCount;
        this.imgSize = imgSize;
        this.imgSelect = imgSelect;
        this.imgUnselect = imgUnselect;

        for (int i = 0; i < mPageCount; i++) {
            ImageView imageView = new ImageView(mContext);
            LinearLayout.layoutparams params = new LinearLayout.LayoutParams(new ViewGroup.LayoutParams(
                    ViewGroup.LayoutParams.wrap_content, ViewGroup.LayoutParams.WRAP_CONTENT));
            //为小圆点左右添加间距
            params.leftMargin = 10;
            params.rightMargin = 10;
            //手动给小圆点一个大小
            params.height = imgSize;
            params.width = imgSize;
            if (i == 0) {
                imageView.setBackgroundResource(imgSelect);
            } else {
                imageView.setBackgroundResource(imgUnselect);
            }
            //为LinearLayout添加ImageView
            mLinearLayout.addView(imageView, params);
            imgList.add(imageView);
        }
    }

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

    }

    @Override
    public void onPageSelected(int position) {
        for (int i = 0; i < mPageCount; i++) {
            //选中的页面改变小圆点为选中状态,反之为未选中
            if ((position % mPageCount) == i) {
                ((View) imgList.get(i)).setBackgroundResource(imgSelect);
            } else {
                ((View) imgList.get(i)).setBackgroundResource(imgUnselect);
            }
        }
    }

    @Override
    public void onPageScrollStateChanged(int state) {
    }
}

到此为止,本项目的实现的功能及展示结束了,还有一些边边角角的地方没有提及,大家可以下载源码自行增改与完善。

项目下载地址:地震信息查询App

    分享既是快乐,感谢您的阅读。尊重他人劳动成果,转载请附加博客原文链接。点赞是一种积极的生活态度!

相关阅读

ACM:下面是512汶川大地震部分受灾学校伤亡情况(惨痛!!)

/*Problem Description下面是512汶川大地震部分受灾学校伤亡情况(惨痛!!)<br><br>1、 四川省都江堰市 聚源中学<br>伤亡情况:遇难学生

kaggle地震剩余时间预测挑战(一)

**kaggle地震剩余时间预测挑战(一) 写在前面的话 这是我第一次参加kaggle的挑战,希望能够记录下来,并且给你们分享,在这里我会记录我的

汶川地震死了多少人,真实报道的人数是多少!

今天是汶川大地震八周年,各地开展活动悼念地震中遇难的同胞,回顾那些定格的瞬间,祭奠历史,悼念遇难者。

十级地震有多大的破坏力,哪里发生过十级地震!

地震是地壳快速释放能量过程中造成振动,产生地震波的一种自然现象。主要原因是由于地球上板块与板块之间相互挤压碰撞,造成板块边沿

地震预测方法(世界历史上最伟大的地震预测)

1975年2月4日19时36分,在辽宁省海城、营口一带发生7.3级强烈地震。震源深度为16公里,震中烈度为9度强。

分享到:

栏目导航

推荐阅读

热门阅读