效果展示:

话不多说,先上效果图:



 看完了效果,我们来分析一下如何实现,并且实现这个我们能学到什么。

如何实现:

   仿照腾讯漫画的效果,实现toast从顶部出现,又从顶部消失,代码逻辑比较简单。只需要用到Android的补间动画。另外需要仿照原生的调用方法,一行代码实现调用,降低开发者学习成本。

学习目的:

  主要是强调一个良好的封装和适配,在写这个控件的过程中充分理解Android补间动画,以及自定义View的使用。另外需要仿照原生的调用方法,一行代码实现调用。

代码结构:

     代码非常简单,只需要两个类,一个ToastLayout继承自RelativeLayout,是一个自定义view,动画的逻辑可以写在里面。另外一个类则是ZToast,是暴露给开发者的类,里面有静态的方法将提供给开发者使用。另外还需要一个布局文件,自定义view将会使用到layout文件。


代码以及讲解:

首先是布局文件,比较简单,不做详细说明:

<?xml version="1.0" encoding="utf-8"?>                        

ToastLayout:

package com.zhhr.custom;import android.content.Context;import android.util.AttributeSet;import android.view.LayoutInflater;import android.view.View;import android.view.animation.Animation;import android.view.animation.AnimationSet;import android.view.animation.TranslateAnimation;import android.widget.ImageView;import android.widget.RelativeLayout;import android.widget.TextView;import com.zhhr.R;/** * Created by 皓然 on 2017/8/3. */public class ToastLayout extends RelativeLayout {    private static final int  ANIMATION_TIME = 200;    private TextView mContent;    private View view;    private boolean isShow;    private RelativeLayout mWrapper;    private ImageView mIcon;    private int height;    public boolean isShow() {        return isShow;    }    public ToastLayout(Context context) {        this(context, null);    }    public ToastLayout(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public ToastLayout(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        view = LayoutInflater.from(getContext()).inflate(R.layout.layout_toast, null);        addView(view);        mContent =  view.findViewById(R.id.tv_content);        mWrapper = view.findViewById(R.id.rl_toast);        mIcon = view.findViewById(R.id.iv_icon);        height = 60;    }    public void setTextColor(int color){        mContent.setTextColor(color);    }    public void setBgColor(int color){        mWrapper.setBackgroundColor(color);    }    public void setIconVisible(boolean isShow){       if(isShow){           mIcon.setVisibility(View.VISIBLE);       }else {           mIcon.setVisibility(View.GONE);       }    }    public void setIcon(int resId){        mIcon.setImageResource(resId);    }    public void setHeight(int height) {        this.height = height;    }    public void setContent(String content){        if(mContent!=null){            mContent.setText(content);        }    }    public void showToast(long time){        AnimationSet animationSet = new AnimationSet(true);        TranslateAnimation trans1 = new TranslateAnimation(0, 0 ,-dip2px(getContext(),height) ,0);        TranslateAnimation trans2 = new TranslateAnimation(0,0 , 0 , -dip2px(getContext(),height));        trans1.setDuration(ANIMATION_TIME);        trans2.setStartOffset(ANIMATION_TIME+time);        trans2.setDuration(ANIMATION_TIME);        animationSet.addAnimation(trans1);        animationSet.addAnimation(trans2);        this.startAnimation(animationSet);        animationSet.setAnimationListener(new Animation.AnimationListener() {            @Override            public void onAnimationStart(Animation animation) {                isShow = true;                ToastLayout.this.setVisibility(View.VISIBLE);            }            @Override            public void onAnimationEnd(Animation animation) {                isShow = false;                ToastLayout.this.setVisibility(View.GONE);            }            @Override            public void onAnimationRepeat(Animation animation) {            }        });    }    /**     * 将dip或dp值转换为px值,保证尺寸大小不变     * @param context     * @param dipValue     * @return     */    public static int dip2px(Context context, float dipValue) {        float density = context.getResources().getDisplayMetrics().density;        return (int) (dipValue * density + 0.5f);    }}

主要在showToast方法里写了两个动画,这里用到了Android的补间动画,详细的说明可以参考博客Android开发——View动画、帧动画和属性动画详解,这里使用的是位移动画TranslationAnimation,分别设置了进入动画trans1和退出动画trans2,再通过动画的持续时间来控制toast的弹出和退出。

ZToast:

package com.zhhr.custom;import android.app.Activity;import android.view.ViewGroup;import android.widget.RelativeLayout;import com.zhhr.R;/** * Created by zhhr on 2018/3/27. */public class ZToast {    private Activity mActivity;    private RelativeLayout mToastLayout;    private ToastLayout mToast;    private ViewGroup mView;    private String text;    private long times;    private static ZToast mToastInstance;    /**     * 固定参数     */    public static final long LENGTH_LONG = 3000;    public static final long LENGTH_SHORT = 1000;    /**     * 静态可设置参数     */    public static int TextColor;    public static int BgColor;    public static boolean isShowIcon = true;    public static int height = 60;    public static int resId;    /**     * 设置小图标     * @param resId     */    public static void setResId(int resId) {        ZToast.resId = resId;    }    /**     * 设置高度     * @param height     */    public static void setHeight(int height) {        ZToast.height = height;    }    /**     * 图标是否显示     * @param isShowIcon     */    public static void setIsShowIcon(boolean isShowIcon) {        ZToast.isShowIcon = isShowIcon;    }    /**     * 背景色     * @param bgColor     */    public static void setBgColor(int bgColor) {        BgColor = bgColor;    }    /**     * 文字颜色     * @param textColor     */    public static void setTextColor(int textColor) {        TextColor = textColor;    }    /**     * 初始化     * @param BgColor 背景颜色     * @param TextColor 文字颜色     * @param isIcon 图标是否显示     * @param resId 图标     * @param height 高度     */    public static void init(int BgColor, int TextColor, boolean isIcon,int resId,int height){        ZToast.BgColor = BgColor;        ZToast.TextColor = TextColor;        ZToast.isShowIcon = isIcon;        ZToast.height = height;        ZToast.resId = resId;    }    /**     * 构造函数,上下文为activity     * @param mActivity     * @param text     * @param times     */    public ZToast(Activity mActivity, String text, long times){        this.mActivity = mActivity;        this.text = text;        this.times = times;    }    /**     * 构造函数,上下文为View     * @param mView     * @param text     * @param times     */    public ZToast(ViewGroup mView, String text, long times){        this.mView = mView;        this.text = text;        this.times = times;    }    /**     * 调用方法,上下文为activity     * @param mActivity     * @param text     * @param times     * @return     */    public static ZToast makeText(Activity mActivity, String text, long times){        mToastInstance = new ZToast(mActivity,text,times);        return mToastInstance;    }    /**     * 调用方法,上下文为view     * @param mView     * @param text     * @param times     * @return     */    public static ZToast makeText(ViewGroup mView, String text, long times){        mToastInstance = new ZToast(mView,text,times);        return mToastInstance;    }    /**     * 展示     */    public void show(){        if(mActivity!=null){            mToastLayout = (RelativeLayout) mActivity.findViewById(R.id.rl_toast);            if(mToastLayout==null){//判断是否已经添加进母VIEW里,没有则添加进去                mToast = new ToastLayout(mActivity);                initToast(mToast);                mActivity.addContentView(mToast,new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ToastLayout.dip2px(mActivity,height)));            }else{//如果有,则直接取出                mToast = (ToastLayout) mToastLayout.getParent();            }            mToast.setContent(text);            mToast.showToast(times);            return;        }else if(mView!=null){            mToastLayout = (RelativeLayout) mView.findViewById(R.id.rl_toast);            if(mToastLayout==null){                mToast = new ToastLayout(mView.getContext());                initToast(mToast);                mView.addView(mToast,new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ToastLayout.dip2px(mView.getContext(),height)));            }else{                mToast = (ToastLayout) mToastLayout.getParent();            }            mToast.setContent(text);            mToast.showToast(times);        }    }    /**     * 设置各个参数     * @param mToast     */    private void initToast(ToastLayout mToast) {        if(TextColor!=0){            mToast.setTextColor(TextColor);        }        if(BgColor!=0){            mToast.setBgColor(BgColor);        }        if(resId!=0){            mToast.setIcon(resId);        }        mToast.setIconVisible(isShowIcon);        mToast.setHeight(height);    }    private boolean isShowToast(){        if(mToast == null){            return false;        }        return  mToast.isShow();    }    /**     * 是否在展示     * @return     */    public static boolean isShow(){        if(mToastInstance == null){            return false;        }else{            boolean isShow = mToastInstance.isShowToast();            mToastInstance = null;            return isShow;        }    }}

     这个类主要是做了一些基本的封装,我们要基本仿照原生toast的写法,降低开发者的学习成本,所以采用ZToast.makeText(MainActivity.this,"文字",ZToast.LENGTH_SHORT).show(); 这样的方法来进行实现。首先判断上下文是activity还是自定义view,这里提供了两套构造方法。如果是activity,则通过addContentView()的方法把我们刚刚写完的自定义view添加进activity里;如果是view,则通过addview()方法把自定义view添加进去,再调用时候自定义view的showToast()方法来进行动画的播放。

     还可以通过init方法和各种set方法来手动设置自定义view的属性。

实现:

显示toast

在activity中使用

ZToast.makeText(MainActivity.this,"文字",ZToast.LENGTH_SHORT).show();

在fragment中使用

ZToast.makeText(getActivity(), "文字",1000).show();

在自定义View中使用

ZToast.makeText((ViewGroup) getParent(),"文字"",1000).show();

设置toast的各个参数

在调用makeText方法之前调用init方法来设置参数ZToast.init(Color.parseColor("#000000"),Color.parseColor("#ff00ff"),true,R.mipmap.item_pasue,90);//参数为 背景色 文字颜色 是否有图标 图标资源 高度//也可以单独设置参数,如高度ZToast.setHeight(200);//最后调用toast方法ZToast.makeText(MainActivity.this,"点击事件",ZToast.LENGTH_SHORT).show();

判断是否正在显示toast

ZToast.isShow()当isShow()为true时,则说明正在显示中,可以用来做双击退出

点击两下back按键退出可以这样写:

代码如下:public boolean onKeyDown(int keyCode, KeyEvent event) {    if((keyCode == KeyEvent.KEYCODE_BACK)){        if(ZToast.isShow()){            return super.onKeyDown(keyCode, event);        }else{            ZToast.makeText(MainActivity.this,"再按一次返回键退出",1000).show();            return false;        }    }else{        return super.onKeyDown(keyCode, event);    }}

PS:推荐使用无actionbar的主题和设置statusbar颜色

强烈建议搭配无actionbar的主题来使用在style.xml中:最好再设置一下statusbar的颜色在activity中:Window window = getWindow();    window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);    window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN            | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);    window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);    window.setStatusBarColor(Color.TRANSPARENT);

总结:

    自定义view的使用已经仿照原生控件的封装方式,极大的简化了我们代码,为项目中今后所有需要用到toast的地方都提供了完整的一套方案。掌握的并不是说代码的技术含量,而是一种封装的思路。

  完整的DEMO代码已经提交到GitHub和Jcenter。GITHUB地址:ZToastDemo

   安装方法:

    compile 'com.zhhr:ztoast:1.0.0'

更多相关文章

  1. [Android]用架构师角度看插件化(2)-Replugin 唯一hook点
  2. android listview为什么会执行很多次,频繁调用getview
  3. Android绘图机制(一)——自定义View的基础属性和方法
  4. Android中使用SAX对XMl文件进行解析
  5. Android仿搜狗浏览器加载动画
  6. [置顶] Android中调用系统相机、系统相册来获取图片,并裁剪图片。
  7. Android优雅地处理按钮重复点击
  8. Android(安卓)ContentProvider数据共享全解析
  9. # Android的按键消息分发机制

随机推荐

  1. Android中main.xml界面参数笔记
  2. Linux下Android(安卓)SDK中adb找不到的解
  3. Android(安卓)蓝牙开发(九)A2DP基本功能
  4. Android(安卓)SDK下载和更新失败的解决方
  5. ScrollView拉到尽头时出现阴影的解决方法
  6. Android(安卓)访问Webservice接口,参数对
  7. Android(安卓)导入项目时遇到的JNI和NDK
  8. android 2.3 wifi (二)
  9. Android(安卓)Camera对焦相关
  10. android从sdcard加载.9.png图片