智慧北京(1)——闪屏与引导界面

Android 项目:智慧北京(1)——闪屏与引导界面

上一篇文章介绍了整个“智慧北京”项目学习总结,接下来就是具体的开发步骤了,其实接下来写的几篇文章都是为了督促我再次独立的敲写一边代码,仅此而已。

项目源代码:http://download.csdn.net/detail/xwdoor/9430613

1 闪屏界面

这里利用旋转动画、渐变动画、缩放动画实现闪屏界面的开发。至于闪屏界面的作用,我估计是因为加载 MainActivity 时比较耗时,为了更好的用户体验,在初始化数据并显示之前,显示闪屏界面,数据初始化完成后,再进入操作界面。

以下是实现步骤:

建立项目:SmartBeijing16

以后都在此项目基础上添加代码

创建 Activity:SplashActivity

并设置为 Launcher Activity,同时创建相应的布局界面:activity_splash.xml

  • 在布局界面 activity_splash 中,添加 ImageView,并设置背景和图片,如下所示。

    <ImageView
            android:id="@+id/iv_splash"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@drawable/splash_bg_newyear"
            android:src="@drawable/splash_horse_newyear"/>
  • 在 SplashActivity 的方法 onCreate() 中,取消标题栏:

supportRequestWindowFeature(Window.FEATURE_NO_TITLE);

  • 创建并启动动画

    //旋转动画
    //以自身为中心旋转360度
    RotateAnimation rotateAnimation = new RotateAnimation(0, 360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
    //设置动画时间为2秒
    rotateAnimation.setDuration(1000);
    //显示动画完成后的视图
    rotateAnimation.setFillAfter(true);

    //缩放动画
    //以自身为中心从0倍放大到1倍
    ScaleAnimation scaleAnimation = new ScaleAnimation(0, 1, 0, 1, Animation.RELATIVE_TO_SELF, 1f, Animation.RELATIVE_TO_SELF, 1f);
    scaleAnimation.setDuration(1000);
    scaleAnimation.setFillAfter(true);

    //渐变动画
    AlphaAnimation alphaAnimation = new AlphaAnimation(0, 1);
    alphaAnimation.setDuration(2000);
    alphaAnimation.setFillAfter(true);

    //声明动画集
    AnimationSet set = new AnimationSet(false);
    //添加动画
    set.addAnimation(rotateAnimation);
    set.addAnimation(scaleAnimation);
    set.addAnimation(alphaAnimation);
    //获取界面中的控件
    ImageView ivSplash = (ImageView) findViewById(R.id.iv_splash);
    //开始动画
    ivSplash.startAnimation(set);

创建两个包:utils 和 global

在 utils 工具包中创建类:PrefUtils,对 SharePreferences 进行简单的封装,用于存放配置数据;创建类: DensityUtils,用于 dp 与 px 单位的转换。
这几个类在接下来的步骤中需要用到,所以先写出来了。


    //对 SharePreferences 进行简单的封装,用于存放配置数据
    public class PrefUtils {
        public static void setBoolean(Context ctx,String key,boolean value){
            SharedPreferences preferences = ctx.getSharedPreferences("config", Context.MODE_PRIVATE);
            preferences.edit().putBoolean(key,value).apply();
        }

        public static boolean getBoolean(Context ctx,String key,boolean defValue){
            SharedPreferences preferences = ctx.getSharedPreferences("config", Context.MODE_PRIVATE);
            return preferences.getBoolean(key,defValue);
        }

        public static void setInt(Context ctx,String key,int value){
            SharedPreferences preferences = ctx.getSharedPreferences("config", Context.MODE_PRIVATE);
            preferences.edit().putInt(key, value).apply();
        }

        public static int getInt(Context ctx,String key,int defValue){
            SharedPreferences preferences = ctx.getSharedPreferences("config", Context.MODE_PRIVATE);
            return preferences.getInt(key, defValue);
        }

        public static void setString(Context ctx,String key,String value){
            SharedPreferences preferences = ctx.getSharedPreferences("config", Context.MODE_PRIVATE);
            preferences.edit().putString(key, value).apply();
        }

        public static String getString(Context ctx,String key,String defValue){
            SharedPreferences preferences = ctx.getSharedPreferences("config", Context.MODE_PRIVATE);
            return preferences.getString(key, defValue);
        }
    }

    /**
     * 单位转换
     * Created by XWdoor on 2016/2/13.
     */
    public class DensityUtils {

        public static float px2Dip(Context ctx, int px) {
            float density = ctx.getResources().getDisplayMetrics().density;
            return px / density;
        }

        public static int dip2Px(Context ctx, float dip) {
            float density = ctx.getResources().getDisplayMetrics().density;
            int px = (int) (dip * density + 0.5);
            return px;
        }
    }

在 global 包中创建 Config 类,用于存放常量数据。


    /**
     * 常量数据
     * Created by XWdoor on 2016/2/13.
     */
    public class Config {
        public static final String IS_FIRST_ENTER = "is_first";
    }

2 引导界面

闪屏界面稍微复杂一点,主要使用 ViewPager 控件,然后用小圆点作为 ViewPager 的指示器,标识当前滑动的位置,难点在于小圆点的位置需要与滑动操作进行同步。这里也可以使用开源项目:ViewPagerIndicator,在后面的开发中我们会用到。

创建 Activity:GuideActivity

取消标题栏,并创建相应的布局文件:activity_guide.xml

  • 在 MainActivity 和 GuideActivity 中添加启动方法 startAct(),如下所示。这是《第一行代码》中提到的方法,这样子在团队开发中就不用询问启动时都传了哪些参数,直接从这个方法中就可以得知。

    public static void startAct(Context ctx) {
        Intent intent = new Intent(ctx, GuideActivity.class);
        ctx.startActivity(intent);
    }
  • 在 SplashActivity 中添加动画监听,在动画结束时,启动引导界面或主界面

    set.setAnimationListener(new Animation.AnimationListener() {
        @Override
        public void onAnimationStart(Animation animation) {

        }

        @Override
        public void onAnimationEnd(Animation animation) {
            boolean isFirst = PrefUtils.getBoolean(SplashActivity.this, Config.IS_FIRST_ENTER, true);
            //判断是否是第一次进入
            if (isFirst) {
                GuideActivity.startAct(SplashActivity.this);
            } else {
                MainActivity.startAct(SplashActivity.this);
            }
            finish();
        }

        @Override
        public void onAnimationRepeat(Animation animation) {

        }
    });

填充布局文件 activity_guide

  • 在布局文件中添加 ViewPager,Button,以及自定义的小圆点(红色),小灰圆点需要与 ViewPager 的页数保持一致,所以需要在后台使用代码动态添加。

    <android.support.v4.view.ViewPager
        android:id="@+id/vp_Guide"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

    <Button
        android:id="@+id/btn_start"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="60dp"
        android:visibility="invisible"
        android:textColor="@color/text_color_button_start"
        android:background="@drawable/background_button_start"
        android:text="@string/start"/>

    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="30dp">

        <LinearLayout
            android:id="@+id/ll_container"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal"/>

        <ImageView
            android:id="@+id/iv_red_point"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/shape_point_red"/>

    </RelativeLayout>
  • 这里的小红点与小灰点用到了自定义形状:Shape — oval,方法是在 drawable 文件夹下创建两个资源文件:shape_point_gray.xml 和 shape_point_red.xml。

shape_point_gray.xml:


    <?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="oval">

        <size android:width="10dp" android:height="10dp"/>
        <solid android:color="@android:color/darker_gray"/>
    </shape>

shape_point_red.xml:


    <?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">

        <size android:width="10dp" android:height="10dp"/>
        <solid android:color="@android:color/holo_red_light"/>
    </shape>
  • 开始体验按钮用到了自定义样式,分别创建 Color 资源文件:text_color_button_start.xml,以及 drawable 资源文件:background_button_start.xml

text_color_button_start.xml:


    <?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">

        <item android:color="@android:color/black" android:state_pressed="true"/>
        <item android:color="@android:color/white"/>
    </selector>

background_button_start.xml:


    <?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">

        <item android:state_pressed="true" android:drawable="@drawable/button_red_pressed"/>
        <item android:drawable="@drawable/button_red_normal"/>
    </selector>

在 GuideActivity 中初始化数据

  • 创建适配器:GuideAdapter,用于 ViewPager 的数据适配

    class GuideAdapter extends PagerAdapter {

        @Override
        public int getCount() {
            return listImageView.size();
        }

        @Override
        public boolean isViewFromObject(View view, Object object) {
            return view == object;
        }

        //初始化item
        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            ImageView view = listImageView.get(position);
            container.addView(view);
            return view;
        }

        //回收item资源
        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            container.removeView((View) object);
        }
    }
  • 创建方法 initData(),对 ViewPager 中的引导图片进行初始化,并添加小灰圆点指示器

    //初始化数据
    private void initData() {
        //图片资源数组
        int[] imageIds = new int[]{R.drawable.guide_1, R.drawable.guide_2, R.drawable.guide_3};
        listImageView = new ArrayList<>();
        for (int i = 0; i < imageIds.length; i++) {
            //添加引导图
            ImageView view = new ImageView(this);
            view.setImageResource(imageIds[i]);
            view.setScaleType(ImageView.ScaleType.FIT_XY);
            listImageView.add(view);

            //添加圆点指示器
            ImageView pointView = new ImageView(this);
            pointView.setImageResource(R.drawable.shape_point_gray);
            if (i > 0) {//从第二个圆点开始设置左间距
                LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
                params.leftMargin = DensityUtils.dip2Px(this, 10);
                pointView.setLayoutParams(params);
            }
            llContainer.addView(pointView);
        }

        //计算两个圆点的距离:圆点本身的直径+间距
        pointDis = DensityUtils.dip2Px(this, 10 + 10);
        Log.i("123123", "pointDis-->" + pointDis);

        vpGuide.setAdapter(new GuideAdapter());
    }
  • 创建方法:initListener(),初始化 ViewPager 的滑动事件以及开始体验按钮的点击事件,在滑动事件中控制小圆点与滑动操作同步,以及按钮的显示与隐藏;在点击事件中需要设置标识,下次启动 App 时不再进入引导界面。

    //初始化监听
    private void initListener() {
        //设置ViewPager滑动监听
        vpGuide.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                Log.i("123123", "positionOffset-->" + positionOffset + ",positionOffsetPixels-->" + positionOffsetPixels);
                //获取布局参数
                RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) ivRedPoint.getLayoutParams();
                //设置小红点的偏移量
                params.leftMargin = (int) (positionOffset * pointDis) + position * pointDis;
                ivRedPoint.setLayoutParams(params);
            }

            @Override
            public void onPageSelected(int position) {
                //当滑动到最后一页时,才显示按钮
                if (position == listImageView.size() - 1) {
                    btnStart.setVisibility(View.VISIBLE);
                } else {
                    btnStart.setVisibility(View.INVISIBLE);
                }
            }

            @Override
            public void onPageScrollStateChanged(int state) {

            }
        });

        btnStart.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //启动主页面
                MainActivity.startAct(GuideActivity.this);
                //设置标志位,下次进入跳过引导界面
                PrefUtils.setBoolean(GuideActivity.this, Config.IS_FIRST_ENTER,false);
                finish();
            }
        });
    }

3 总结

到此,闪屏界面和引导界面就开发完了,接下来就要进入主界面开发了。
春节将近一星期没有碰电脑,也没有敲代码,还有点手生了,呵呵…

通过这次敲代码,有两个地方还是不太熟悉,一个就是资源文件的创建与编写,就是自定义小圆点的地方,是以 Shape 为根节点;还有一个就是小圆点指示器的布局,总是想之前是怎么实现的,而不是忘掉以前,从新写出实现方式。

不一样的地方:小圆点的计算方式,我是通过单位换算得到小灰圆点之间的距离,没有调用系统的视图树,添加布局监听来计算。

项目源代码:http://download.csdn.net/detail/xwdoor/9430613

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值