快速开发之加载动画
来源:互联网 发布:单反照片导入mac 编辑:程序博客网 时间:2024/06/05 15:21
现在的App或多或少都会用到加载动画,那么如何将多样性的加载动画集成到我们的页面框架中呢?
一些实现方式:
方式一:将加载动画封装成自定义View,在布局中进行添加。
<?xml version="1.0" encoding="utf-8"?><FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/activity_project_select_designer" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v7.widget.RecyclerView android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="match_parent"/> <LoadingProgress android:id="@+id/loading_progress" android:layout_width="match_parent" android:layout_height="match_parent" /></FrameLayout>
这样的实现方式,需要在每一个使用加载动画的布局文件中添加LoadingProgress,并且在界面调用时控制显示逻辑。如果大面积的使用到重复的代码,我们可以对代码进行封装,例如封装成一个RecyclerWithLoadAnimView,在该类中进行对LoadingProgress的显示控制。
但是问题来了,如果有特定需求需要继承RecyclerView实现特定功能呢?
所以我们还是不这样写了,为了解耦合,我们还是讲LoadingProgress放在别的地方去写。
方式二:在BaseActivity中添加LoadingProgress
那么问题来了,我们怎么在不通过布局文件,并且不影响子类的情况下,添加LoadingProgress呢?
其实很简单,DecorView大家都知道吧,这是我们在onCreate() 的setContentView()方法返回的布局的一个父容器。我们可以直接将LoadingProgress添加到布局的一个父容器中就可以了,然后在BaseActivity中对LoadingProgress进行逻辑控制。
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(...); }
现在我们找一下这个DecorView。大家都知道,我们视图都会放在Window里,而Window类却是一个抽象类,所以我们要找到它的子类,PhoneWindow类,就是这个类,我们的setContentView方法最终会调用PhoneWindow类中的
@Overridepublic void setContentView(int layoutResID) { if (mContentParent == null) { installDecor(); } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) { mContentParent.removeAllViews(); } ... }
多余的代码我们不用看,我们只需要看installDecor()方法,这就是创建DecorView的方,我们看一下:
private void installDecor() { if (mDecor == null) { mDecor = generateDecor(); mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS); mDecor.setIsRootNamespace(true); if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) { mDecor.postOnAnimation(mInvalidatePanelMenuRunnable); } } if (mContentParent == null) { mContentParent = generateLayout(mDecor); ... }}protected DecorView generateDecor() { return new DecorView(getContext(), -1);}private final class DecorView extends FrameLayout{ ...}
这里我们看到generateDecor()方法,这只是创建了一个DecorView,不过我们可以知道DecorView是FrameLayout的子类。
但是我们没有找到对我们有利的东西,不过大家不要气馁,相信有些人已经看到另一个对象mContentParent,顾名思义,它应该是内容的父类,我们继续往下看 mContentParent = generateLayout(mDecor); 这个MContentParent是通过mDecor创建的。接下来,我们看一下generateLayout()方法:
public static final int ID_ANDROID_CONTENT = com.android.internal.R.id.content;protected ViewGroup generateLayout(DecorView decor) { ... View in = mLayoutInflater.inflate(layoutResource, null); decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); mContentRoot = (ViewGroup) in; ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT); ... return contentParent;}
通过对源码的查看,我们知道了mContentParent是DecorView 的一个子View,而contentParent是通过findViewById()这个方法得到的,而这个Id就是 R.id.content ,所以我们找到了页面的另一父容器mContentParent,并获取到了它在布局中的Id。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" android:orientation="vertical"> <ViewStub android:id="@+id/action_mode_bar_stub" android:inflatedId="@+id/action_mode_bar" android:layout="@layout/action_mode_bar" android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="?attr/actionBarTheme" /> <FrameLayout android:id="@android:id/content" android:layout_width="match_parent" android:layout_height="match_parent" android:foregroundInsidePadding="false" android:foregroundGravity="fill_horizontal|top" android:foreground="?android:attr/windowContentOverlay" /></LinearLayout>
这样我们在BaseActivity中就能得到mContentParent对象了。而且它也是一个帧布局,讲到这里应该比较清楚了,我们可以直接将LoadingProgress添加到mContentParent中,并在BaseActivity中进行逻辑控制。
public abstract class BaseActivity extends AppCompatActivity { private LoadingProgress mProgress; private List<View> views = new ArrayList<>(); private boolean isLoading = false; private ViewGroup mContentView; @Override public void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); initView(); initData(); initListener(); } @Override public void setContentView(int layoutResID) { super.setContentView(layoutResID); //在setContentView() 中所设置布局的父容器的ID 是 android.R.id.content mContentView = (ViewGroup) findViewById(android.R.id.content); setupLoadView(); } /** * 初始化加载动画视图 * 找到布局中的所有一级子view */ private void setupLoadView() { if (mProgress != null) return; mProgress = new LoadingProgress(this); mProgress.setBackgroundResource(R.color.all_bg); View contentView = mContentView.getChildAt(0); if (contentView instanceof ViewGroup) { ViewGroup contentGroup = (ViewGroup) contentView; for (int i = 1; i < contentGroup.getChildCount(); i++) { views.add(contentGroup.getChildAt(i)); } } int marginTop = getTitleHeight(); FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); layoutParams.setMargins(0, marginTop, 0, 0); mContentView.addView(mProgress, layoutParams); } /** * 开启动画 */ protected void openLoadAnim() { if (isLoading || mProgress == null) return; mProgress.show(); isLoading = true; } /** * 关闭动画 */ protected void closeLoadAnim() { if (!isLoading || mProgress == null) return; mProgress.dismiss(); isLoading = false; } /** * 初始化view * 设置view 部分属性(显示隐藏等) */ protected abstract void initView(); /** * 加载数据 * 在这里调用 openLoadAnim() 方法 */ protected abstract void initData(); /** * 初始化监听 */ protected abstract void initListener(); /** * 返回title高度,防止加载动画格挡标题 */ protected abstract int getTitleHeight(); /** * 父容器获取焦点,禁止子控件自动获取焦点 * 布局中有EditText时,禁止弹出软键盘 */ protected void containerFocus() { mContentView.getChildAt(0).setFocusable(true); } @Override protected void onDestroy() { super.onDestroy(); closeLoadAnim(); mProgress = null; views.clear(); views = null; mContentView = null; }}
大家可能看到我没有在onCreate中调用initView(),initData(),initListener()方法,而是在onPostCreate方法中调用。原因就留给大家去探索了。
项目地址
https://github.com/Huang102/LoadAnimTemplate
- 快速开发之加载动画
- 快速开发04之动画的统一配置
- ArcGlobe三维开发之十三——加载保存动画
- iOS开发 ----- 加载动画之牛顿摆的实现
- 安卓开发之自定义粒子旋转动画加载控件
- 安卓开发之使用PathMeasure自定义加载动画控件
- iOS开发 ----- 加载动画之牛顿摆的实现
- Android快速开发 动画系列(一) 之 TranslateAnimation(平移动画)
- Android快速开发 动画系列(二) 之 overridePendingTransition(跳转动画)
- iPhone开发【十三】动画效果之最简单的动画——动态加载图片
- iPhone开发【十三】动画效果之最简单的动画——动态加载图片
- 安卓开发之自定义动画控件BatteryView(电池加载动画)
- tweenMAX 快速开发tween动画
- IOS 动画之加载图片
- 自定义之-加载中动画
- iOS之TableViewCell加载动画
- 小程序之加载动画
- android之动画开发
- knn分类
- JAVA基础(二)·类的一些基础特性概念
- BZOJ 1398: Vijos1382寻找主人 Necklace 字符串最小表示法
- wake-sleep算法
- 五、stpringMVC
- 快速开发之加载动画
- Unity 启动画面淡入淡出
- 可变参数列表解析
- Hessian矩阵与牛顿法
- 开源软件和商业软件版本的介绍:alpha、beta、rc、GA等等
- Servlet开发须知知识点
- tornado处理post请求的json数据
- PHP中单引号和双引号的区别
- 用Swift3实现从中心开始,逆时针打印 n*n 矩阵