实现效果
功能说明
网速慢时,加载网络数据时,界面怎么处理才美观?载入失败或网络丢包时,如何让界面显得更和谐?这一直是开发人员和美工人员不绝于耳的问题,为了达到功能和UI的完美交互,我们不得不做一些基本的美化操作,本文就编写举例一个Android载入显示和载入失败的小Demo供大家参考。
这篇Blog主要实现了自定义有趣的动画载入视图,适用于各种网络及数据库数据载入UI界面显示,主要有载入动画和载入失败动画两种效果,主要功能原理利用了安卓逐帧动画和多视图布局原理,适用于新手及新学习Android的码友们,老玩家当然也可以看看,这个还是挺简单挺实用的,在后面会简略介绍实现方法及源代码,同时博客的最后还提供源代码和图片等资源github下载地址。
这篇文章的逐帧动画实现就不做详细介绍,前面的文章我有详细的介绍:
--------------------------------------------------------------------------------------------------------------------
Android实用视图动画及工具系列之一:简单的载入视图和载入动画:
--------------------------------------------------------------------------------------------------------------------
实现步骤
步骤一:添加逐帧动画资源和帧布局Drawable
顾名思义,逐帧动画就是一帧一帧的播放,在Android原生组件不主持gif的情况下,我们要实现逐帧动画只能使用一张一张图片来逐帧播放以达到效果,如下面的几张图(其他图片资源在源代码内,需要的自行下载):
将所有帧图片导入到Android项目目录的drawable文件夹下:
在drawable目录下新建face_progressbar_default.xml,和face_progressbar_failed.xml,输入如下代码(附属性说明):
animation-list:Android动画列表 ;
oneshot:true播放一次,false循环播放;
item:每项动画;
android:drawable:图片索引;
android:duration:每帧持续时间。
新建face_progressbar_default.xml:
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false" >
<item android:duration="100" android:drawable="@drawable/global_face_loading1"></item>
<item android:duration="100" android:drawable="@drawable/global_face_loading2"></item>
</animation-list>
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false" >
<item android:duration="100" android:drawable="@drawable/global_face_loadfail1"></item>
<item android:duration="100" android:drawable="@drawable/global_face_loadfail2"></item>
</animation-list>
步骤二:自定义动画类
新建类FaceImageView,代码如下,此类主要继承自ImageView,实现了基本动画播放,暂停和停止功能,注意包名改为自己的:
package com.jaiky.test.faceloadingview;
import android.content.Context;
import android.graphics.drawable.AnimationDrawable;
import android.util.AttributeSet;
import android.widget.ImageView;
/**
* Loading Faceview
* @author Jaiky
* @date Jul 4, 2016
* PS: Not easy to write code, please indicate.
*/
public class FaceImageView extends ImageView{
private AnimationDrawable loadingDrawable;
private AnimationDrawable failedDrawable;
public FaceImageView(Context context) {
super(context);
init();
}
public FaceImageView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public FaceImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public void init(){
setImageResource(R.drawable.face_progressbar_default);
loadingDrawable = (AnimationDrawable) getDrawable();
failedDrawable = (AnimationDrawable) getResources().getDrawable(R.drawable.face_progressbar_failed);
loadingDrawable.start();
}
/**
* 设置载入失败
*/
public void setFailed() {
setImageDrawable(failedDrawable);
failedDrawable.start();
}
/**
* 设置正在载入
*/
public void setloading() {
setImageDrawable(loadingDrawable);
loadingDrawable.start();
}
public void startAnimation(){
AnimationDrawable anim = (AnimationDrawable) getDrawable();
anim.start();
}
public void stopAnimation(){
AnimationDrawable anim = (AnimationDrawable) getDrawable();
//停留在第一针
anim.setVisible(true, true);
anim.stop();
}
public void pauseAnimation(){
AnimationDrawable anim = (AnimationDrawable) getDrawable();
anim.stop();
}
}
新建类FaceImageView
,此类主要用于控制帧动画的显示,隐藏,以及失败等,代码如下:
package com.jaiky.test.faceloadingview;
import android.content.Context;
import android.graphics.Color;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.TextView;
/**
* Loading Faceview
* @author Jaiky
* @date Jul 4, 2016
* PS: Not easy to write code, please indicate.
*/
public class FaceLoadingView extends FrameLayout{
private TextView tvInfo;
private FaceImageView faceView;
public FaceLoadingView(Context context) {
super(context);
init(context);
}
public FaceLoadingView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public FaceLoadingView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
public void init(Context context){
//设置动画视图
faceView = new FaceImageView(context);
DisplayMetrics dm = getResources().getDisplayMetrics();
//int widthHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 220, dm);
LayoutParams faceLayout = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
faceLayout.gravity = Gravity.CENTER;
faceView.setLayoutParams(faceLayout);
//设置显示文本
tvInfo = new TextView(context);
LayoutParams tvLayout = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
tvLayout.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
tvLayout.bottomMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 30, dm);
tvLayout.leftMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 5, dm);
tvInfo.setLayoutParams(tvLayout);
tvInfo.setText("努力加载中...");
tvInfo.setTextColor(Color.parseColor("#757575"));
tvInfo.setTextSize(TypedValue.COMPLEX_UNIT_SP, 11);
//添加到布局
addView(faceView);
addView(tvInfo);
}
public void setFailed() {
setVisibility(View.VISIBLE);
faceView.setFailed();
tvInfo.setText("载入失败,请刷新尝试...");
}
public void setFailedWithMsg(String msg) {
setVisibility(View.VISIBLE);
faceView.setFailed();
tvInfo.setText(msg);
}
public void setloading() {
setVisibility(View.VISIBLE);
faceView.setloading();
tvInfo.setText("努力加载中...");
}
public void setloadingWithMsg(String msg) {
setVisibility(View.VISIBLE);
faceView.setloading();
tvInfo.setText(msg);
}
/**
* 隐藏视图
*/
public void hiddenView(){
setVisibility(View.GONE);
}
/**
* 显示视图
*/
public void show(){
setVisibility(View.VISIBLE);
}
/**
* 设置加载消息内容
*
* @param msg
*/
public void setMsg(String msg) {
tvInfo.setText(msg);
}
}
步骤三:Demo测试修改布局和主类
修改activity_main.xml内容如下(注意自定义控件包名):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.jaiky.test.faceloadingview.MainActivity">
<Button
android:id="@+id/btn1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="载入成功"/>
<Button
android:id="@+id/btn2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="载入失败"/>
</LinearLayout>
新建布局文件activity_list.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.jaiky.test.faceloadingview.MainActivity">
<com.jaiky.test.faceloadingview.FaceLoadingView
android:id="@+id/faceView"
android:layout_width="220dp"
android:layout_height="220dp"
android:layout_centerInParent="true"/>
<TextView
android:id="@+id/mTextView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="显示加载后的数据\nShow loaded Data"
android:background="@color/colorAccent"
android:textColor="#ffffff"
android:gravity="center"
android:textSize="25sp"/>
</RelativeLayout>
修改MainActiivty类内容如下(注意包名):
package com.jaiky.test.faceloadingview;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
Button btn1, btn2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn1 = (Button) findViewById(R.id.btn1);
btn2 = (Button) findViewById(R.id.btn2);
btn1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, ListActivity.class);
intent.putExtra("isFail", false);
startActivity(intent);
}
});
btn2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, ListActivity.class);
intent.putExtra("isFail", true);
startActivity(intent);
}
});
}
}
package com.jaiky.test.faceloadingview;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.TextView;
public class ListActivity extends AppCompatActivity {
TextView mTextView;
FaceLoadingView mFaceLoadingView;
boolean isFail;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list);
mFaceLoadingView = (FaceLoadingView) findViewById(R.id.faceView);
mTextView = (TextView) findViewById(R.id.mTextView);
mTextView.setVisibility(View.GONE);
isFail = getIntent().getBooleanExtra("isFail", false);
//Simulate get data
if (isFail) {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
mFaceLoadingView.setFailed();
}
}, 5000);
}
else {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
mFaceLoadingView.hiddenView();
mTextView.setVisibility(View.VISIBLE);
}
}, 5000);
}
}
}
最后是在AndroidManifest文件加入新的Activity:
<activity android:name=".ListActivity">
</activity>
--------------------------------------------------------------------------------------------------------------------
获取源代码及资源文件:
--------------------------------------------------------------------------------------------------------------------