1 Skeleton
1.阅览
2.使用说明
Android Studio 中使用需要dependencies中添加:
dependencies {
implementation ‘com.ethanhua:skeleton:1.1.2’
implementation ‘io.supercharge:shimmerlayout:2.1.0’
}
Skeleton库有两种主要用法,一种是和RecycleView 搭配使用,另外一种是直接作用于View。
主要函数说明:
bind函数:
public class Skeleton {
//用于RecycleView,配合RecyclerViewSkeletonScreen
public static RecyclerViewSkeletonScreen.Builder bind(RecyclerView recyclerView) {
return new RecyclerViewSkeletonScreen.Builder(recyclerView);
}
//用于普通view,配合ViewSkeletonScreen
public static ViewSkeletonScreen.Builder bind(View view) {
return new ViewSkeletonScreen.Builder(view);
}
}
2.1RecyclerViewSkeletonScreen 作用于RecycleView
skeletonScreen = Skeleton.bind(mRecycleView)
.adapter(mAdapterDemo)
.shimmer(true)
.angle(20)
.frozen(false)
.duration(3300)
.color(R.color.shimmer_color)
// .count(10)
.load(R.layout.skeletonlayout2)
.show(); //default count is 10
bind //绑定RecycleView,不要给RecycleView设置
adapteradapter //设置Skeleton消失时要RecycleView设置的 adapter,内部会自动绑定
load //预览加载的RecycleView item 布局文件
shimmer(true) // 是否显示shimmer动画,默认显示
count(10) // 设置recycleView 默认预览加载条目数,默认10
color(color) // shimmer 动画颜色,默认 #a2878787
angle(20) //shimmer 动画角度,默认 20度
duration(1000) // shimmer动画持续时间 ,默认1000ms;
frozen(true) // skeleton 显示时是否RecycleView 不可操作,默认不可操作
hide // 关闭Skeleton,就会自动绑定Adapter,显示真正数据
2.2ViewSkeletonScreen作用于View
skeletonScreen = Skeleton.bind(mRootView)
.load(R.layout.skeleton_view_layout)
.shimmer(true)
.angle(20)
.duration(1000)
.color(R.color.shimmer_color)
.show();
bind //绑定view
load //预览加载的View 布局,会替换绑定view内的view
shimmer(true) // 是否显示shimmer动画,默认显示
color(color) // shimmer 动画颜色,默认 #a2878787
angle(20) //shimmer 动画角度,默认 20度
duration(1000) // shimmer动画持续时间 ,默认1000ms;
hide // 关闭Skeleton 加载预览,显示真正View
3.示例代码
3.1RecycleView 骨架加载预
layout_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Main54Activity">
<android.support.v7.widget.RecyclerView
android:id="@+id/recycleview"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent">
</android.support.v7.widget.RecyclerView>
</android.support.constraint.ConstraintLayout>
MainActivity.java:
public class Main54Activity extends AppCompatActivity {
private RecyclerView mRecycleView;
private ArrayList<String> mData;
private AdapterDemo mAdapterDemo;
private RecyclerViewSkeletonScreen skeletonScreen;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecycleView = findViewById(R.id.recycleview);
LinearLayoutManager layoutManager = new LinearLayoutManager(this );
mRecycleView.setLayoutManager(layoutManager);
layoutManager.setOrientation(OrientationHelper. VERTICAL);
initData();
}
private void initData() {
mData = new ArrayList<>();
mData.add("111111111111111111111111111111111111111111");
mData.add("222222222222222222222222222222222222222222");
mData.add("333333333333333333333333333333333333333333");
mData.add("444444444444444444444444444444444444444444");
mData.add("555555555555555555555555555555555555555555");
mData.add("666666666666666666666666666666666666666666");
mAdapterDemo = new AdapterDemo(mData,Main54Activity.this);
skeletonScreen = Skeleton.bind(mRecycleView)
.adapter(mAdapterDemo)
.shimmer(true)
.angle(20)
.frozen(false)
.duration(3300)
.color(R.color.shimmer_color)
// .count(10)
.load(R.layout.layout_skeleton)
.show(); //default count is 10
mRecycleView.postDelayed(new Runnable() {
@Override
public void run() {
skeletonScreen.hide();
}
}, 3300);
}
}
Adapter:
public class AdapterDemo extends RecyclerView.Adapter<AdapterDemo.AdapterDemoViewHolder> {
private ArrayList<String> mData;
private Context mContext;
public AdapterDemo(ArrayList<String> mData, Context mContext) {
this.mData = mData;
this.mContext = mContext;
}
@NonNull
@Override
public AdapterDemoViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_skeleton_layout, viewGroup, false);
return new AdapterDemoViewHolder(v);
}
@Override
public void onBindViewHolder(@NonNull AdapterDemoViewHolder adapterDemoViewHolder, int i) {
String data = mData.get(i);
adapterDemoViewHolder.imageView.setImageResource(R.mipmap.ic_launcher);
adapterDemoViewHolder.textView.setText(data);
}
@Override
public int getItemCount() {
return mData.size();
}
public class AdapterDemoViewHolder extends RecyclerView.ViewHolder {
private ImageView imageView;
private TextView textView;
public AdapterDemoViewHolder(@NonNull View itemView) {
super(itemView);
imageView = itemView.findViewById(R.id.imageview);
textView = itemView.findViewById(R.id.textview);
}
}
}
item_skeleton_layout.xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="120dp"
xmlns:app="http://schemas.android.com/apk/res-auto">
<ImageView
android:id="@+id/imageview"
android:layout_width="100dp"
android:layout_height="100dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
<TextView
android:id="@+id/textview"
android:layout_width="100dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:maxLines="3"/>
</android.support.constraint.ConstraintLayout>
layout_skeleton.xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="120dp"
xmlns:app="http://schemas.android.com/apk/res-auto">
<ImageView
android:id="@+id/imageview"
android:layout_width="85dp"
android:layout_height="85dp"
android:background="#CDCDCD"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
<TextView
android:id="@+id/textview"
android:layout_width="100dp"
android:layout_height="15dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@id/textview2"
app:layout_constraintRight_toRightOf="parent"
android:background="#CDCDCD"
android:maxLines="3"
android:layout_marginTop="10dp"
/>
<TextView
android:id="@+id/textview2"
android:layout_width="100dp"
android:layout_height="15dp"
app:layout_constraintTop_toBottomOf="@id/textview"
app:layout_constraintBottom_toTopOf="@+id/textview3"
app:layout_constraintRight_toRightOf="parent"
android:background="#CDCDCD"
android:maxLines="3"
/>
<TextView
android:id="@+id/textview3"
android:layout_width="100dp"
android:layout_height="15dp"
app:layout_constraintTop_toBottomOf="@id/textview2"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:background="#CDCDCD"
android:maxLines="3"
android:layout_marginBottom="10dp" />
</android.support.constraint.ConstraintLayout>
3.1骨架加载预览 View 相关
layout_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
android:id="@+id/rootview"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<LinearLayout
android:id="@+id/linearlayout1"
android:layout_width="match_parent"
android:layout_height="250dp"
android:orientation="vertical"
android:gravity="center"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent">
<ImageView
android:layout_width="300dp"
android:layout_height="120dp"
android:scaleType="fitCenter"
android:src="@drawable/image_home_game_nor"
android:layout_marginBottom="5dp"/>
<TextView
android:layout_width="350dp"
android:layout_height="20dp"
android:textSize="15sp"
android:text="电视节目广告太多,优化节目播出效果"
android:lines="1"
android:layout_marginBottom="5dp"/>
<TextView
android:layout_width="350dp"
android:layout_height="20dp"
android:textSize="15sp"
android:text="电视节目广告太多,优化节目播出效果"
android:lines="1"
android:layout_marginBottom="5dp"/>
<TextView
android:layout_width="350dp"
android:layout_height="20dp"
android:textSize="15sp"
android:text="电视节目广告太多,优化节目播出效果"
android:lines="1"
android:layout_marginBottom="5dp"/>
</LinearLayout>
<LinearLayout
android:id="@+id/linearlayout2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/linearlayout1"
app:layout_constraintBottom_toTopOf="@id/linearlayout3"
android:layout_marginTop="30dp"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="30dp"
android:textSize="24sp"
android:text="电视节目广告太多,优化节目播出效果"
android:lines="1"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginBottom="20dp"/>
<TextView
android:layout_width="match_parent"
android:layout_height="30dp"
android:textSize="24sp"
android:text="电视节目广告太多,优化节目播出效果"
android:lines="1"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginBottom="20dp"/>
<TextView
android:layout_width="match_parent"
android:layout_height="30dp"
android:textSize="24sp"
android:text="电视节目广告太多,优化节目播出效果"
android:lines="1"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginBottom="20dp"/>
</LinearLayout>
<LinearLayout
android:id="@+id/linearlayout3"
android:layout_width="match_parent"
android:layout_height="150dp"
android:orientation="horizontal"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/linearlayout2"
app:layout_constraintBottom_toTopOf="parent">
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_gravity="left"
android:src="@mipmap/ic_launcher"
android:scaleType="fitCenter"/>
<TextView
android:layout_width="200dp"
android:layout_height="20dp"
android:textSize="15sp"
android:text="电视节目广告太多,优化节目播出效果"
android:lines="1"
android:layout_gravity="right"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginBottom="20dp"/>
</LinearLayout>
</android.support.constraint.ConstraintLayout>
Activity.java:
public class Main55Activity extends AppCompatActivity {
private ConstraintLayout mRootView;
private ViewSkeletonScreen skeletonScreen;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRootView = findViewById(R.id.rootview);
skeletonScreen = Skeleton.bind(mRootView)
.load(R.layout.skeleton_view_layout)
.shimmer(true)
.angle(20)
.duration(1000)
.color(R.color.shimmer_color)
.show();
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
skeletonScreen.hide();
}
},3000);
}
}
skeleton_view_layout.xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<LinearLayout
android:id="@+id/linearlayout1"
android:layout_width="match_parent"
android:layout_height="250dp"
android:orientation="vertical"
android:gravity="center"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent">
<ImageView
android:layout_width="300dp"
android:layout_height="120dp"
android:scaleType="fitCenter"
android:background="#cdcdcd"
android:layout_marginBottom="5dp"/>
<TextView
android:layout_width="350dp"
android:layout_height="20dp"
android:textSize="20sp"
android:background="#cdcdcd"
android:layout_marginBottom="5dp"/>
<TextView
android:layout_width="350dp"
android:layout_height="20dp"
android:textSize="20sp"
android:background="#cdcdcd"
android:layout_marginBottom="5dp"/>
<TextView
android:layout_width="350dp"
android:layout_height="20dp"
android:textSize="20sp"
android:background="#cdcdcd"
android:layout_marginBottom="5dp"/>
</LinearLayout>
<LinearLayout
android:id="@+id/linearlayout2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/linearlayout1"
app:layout_constraintBottom_toTopOf="@id/linearlayout3"
android:layout_marginTop="30dp"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="30dp"
android:textSize="20sp"
android:background="#cdcdcd"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginBottom="20dp"/>
<TextView
android:layout_width="match_parent"
android:layout_height="30dp"
android:textSize="20sp"
android:background="#cdcdcd"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginBottom="20dp"/>
<TextView
android:layout_width="match_parent"
android:layout_height="30dp"
android:textSize="20sp"
android:background="#cdcdcd"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginBottom="20dp"/>
</LinearLayout>
<LinearLayout
android:id="@+id/linearlayout3"
android:layout_width="match_parent"
android:layout_height="150dp"
android:orientation="horizontal"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/linearlayout2"
app:layout_constraintBottom_toTopOf="parent">
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
android:background="#cdcdcd"
android:layout_gravity="left"/>
<TextView
android:layout_width="200dp"
android:layout_height="20dp"
android:textSize="20sp"
android:background="#cdcdcd"
android:layout_gravity="right"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginBottom="20dp"/>
</LinearLayout>
</android.support.constraint.ConstraintLayout>
2 Spruce
添加依赖
dependencies {
compile 'com.willowtreeapps.spruce:spruce-android:1.0.1'
}
使用:
Animator spruceAnimator = new Spruce
.SpruceBuilder(parentViewGroup)
.sortWith(new DefaultSort(/*interObjectDelay=*/50L))
.animateWith(animators)
.start();
https://github.com/willowtreeapps/spruce-android
public class RecyclerFragment extends Fragment {
public static RecyclerFragment newInstance() {
return new RecyclerFragment();
}
private RecyclerView recyclerView;
private Animator spruceAnimator;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, @Nullable Bundle savedInstanceState) {
recyclerView = container.findViewById(R.id.recycler);
recyclerView.setHasFixedSize(true);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext()) {
@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
super.onLayoutChildren(recycler, state);
initSpruce();
}
};
// Mock data objects
List<ExampleData> placeHolderList = new ArrayList<>();
for (int i = 0; i < 10; i++) {
placeHolderList.add(new ExampleData());
}
recyclerView.setAdapter(new RecyclerAdapter(placeHolderList));
recyclerView.setLayoutManager(linearLayoutManager);
return inflater.inflate(R.layout.recycler_fragment, container, false);
}
@Override
public void onResume() {
super.onResume();
if (spruceAnimator != null) {
spruceAnimator.start();
}
}
private void initSpruce() {
spruceAnimator = new Spruce.SpruceBuilder(recyclerView)
.sortWith(new DefaultSort(100))
.animateWith(DefaultAnimations.shrinkAnimator(recyclerView, 800),
ObjectAnimator.ofFloat(recyclerView, "translationX", -recyclerView.getWidth(), 0f).setDuration(800))
.start();
}
private class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.ViewHolder> {
List<ExampleData> placeholderList;
class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
RelativeLayout placeholderView;
ViewHolder(View itemView) {
super(itemView);
placeholderView = (RelativeLayout) itemView.findViewById(R.id.placeholder_view);
placeholderView.setOnClickListener(this);
}
@Override
public void onClick(View v) {
initSpruce();
}
}
RecyclerAdapter(List<ExampleData> placeholderList) {
this.placeholderList = placeholderList;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
RelativeLayout view = (RelativeLayout) LayoutInflater.from(parent.getContext())
.inflate(R.layout.view_placeholder, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
}
@Override
public int getItemCount() {
return placeholderList.size();
}
}
}
recycler_fragment.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/recycler_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.appcompat.widget.Toolbar
android:id="@+id/recycler_tool_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorPrimary" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
view_placeholder.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/placeholder_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/white">
<View
android:id="@+id/square"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginLeft="20dp"
android:layout_marginStart="20dp"
android:layout_marginTop="20dp"
android:background="@color/square_background"/>
<View
android:id="@+id/darker_gray_strip"
android:layout_width="150dp"
android:layout_height="10dp"
android:layout_marginLeft="10dp"
android:layout_marginStart="10dp"
android:layout_marginTop="20dp"
android:layout_toRightOf="@id/square"
android:layout_toEndOf="@id/square"
android:alpha="1"
android:background="@color/fake_paragraphs"/>
<View
android:id="@+id/secondary_gray_strip"
android:layout_width="250dp"
android:layout_height="10dp"
android:layout_below="@id/darker_gray_strip"
android:layout_marginLeft="10dp"
android:layout_marginStart="10dp"
android:layout_marginTop="20dp"
android:layout_toRightOf="@id/square"
android:layout_toEndOf="@id/square"
android:alpha="0.5"
android:background="@color/fake_paragraphs"/>
<View
android:id="@+id/tertiary_gray_strip"
android:layout_width="200dp"
android:layout_height="10dp"
android:layout_below="@id/secondary_gray_strip"
android:layout_marginStart="10dp"
android:layout_marginLeft="10dp"
android:layout_marginTop="20dp"
android:layout_toRightOf="@id/square"
android:layout_toEndOf="@id/square"
android:alpha="0.5"
android:background="@color/fake_paragraphs"/>
<View
android:layout_width="match_parent"
android:layout_height="3dp"
android:layout_below="@id/tertiary_gray_strip"
android:layout_marginTop="10dp"
android:background="@color/recycler_background" />
</RelativeLayout>
也可直接在Activity中引用:
public class RecyclerActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.recycler_fragment);
FragmentManager fm = getSupportFragmentManager();
Fragment recyclerFragment = fm.findFragmentById(R.id.recycler_fragment);
if (recyclerFragment == null) {
recyclerFragment = RecyclerFragment.newInstance();
fm.beginTransaction()
.replace(R.id.recycler_fragment, recyclerFragment)
.commit();
}
Toolbar toolBar = (Toolbar) findViewById(R.id.recycler_tool_bar);
setSupportActionBar(toolBar);
if (getSupportActionBar() != null) {
getSupportActionBar().setTitle(R.string.recycler_name);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
}
}
颜色:
<color name="colorPrimary">#3BB894</color>
<color name="colorPrimaryDark">#2e7d32</color>
<color name="colorAccent">#8BC34A</color>
<color name="spruceViewColor">#4bc495</color>
<color name="white">#FFFFFF</color>
<color name="black">#000000</color>
<color name="lighter_gray">#DDDDDD</color>
<color name="darker_gray">#939393</color>
<color name="recycler_background">#F8F8F9</color>
<color name="fake_paragraphs">#D9E1E2</color>
<color name="square_background">#DBE9F9</color>