zoukankan      html  css  js  c++  java
  • Java安卓开发入门-TabLayout、Fragment和属性动画

    功能介绍

    • 使用Java编写
    • 主要有那些功能?
      • ex1:通过seekbar控制lottie动画播放,以及动画自动播放
      • ex2:通过下方输入参数控制中间view的动画效果
      • ex3:使用tablayout和fragment进行标签页切换,并加入切换后前5s播放lottie动画的功能,动画结束后淡入淡出

    效果图

    前置技能点

    用用java写吧。

    Android开发入门http://hukai.me/android-training-course-in-chinese/basics/index.html

    java入门https://www.runoob.com/java/java-tutorial.html

    Fragment参考

    • 官⽅⽂档:

    https://developer.android.com/guide/fragments

    • 中⽂翻译:

    https://juejin.cn/post/6900739309826441224#heading-29

    https://juejin.cn/post/6901453354463920135

    • Fragment 源码解读:

    https://juejin.cn/post/6844904086437904398

    Animation参考

    • 属性动画:

    https://developer.android.com/guide/topics/graphics/prop-animation

    • ⻉塞尔曲线可视化:

    https://cubic-bezier.com/

    • ⾮官⽅总结:

    https://juejin.cn/post/6844903465211133959

    • 其他阅读材料:属性动画

    https://rengwuxian.com/123.html

    https://rengwuxian.com/127.html

    • Lottie Android 指南:

    https://airbnb.io/lottie/#/android

    • Lottie 资源:

    https://lottiefiles.com/

    本项目地址在本人github

    项目结构

    项目是老师给的模板中融合了我参考Android Studio的Tabbed Activity模板添加的文件。文件比较多,只列了部分,也只挑其中重要的讲。

    Java文件

    从上到下依次为:

    • 1-3 三个按键对应的activity类
    • 4 主界面活动,控制三个按键逻辑,进入三个不同的activity
    • 5 这个名字取得不太好,因为是直接照搬的我上一篇教程。RecyclerView的自定义Adapter类,主要是规定了如何装载和控制视图内容,包括item的点击事件,这次把ViewHolder也放在里面了
    • 6 写这个的时候发现并不需要这个类,这个类是默认模板控制每个页面view内容的
    • 7 调用SectionsPagerAdapter的getItem时需要来实例化给定页面的fragment实例,通过PlaceholderFragment.newInstance实现
    • 8 自定义的view类型,可以制作彩虹文字
    • 9 自定义的SectionsPagerAdapter,继承自FragmentPagerAdapter,控制整个Fragment的显示效果,包括tab的文字,总页面数量等

    Layout文件

    分别为对应的activity的布局,不详细解释了,说一下要注意的点。

    xml添加lottie动画

    如何添加lottie动画在前置技能点有,在本app中,需要在ex1.xml和fragment_placeholder.xml中加入(当然id注意不要重复)

        <com.airbnb.lottie.LottieAnimationView
            android:id="@+id/animation_view"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            app:lottie_loop="true"
            app:lottie_rawRes="@raw/material_wave_loading" />

    其中app:lottie_rawRes指定了json格式文件的动画文件位置,一般放在raw文件夹下。

    fragment_placeholder.xml中只有animation_view2和recycler_view,每个fragment片段就是这两个view淡入淡出实现的

    功能实现

    勾选checkbox切换动画播放状态

    这里的loopCheckBox是一个CheckBox类型

            loopCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
                @Override
                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                    if (isChecked) {
                        // 当选中自动播放的时候,开始播放 lottie 动画,同时禁止手动修改进度
                        animationView.playAnimation();
                        seekBar.setEnabled(false);
                    } else {
                        // 当去除自动播放时,停止播放 lottie 动画,同时允许手动修改进度
                        animationView.pauseAnimation();
                        seekBar.setEnabled(true);
                    }
                }
            });
    

      

    seekbar控制动画进度

    这里的seekBar是一个SeekBar类型,已通过findViewById(R.id.seekbar)绑定

            seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
                @Override
                public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                    // TODO ex1-2: 这里应该调用哪个函数呢
                    // 提示1:可以参考 https://airbnb.io/lottie/#/android?id=custom-animators
                    // 提示2:SeekBar 的文档可以把鼠标放在 OnProgressChanged 中间,并点击 F1 查看,
                    // 或者到官网查询 https://developer.android.google.cn/reference/android/widget/SeekBar.OnSeekBarChangeListener.html#onProgressChanged(android.widget.SeekBar,%20int,%20boolean
    
                    // 每次progress改变的时候都会调用这个函数,所以只需要在这时候将新的progress对应的百分比传入即可
                    // progress默认是1-100的整数,用getMax()最理想
                    animationView.setProgress((float)progress/seekBar.getMax());
    
                }
    

      

    ex2中的一些实现

    选颜色是通过给颜色view添加一个点击监听,通过ColorPicker类展示的选择颜色窗口

    复杂的动画效果是通过AnimatorSet串联了多个动画实现的,其中控制颜色使用的是ObjectAnimator.ofArgb()实现的,其他的是ofFloat()

    ex3的一些实现

    主活动如下

    public class Ch3Ex3Activity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_ch3ex3);
    
            // TODO: ex3-1. 添加 ViewPager 和 Fragment 做可滑动界面
            SectionsPagerAdapter sectionsPagerAdapter = new SectionsPagerAdapter(this, getSupportFragmentManager());
            ViewPager viewPager = findViewById(R.id.view_pager);
            viewPager.setAdapter(sectionsPagerAdapter);
    
            // TODO: ex3-2, 添加 TabLayout 支持 Tab
            TabLayout tabs = findViewById(R.id.tabs);
            tabs.setupWithViewPager(viewPager);
        }
    }
     
    

      

    SectionsPagerAdapter类

    public class SectionsPagerAdapter extends FragmentPagerAdapter {
    
        @StringRes
        private static final int[] TAB_TITLES = new int[]{R.string.tab_text_1, R.string.tab_text_2, R.string.tab_text_3};
        private final Context mContext;
    
        public SectionsPagerAdapter(Context context, FragmentManager fm) {
            super(fm);
            mContext = context;
        }
    
        @Override
        public Fragment getItem(int position) {
            // getItem is called to instantiate the fragment for the given page.
            // Return a PlaceholderFragment (defined as a static inner class below).
            return PlaceholderFragment.newInstance(position);
        }
    
        @Nullable
        @Override
        public CharSequence getPageTitle(int position) {
            return mContext.getResources().getString(TAB_TITLES[position]);
        }
    
        @Override
        public int getCount() {
            // Show 3 total pages.
            return 3;
        }
    }
    

      

    PlaceholderFragment类

    public class PlaceholderFragment extends Fragment {
    
        private LottieAnimationView animationView2;
        private RecyclerView myRecycler;
        private Context mContext;
    
        private List list = new ArrayList();
    
        private static final String ARG_SECTION_NUMBER = "tab_number";
    
        public static PlaceholderFragment newInstance(int index) {
            PlaceholderFragment fragment = new PlaceholderFragment();
            Bundle bundle = new Bundle();
            bundle.putInt(ARG_SECTION_NUMBER, index);
            fragment.setArguments(bundle);
            return fragment;
        }
    
        @Override
        public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            // TODO ex3-3: 修改 fragment_placeholder,添加 loading 控件和列表视图控件
            View root = inflater.inflate(R.layout.fragment_placeholder, container, false);
            animationView2 = root.findViewById(R.id.animation_view2);
            myRecycler = root.findViewById(R.id.recycler_view);
            mContext = container.getContext();
            return root;
        }
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            // 初始化数组
            for (int i = 1; i < 101; i++) {
                list.add(String.format("这里是第 %d 行", i));
            }
        }
    
        @Override
        public void onActivityCreated(@Nullable Bundle savedInstanceState) {
            super.onActivityCreated(savedInstanceState);
            // 播放动画
            animationView2.playAnimation();
    
            // 展示 recycler view
            myRecycler.setLayoutManager(new LinearLayoutManager(mContext));
            myRecycler.setAdapter(new MyAdapter(list));
            myRecycler.setVisibility(View.GONE); //前5s并不显示不渲染
    
            ObjectAnimator fadeOutAnimator = ObjectAnimator.ofFloat(animationView2,
                    "alpha", 1f, 0f);//淡出效果,alpha从1到0
            fadeOutAnimator.setDuration(1000);// 淡出1s
    //        fadeOutAnimator.setRepeatCount(0); // 设置动画重复播放次数 = 重放次数+1
    
            ObjectAnimator fadeInAnimator = ObjectAnimator.ofFloat(myRecycler,
                    "alpha", 0f, 1f);
            fadeInAnimator.setDuration(1000);
    //        fadeInAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    //           // 如果fadeInAnimator = ValueAnimator.ofInt(0,255) ,也可以使用这个
    //            @Override
    //            public void onAnimationUpdate(ValueAnimator animation) {
    //                int curValue = (int)animation.getAnimatedValue();
    //                myRecycler.setAlpha((float)curValue/255);
    //                Log.d("now alpha:" + myRecycler.getAlpha()," curValue:"+curValue);
    //            }
    //        });
    
            // 丢到一个动画集合里,一起运行
            final AnimatorSet fadeInOut = new AnimatorSet();
            fadeInOut.playTogether(fadeInAnimator,fadeOutAnimator);
    
            getView().postDelayed(new Runnable() {
                @Override
                public void run() {
                    // 这里会在 5s 后执行
                    // TODO ex3-4:实现动画,将 lottie 控件淡出,列表数据淡入
                    myRecycler.setAlpha(0f); //先设置透明度为0再显示
                    myRecycler.setVisibility(View.VISIBLE);
                    fadeInOut.start();
                }
            }, 5000);
    
            //  如果不需要等5s设置透明度,可以用这个delay
            //  fadeInOut.setStartDelay(5000);
            //  fadeInOut.start();
    
        }
    
    }
    

      

    主要的坑是

    • setRepeatCount()设置的是重复次数而不是运行次数,如果设置为1,是运行两次
    • 对于一个想要延迟淡入的view,首先要设置visibility为GONE,然后在即将淡入前设置透明度为0,visibility为VISIBLE

    说明

    本例中的不同fragment切换时的动画有时有,有时没有。

    这是因为fragment默认是预加载下一个的,所以tab1和2都加载了,再进入tab2时没有加载动画,而到tab3就有动画了。

    默认的预加载如果想要取消,需要自定义一个判断当前fragment是否可见的子类,参考https://www.jianshu.com/p/0e2d746e3a3d

  • 相关阅读:
    链接脚本语法
    STM32 硬件IIC接口总线
    C99一些特性
    oneid与用户标签之间的相互打通 实现用户标签
    图计算实现ID_Mapping、Oneid打通数据孤岛
    对于hive使用的一点记录
    centos7 hue安装
    Kafka监控安装
    hadoop2.6.0集群搭建
    centos6+cdh5.4.0 离线搭建cdh搭建
  • 原文地址:https://www.cnblogs.com/smileglaze/p/14501545.html
Copyright © 2011-2022 走看看