手把手教大家撸一个知乎的自定义loadingview
buxiemg
8年前
<p> </p> <p>第一,希望能帮到各位,与大家分享下知识点;</p> <p>第二,希望能从中梳理一些知识点,这也对我后期开发以及能力的提升有一些帮助。</p> <p>废话不多说,马上开始正文:</p> <p>大家都知道,在android开发中,或多或少都会使用到loading状态的view,因为网络请求延时或者彰显app的logo,都会设计对应的loading,这次我就以知乎之前的loadingview为例,帮大家讲解下,这个效果怎么实现:</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/557519f6fc31b4ec19a10e659dabc2c2.gif"></p> <p style="text-align:center">效果图</p> <p><strong>1.配置一个dialog的样式,我的loadingview是继承自DialogFragment的布局</strong></p> <pre> <code class="language-java"><- 设置透明背景,居中,而且可悬浮-> <style name="cart_dialog" parent="@android:style/Theme.Holo.Light.Dialog"> <item name="android:windowFrame">@null</item> <item name="android:windowIsFloating">true</item> <item name="android:windowIsTranslucent">true</item> <item name="android:windowNoTitle">true</item> <item name="android:background">@android:color/transparent</item> <item name="android:windowBackground">@android:color/transparent</item> <item name="android:backgroundDimEnabled">true</item> <item name="android:backgroundDimAmount">0.6</item> </style></code></pre> <p><strong>2.自定义样式需要填充的layout 比如 取名:catloading_main.xml</strong></p> <pre> <code class="language-java"><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="170dp" android:layout_height="200dp" android:background="@drawable/background" tools:context=".MainActivity"> <ImageView android:layout_centerInParent="true" android:src="@drawable/mouse" android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/mouse"/> <RelativeLayout android:layout_centerInParent="true" android:layout_width="wrap_content" android:layout_height="wrap_content"> <ImageView android:layout_centerInParent="true" android:src="@drawable/cat" android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/cat"/> <ImageView android:layout_marginLeft="3.5dp" android:layout_marginTop="12.5dp" android:src="@drawable/eyes" android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/eye_left"/> <com.roger.catloadinglibrary.EyelidView android:layout_marginLeft="3.5dp" android:layout_marginTop="12.5dp" android:src="@drawable/eyes" android:layout_width="24dp" android:layout_height="15dp" android:id="@+id/eyelid_left"/> <ImageView android:layout_marginLeft="28dp" android:layout_marginTop="12.5dp" android:src="@drawable/eyes" android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/eye_right"/> <com.roger.catloadinglibrary.EyelidView android:layout_marginLeft="28dp" android:layout_marginTop="12.5dp" android:src="@drawable/eyes" android:layout_width="24dp" android:layout_height="15dp" android:id="@+id/eyelid_right"/> </RelativeLayout> <com.roger.catloadinglibrary.GraduallyTextView android:id="@+id/graduallyTextView" android:layout_marginBottom="10dp" android:textSize="15sp" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:textColor="#ffffff" android:text="L O A D I N G ..." android:layout_width="110dp" android:layout_height="wrap_content"/> </RelativeLayout> 样式如下:</code></pre> <p style="text-align:center"><img src="https://simg.open-open.com/show/710551913b9c57558f2f927f18fe29e3.png"></p> <p style="text-align:center">猫眼图</p> <p><strong>3.自定义样式背景的shape</strong></p> <pre> <code class="language-java"><shape xmlns:android="http://schemas.android.com/apk/res/android"> <solid android:color="#5d4773"/> <corners android:radius="30px"/> <padding android:left="0dp" android:top="0dp" android:right="0dp"android:bottom="0dp" /> </shape></code></pre> <p><strong>4.自定义GraduallyTextView,主要是用于展示loading...文字的自定义view</strong></p> <pre> <code class="language-java">public class GraduallyTextView extends EditText { private CharSequence text;//自定义的文本 private int startY = 0; private float progress;//读取进度条 private boolean isLoading;//判断是否正在读取 private Paint mPaint; private int textLength;//设置文本长度 private boolean isStop = true; private float scaleX;//设置缩放比例 private int duration = 2000; private float sigleDuration; private ValueAnimator valueAnimator;//设置属性平移、缩放动画 public GraduallyTextView(Context context) { super(context); init(); } public GraduallyTextView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public GraduallyTextView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } public void init() { mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setStyle(Paint.Style.FILL); setBackground(null); setCursorVisible(false); setFocusable(false); setEnabled(false); setFocusableInTouchMode(false); //设置平移动画 valueAnimator = ValueAnimator.ofFloat(0, 100).setDuration(duration); valueAnimator.setInterpolator(new AccelerateDecelerateInterpolator()); valueAnimator.setRepeatCount(Animation.INFINITE); valueAnimator.setRepeatMode(ValueAnimator.RESTART); valueAnimator.addUpdateListener( new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { //设置监听,当动画更新的时候触发重绘 progress = (Float) animation.getAnimatedValue(); GraduallyTextView.this.invalidate(); } }); } //设置开始读取的方法 public void startLoading() { if (!isStop) { return; } textLength = getText().length(); if (TextUtils.isEmpty(getText().toString())) { return; } isLoading = true; isStop = false; text = getText(); scaleX = getTextScaleX() * 10; startY = 88; mPaint.setColor(getCurrentTextColor()); mPaint.setTextSize(getTextSize()); setMinWidth(getWidth()); setText(""); setHint(""); valueAnimator.start(); sigleDuration = 100f / textLength; } //停止loading的方法 public void stopLoading() { isLoading = false; valueAnimator.end(); valueAnimator.cancel(); isStop = true; setText(text); } //设置时长 public void setDuration(int duration) { this.duration = duration; } @Override protected void onVisibilityChanged(View changedView, int visibility) { super.onVisibilityChanged(changedView, visibility); if (!isLoading) { return; } if (visibility == View.VISIBLE) { valueAnimator.resume(); } else { valueAnimator.pause(); } } //重写ondraw方法,如果还在loading,而且进度还小于1,则让它和透明度联动 @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (!isStop) { mPaint.setAlpha(255); if (progress / sigleDuration >= 1) { canvas.drawText(String.valueOf(text), 0, (int) (progress / sigleDuration), scaleX, startY, mPaint); } mPaint.setAlpha( (int) (255 * ((progress % sigleDuration) / sigleDuration))); int lastOne = (int) (progress / sigleDuration); if (lastOne < textLength) { canvas.drawText(String.valueOf(text.charAt(lastOne)), 0, 1, scaleX + getPaint().measureText( text.subSequence(0, lastOne).toString()), startY, mPaint); } } } }</code></pre> <p><strong>5.自定义眼睛旋转的EyelidView,</strong></p> <pre> <code class="language-java">public class EyelidView extends View { private float progress; private boolean isLoading; private Paint mPaint; private boolean isStop = true; private int duration = 1000; private ValueAnimator valueAnimator; private boolean isFromFull; public EyelidView(Context context) { super(context); init(); } public EyelidView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public EyelidView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } public void init() { mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setColor(Color.BLACK); mPaint.setStyle(Paint.Style.FILL); setBackground(null); setFocusable(false); setEnabled(false); setFocusableInTouchMode(false); valueAnimator = ValueAnimator.ofFloat(0, 1).setDuration(duration); valueAnimator.setInterpolator(new AccelerateDecelerateInterpolator()); valueAnimator.setRepeatCount(Animation.INFINITE); valueAnimator.setRepeatMode(ValueAnimator.REVERSE); valueAnimator.addUpdateListener( new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { progress = (float) animation.getAnimatedValue(); invalidate(); } }); } //可以设置画笔颜色 public void setColor(int color) { mPaint.setColor(color); } //定义开始读取方法 public void startLoading() { if (!isStop) { return; } isLoading = true; isStop = false; valueAnimator.start(); } public void resetAnimator(){ valueAnimator.start(); } //停止读取方法,与生命周期绑定 public void stopLoading() { isLoading = false; valueAnimator.end(); valueAnimator.cancel(); isStop = true; } public void setDuration(int duration) { this.duration = duration; } //重写当eyeview可见状态改变时候的动画 @Override protected void onVisibilityChanged(View changedView, int visibility) { super.onVisibilityChanged(changedView, visibility); if (!isLoading) { return; } if (visibility == View.VISIBLE) { valueAnimator.resume(); } else { valueAnimator.pause(); } } public void setFromFull(boolean fromFull) { isFromFull = fromFull; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (!isStop) { float bottom = 0.0f; if (!isFromFull) { bottom = progress * getHeight(); } else { bottom = (1.0f - progress) * getHeight(); } bottom = bottom >= (getHeight() / 2) ? (getHeight() / 2) : bottom; canvas.drawRect(0, 0, getWidth(), bottom, mPaint); } } private boolean whenStop() { return (isLoading == false && progress <= 0.001f); } }</code></pre> <p><strong>6.编写,loadingview的核心类CatLoadingView</strong></p> <pre> <code class="language-java">public class CatLoadingView extends DialogFragment { public CatLoadingView() { } Animation operatingAnim, eye_left_Anim, eye_right_Anim; Dialog mDialog; View mouse, eye_left, eye_right; EyelidView eyelid_left, eyelid_right; GraduallyTextView mGraduallyTextView; @Override public Dialog onCreateDialog(Bundle savedInstanceState) { if (mDialog == null) { //以1步骤的样式创建一个dialog并填充2步骤的布局 mDialog = new Dialog(getActivity(), R.style.cart_dialog); mDialog.setContentView(R.layout.catloading_main); mDialog.setCanceledOnTouchOutside(true); mDialog.getWindow().setGravity(Gravity.CENTER); //设置旋转动画,以圆心为准点进行旋转,时长2s operatingAnim = new RotateAnimation(360f, 0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); operatingAnim.setRepeatCount(Animation.INFINITE); operatingAnim.setDuration(2000); //创建5中的左侧眼睛旋转动画 eye_left_Anim = new RotateAnimation(360f, 0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); eye_left_Anim.setRepeatCount(Animation.INFINITE); eye_left_Anim.setDuration(2000); //创建5中的右侧眼睛旋转动画 eye_right_Anim = new RotateAnimation(360f, 0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); eye_right_Anim.setRepeatCount(Animation.INFINITE); eye_right_Anim.setDuration(2000); //设置水平插值器 LinearInterpolator lin = new LinearInterpolator(); operatingAnim.setInterpolator(lin); eye_left_Anim.setInterpolator(lin); eye_right_Anim.setInterpolator(lin); View view = mDialog.getWindow().getDecorView(); mouse = view.findViewById(R.id.mouse); eye_left = view.findViewById(R.id.eye_left); eye_right = view.findViewById(R.id.eye_right); eyelid_left = (EyelidView) view.findViewById(R.id.eyelid_left); eyelid_left.setColor(Color.parseColor("#d0ced1")); eyelid_left.setFromFull(true); eyelid_right = (EyelidView) view.findViewById(R.id.eyelid_right); eyelid_right.setColor(Color.parseColor("#d0ced1")); eyelid_right.setFromFull(true); mGraduallyTextView = (GraduallyTextView) view.findViewById( R.id.graduallyTextView); operatingAnim.setAnimationListener( new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { } //加多一个重复动画,当文本走动时,让左侧和右侧眼睛也同时转动 @Override public void onAnimationRepeat(Animation animation) { eyelid_left.resetAnimator(); eyelid_right.resetAnimator(); } }); } return mDialog; } //重写onresume方法,绑定activity的生命周期 @Override public void onResume() { super.onResume(); mouse.setAnimation(operatingAnim); eye_left.setAnimation(eye_left_Anim); eye_right.setAnimation(eye_right_Anim); eyelid_left.startLoading(); eyelid_right.startLoading(); mGraduallyTextView.startLoading(); } //重写onPause方法,绑定activity的生命周期 @Override public void onPause() { super.onPause(); operatingAnim.reset(); eye_left_Anim.reset(); eye_right_Anim.reset(); mouse.clearAnimation(); eye_left.clearAnimation(); eye_right.clearAnimation(); eyelid_left.stopLoading(); eyelid_right.stopLoading(); mGraduallyTextView.stopLoading(); } //设置关闭loadingview的方法 @Override public void onDismiss(DialogInterface dialog) { super.onDismiss(dialog); mDialog = null; System.gc(); } }</code></pre> <p><strong>7.最后一步,你只需要在引用到loadingview的地方,添加</strong></p> <pre> <code class="language-java">CatLoadingView mView = new CatLoadingView(); mView.show(getSupportFragmentManager(), "");</code></pre> <p>OK,这样就可以实现,有个性的loadlingview效果了,大伙,不自己自定义一个么。</p> <p> </p> <p>来自:http://www.jianshu.com/p/f8a9cfb729f9</p> <p> </p>