美文网首页Android知识
点击悬浮按钮进行日历选择并监听日历时间数据的变化

点击悬浮按钮进行日历选择并监听日历时间数据的变化

作者: 破荒之恋 | 来源:发表于2017-06-09 19:21 被阅读183次

在Android中需要时间日历选择功能的APP不少,但是实现日历功能都比较麻烦,在这里使用一款第三方开源库快速实现日历选择功能

先在gradle中加入下面这句,刷新工程

  compile 'com.prolificinteractive:material-calendarview:1.4.2'   //日历所在的开源库
compile 'com.jakewharton:butterknife:8.4.0'   //注解使用的第三方库
compile 'com.android.support:design:25.0.0'
compile 'org.greenrobot:eventbus:3.0.0'
compile 'com.android.support.constraint:constraint-layout:1.0.2'

封装一个BaseActivity


public abstract class BaseActivity extends AppCompatActivity {
//定义一个Activity的集合,方便管理和销毁
    private List<Activity> mActivitys=new ArrayList<>();

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(getLayoutId());
        mActivitys.add(this);
        ButterKnife.bind(this);
    }

//布局让继承他的Activity去实现
    public abstract int getLayoutId();

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mActivitys.remove(this);
    }

//退出所有Activity
    public void finishAll(){
       for (Activity activity:mActivitys){
           if (activity!=null){
               activity.finish();
           }
       }
    }

//设置标题栏
    protected void setToolbar(Toolbar toolbar, String title){
        toolbar.setTitle(title);
        setSupportActionBar(toolbar);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        getSupportActionBar().setDisplayShowHomeEnabled(true);
        toolbar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                    finishAfterTransition();
                }else {
                    finish();
                }
            }
        });
    }
}

有日历时间的主界面

主界面中继承BaseActivity并且实现他的抽象方法

 
public class MainActivity extends BaseActivity implements View.OnClickListener {

    private static final String TAG = "MainActivity";
    RelativeLayout rlPrevious;
    TextView tvTime;
    RelativeLayout rlNext;
    LinearLayout linTimeBar;
    FloatingActionButton floatButton;
    FloatingActionButton floatButton2;
    private Calendar calendar;
    private int currentDay;
    private int currentMonth;
    private int currentYear;

    @Override
    public int getLayoutId() {

        Log.d(TAG, "------------getLayoutId: ------------------");
        return R.layout.activity_main;
    }

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

      rlNext= (RelativeLayout) findViewById(R.id.rl_next);
        rlPrevious = (RelativeLayout) findViewById(R.id.rl_previous);
        tvTime= (TextView) findViewById(R.id.tv_time);
        linTimeBar= (LinearLayout) findViewById(R.id.lin_time_bar);
        floatButton= (FloatingActionButton) findViewById(R.id.floatButton);
        floatButton2= (FloatingActionButton) findViewById(R.id.floatButton2);

        Log.d(TAG, "------------onCreate: ------------------");
        rlPrevious.setOnClickListener(this);
        rlNext.setOnClickListener(this);
        tvTime.setOnClickListener(this);
        floatButton.setOnClickListener(this);
        floatButton2.setOnClickListener(this);

        initTime();

        EventBus.getDefault().register(this);

    }

    @Override
    protected void onStart() {
        super.onStart();
         /* rlPrevious.setOnClickListener(this);
        rlNext.setOnClickListener(this);
        tvTime.setOnClickListener(this);
        floatButton.setOnClickListener(this);*/
        Log.d(TAG, "------------onStart: ------------------");
    }
    //获取当前时间日历
    private void initTime() {
        calendar = Calendar.getInstance();
        currentYear = calendar.get(Calendar.YEAR);
        currentMonth = calendar.get(Calendar.MONTH) + 1;
        currentDay = calendar.get(Calendar.DAY_OF_MONTH);
        Log.d(TAG, "initTime: "+currentDay+"-----"+currentMonth+"------"+currentYear);
        setTVTime();
    }
//监听日历时间的变化,并且接收传过来的数据
    @Subscribe
    public void onEventMainThread(CalendarDay date) {
        currentYear=date.getYear();
        currentMonth=date.getMonth()+1;
        currentDay=date.getDay();
        Log.d(TAG, "-------------------onEventMainThread: -------------------"+currentDay);
        setTVTime();
    }
    //设置标题时间
    private void setTVTime() {

        tvTime.setText(currentYear+"年"+currentMonth+"月"+currentDay+"日");
    }

    @Override
    public void onClick(View v) {
        Log.d(TAG, "-------onClick:------ ");
        switch(v.getId()){
            case R.id.rl_next:
                Toast.makeText(this, "下一天", Toast.LENGTH_SHORT).show();
                Log.d(TAG,"下一天");
                setNext();
                setTVTime();
                break;
            case R.id.rl_previous:
                Toast.makeText(this, "前一天", Toast.LENGTH_SHORT).show();
                setPreVious();
                setTVTime();
                Log.d(TAG,"前一天");
                break;
            case R.id.floatButton:
                Toast.makeText(this, "悬浮按钮", Toast.LENGTH_SHORT).show();
                Intent intent=new Intent(this,CalendarActivity.class);
                CircularAnimUtil.startActivity(this,intent,v,R.color.colorPrimary,500);
                //CircularAnimUtil.startActivityForResult(this,intent, 10,v, R.color.colorPrimary);
                Log.d(TAG,"悬浮按钮");
                break;
          
            case R.id.tv_time:
                Toast.makeText(this, "时间", Toast.LENGTH_SHORT).show();
                break;
        }
    }
    private void setPreVious() {
        if (currentMonth == 3) {
            currentDay--;
            if (currentDay < 1) {
                if ((currentYear % 4 == 0 && currentYear % 100 != 0) || currentYear % 400 == 0) {
                    //闰年
                    currentDay = 29;
                    currentMonth--;
                } else {
                    //平年
                    currentDay = 28;
                    currentMonth--;
                }
            }
        } else if (currentMonth == 1) {
            currentDay--;
            if (currentDay < 1) {
                currentDay = 31;
                currentMonth = 12;
                currentYear--;
            }
        } else if (currentMonth == 2 || currentMonth == 4 || currentMonth == 6 || currentMonth == 8 || currentMonth == 9 || currentMonth == 11) {
            currentDay--;
            if (currentDay < 1) {
                currentDay = 31;
                currentMonth--;
            }
        } else {
            currentDay--;
            if (currentDay < 1) {
                currentDay = 30;
                currentMonth--;
            }
        }
    }
    private void setNext() {
        if (currentMonth == 2) {
            //二月
            if ((currentYear % 4 == 0 && currentYear % 100 != 0) || currentYear % 400 == 0) {
                //闰年
                currentDay++;
                if (currentDay > 29) {
                    currentDay = 1;
                    currentMonth++;
                }
            } else {
                //平年
                currentDay++;
                if (currentDay > 28) {
                    currentDay = 1;
                    currentMonth++;
                }
            }
        } else if (currentMonth == 1 || currentMonth == 3 || currentMonth == 5 || currentMonth == 6 || currentMonth == 8 || currentMonth == 10) {
            //大月
            currentDay++;
            if (currentDay > 31) {
                currentDay = 1;
                currentMonth++;
            }
        } else if (currentMonth == 12) {
            currentDay++;
            if (currentDay > 31) {
                currentDay = 1;
                currentMonth = 1;
                currentYear++;
            }
        } else {
            //小月
            currentDay++;
            if (currentDay > 30) {
                currentDay = 1;
                currentMonth++;
            }
        }
    }
}

主界面fragment_today_in_history布局如下
<android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">


        <LinearLayout
            android:id="@+id/ll_time_bar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@android:color/holo_blue_light"
            android:gravity="center"
            android:orientation="horizontal"
            android:paddingTop="5dp"
            android:paddingBottom="10dp"
            app:layout_scrollFlags="scroll|enterAlways">

            <RelativeLayout
                android:id="@+id/rl_previous"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1">

                <ImageView
                    android:layout_width="35dp"
                    android:layout_height="35dp"
                    android:layout_centerInParent="true"
                    android:src="@drawable/ic_left"
                    android:tint="@android:color/white" />
            </RelativeLayout>


            <TextView
                android:id="@+id/tv_time"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="2"
                android:gravity="center"
                android:text="2016年10月15日"
                android:textColor="@android:color/white"
                android:textSize="20sp" />

            <RelativeLayout
                android:id="@+id/rl_next"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1">

                <ImageView
                    android:layout_width="35dp"
                    android:layout_height="35dp"
                    android:layout_centerInParent="true"
                    android:src="@drawable/ic_right"
                    android:tint="@android:color/white" />
            </RelativeLayout>
        </LinearLayout>

<android.support.design.widget.FloatingActionButton
        android:id="@+id/floatActionBtn"
        app:elevation="6dp"
        app:fabSize="normal"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|right"
        android:layout_margin="30dp"
        android:src="@drawable/ic_calender" />
    </android.support.design.widget.AppBarLayout>

效果如下:

image.png

记得初始化EventBus

     EventBus.getDefault().register(this);
点击悬浮按钮跳转到日历选择器
 Intent intent=new Intent(getActivity(),CalendarActivity.class);
 CircularAnimUtil.startActivityForResult(getActivity(),intent, Constants.CODE_CALENDAR,v, R.color.colorPrimary);
工具类CircularAnimUtil的具体代码,点击悬浮按钮使用动画出现日历选择界面
/**
 * 对 ViewAnimationUtils.createCircularReveal() 方法的封装.
 * <p/>
 * Created on 16/7/20.
 * GitHub: https://github.com/XunMengWinter
 *
 * @author ice
 */
public class CircularAnimUtil {

    public static final long PERFECT_MILLS = 618;
    public static final int MINI_RADIUS = 0;

    /**
     * 向四周伸张,直到完成显示。
     */
    @SuppressLint("NewApi")
    public static void show(View myView, float startRadius, long durationMills) {
        if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.LOLLIPOP) {
            myView.setVisibility(View.VISIBLE);
            return;
        }

        int cx = (myView.getLeft() + myView.getRight()) / 2;
        int cy = (myView.getTop() + myView.getBottom()) / 2;

        int w = myView.getWidth();
        int h = myView.getHeight();

        // 勾股定理 & 进一法
        int finalRadius = (int) Math.sqrt(w * w + h * h) + 1;

        Animator anim =
                ViewAnimationUtils.createCircularReveal(myView, cx, cy, startRadius, finalRadius);
        myView.setVisibility(View.VISIBLE);
        anim.setDuration(durationMills);
        anim.start();
    }

    /**
     * 由满向中间收缩,直到隐藏。
     */
    @SuppressLint("NewApi")
    public static void hide(final View myView, float endRadius, long durationMills) {
        if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.LOLLIPOP) {
            myView.setVisibility(View.INVISIBLE);
            return;
        }

        int cx = (myView.getLeft() + myView.getRight()) / 2;
        int cy = (myView.getTop() + myView.getBottom()) / 2;
        int w = myView.getWidth();
        int h = myView.getHeight();

        // 勾股定理 & 进一法
        int initialRadius = (int) Math.sqrt(w * w + h * h) + 1;

        Animator anim =
                ViewAnimationUtils.createCircularReveal(myView, cx, cy, initialRadius, endRadius);
        anim.setDuration(durationMills);
        anim.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                myView.setVisibility(View.INVISIBLE);
            }
        });

        anim.start();
    }

    /**
     * 从指定View开始向四周伸张(伸张颜色或图片为colorOrImageRes), 然后进入另一个Activity,
     * 返回至 @thisActivity 后显示收缩动画。
     */
    @SuppressLint("NewApi")
    public static void startActivityForResult(
            final Activity thisActivity, final Intent intent, final Integer requestCode, final Bundle bundle,
            final View triggerView, int colorOrImageRes, long durationMills) {

        if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.LOLLIPOP) {
            thisActivity.startActivity(intent);
            return;
        }

        int[] location = new int[2];
        triggerView.getLocationInWindow(location);
        final int cx = location[0] + triggerView.getWidth() / 2;
        final int cy = location[1] + triggerView.getHeight() / 2;
        final ImageView view = new ImageView(thisActivity);
        view.setScaleType(ImageView.ScaleType.CENTER_CROP);
        view.setImageResource(colorOrImageRes);
        final ViewGroup decorView = (ViewGroup) thisActivity.getWindow().getDecorView();
        int w = decorView.getWidth();
        int h = decorView.getHeight();
        decorView.addView(view, w, h);

        // 计算中心点至view边界的最大距离
        int maxW = Math.max(cx, w - cx);
        int maxH = Math.max(cy, h - cy);
        final int finalRadius = (int) Math.sqrt(maxW * maxW + maxH * maxH) + 1;
        Animator
                anim = ViewAnimationUtils.createCircularReveal(view, cx, cy, 0, finalRadius);
        int maxRadius = (int) Math.sqrt(w * w + h * h) + 1;
        // 若使用默认时长,则需要根据水波扩散的距离来计算实际时间
        if (durationMills == PERFECT_MILLS) {
            // 算出实际边距与最大边距的比率
            double rate = 1d * finalRadius / maxRadius;
            // 水波扩散的距离与扩散时间成正比
            durationMills = (long) (PERFECT_MILLS * rate);
        }
        final long finalDuration = durationMills;
        anim.setDuration(finalDuration);
        anim.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);

                if (requestCode == null)
                    thisActivity.startActivity(intent);
                else if (bundle == null)
                    thisActivity.startActivityForResult(intent, requestCode);
                else
                    thisActivity.startActivityForResult(intent, requestCode, bundle);

                // 默认渐隐过渡动画.
                thisActivity.overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);

                // 默认显示返回至当前Activity的动画.
                triggerView.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        Animator anim =
                                ViewAnimationUtils.createCircularReveal(view, cx, cy, finalRadius, 0);
                        anim.setDuration(finalDuration);
                        anim.addListener(new AnimatorListenerAdapter() {
                            @Override
                            public void onAnimationEnd(Animator animation) {
                                super.onAnimationEnd(animation);
                                try {
                                    decorView.removeView(view);
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                            }
                        });
                        anim.start();
                    }
                }, 1000);

            }
        });
        anim.start();
    }


    /*下面的方法全是重载,用简化上面方法的构建*/


    public static void startActivityForResult(
            Activity thisActivity, Intent intent, Integer requestCode, View triggerView, int colorOrImageRes) {
        startActivityForResult(thisActivity, intent, requestCode, null, triggerView, colorOrImageRes, PERFECT_MILLS);
    }

    public static void startActivity(
            Activity thisActivity, Intent intent, View triggerView, int colorOrImageRes, long durationMills) {
        startActivityForResult(thisActivity, intent, null, null, triggerView, colorOrImageRes, durationMills);
    }

    public static void startActivity(
            Activity thisActivity, Intent intent, View triggerView, int colorOrImageRes) {
        startActivity(thisActivity, intent, triggerView, colorOrImageRes, PERFECT_MILLS);
    }

    public static void startActivity(Activity thisActivity, Class<?> targetClass, View triggerView, int colorOrImageRes) {
        startActivity(thisActivity, new Intent(thisActivity, targetClass), triggerView, colorOrImageRes, PERFECT_MILLS);
    }

    public static void show(View myView) {
        show(myView, MINI_RADIUS, PERFECT_MILLS);
    }

    public static void hide(View myView) {
        hide(myView, MINI_RADIUS, PERFECT_MILLS);
    }

}

日历界面

/**
 * Created by an on 2017/6/10.
 */

class CalendarActivity extends BaseActivity{
    private Toolbar toolbar;
    private MaterialCalendarView materialCalendarView;
    private Button btOk;
    private CalendarDay mDatas;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        btOk = (Button) findViewById(R.id.btn_ok);
        materialCalendarView = (MaterialCalendarView) findViewById(R.id.calendarView);
        toolbar = (Toolbar) findViewById(R.id.toolbar);
        setToolbar();
        materialCalendarView.setOnDateChangedListener(new OnDateSelectedListener() {
            @Override
            public void onDateSelected(@NonNull MaterialCalendarView widget, @NonNull CalendarDay date, boolean selected) {
                mDatas=date;
            }
        });
        btOk.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mDatas!=null) {
                    EventBus.getDefault().post(mDatas);
                }
                finish();
            }
        });
    }
    private void setToolbar() {
        toolbar.setTitle("选择日期");
        setSupportActionBar(toolbar);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        getSupportActionBar().setDisplayShowHomeEnabled(true);
        toolbar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();
            }
        });
    }
    @Override
    public int getLayoutId() {
        return R.layout.activity_calendar;
    }
}

日历界面布局如下

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <include layout="@layout/toolbar"/>

    <com.prolificinteractive.materialcalendarview.MaterialCalendarView
        android:id="@+id/calendarView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

    <Button
        android:layout_marginTop="20dp"
        android:textColor="@android:color/white"
        android:text="确定"
        android:background="@color/colorPrimary"
        android:id="@+id/btn_ok"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</LinearLayout>
<include layout="@layout/toolbar"/>中toolbar的布局如下
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/toolbar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/titile_bg"
    android:fitsSystemWindows="true"
    app:titleTextColor="@android:color/white" />

效果图如下

image.png

选择日期之后,确定就会把所选的日期时间返回到上一级页面,只需要在那个界面做接受数据的处理就行了。

在这里使用EventBus来监听数据的变化

     compile 'org.greenrobot:eventbus:3.0.0'

在显示日期的界面中获取返回的时间数据代码如下

  @Subscribe
    public void onEventMainThread(CalendarDay date) {
        currentYear=date.getYear();
        currentMonth=date.getMonth()+1;
        currentDay=date.getDay();

        Log.d(TAG, "-------------------onEventMainThread: -------------------"+currentDay);
        setTVTime();
    }

//设置时间年月日
    public void setTVTime() {
        tvTime.setText(currentYear + "年" + currentMonth + "月" + currentDay + "日");
    }

此时日历选择功能基本结束了,不清楚的可以看看“历史的今天”这个项目。

相关文章

网友评论

    本文标题:点击悬浮按钮进行日历选择并监听日历时间数据的变化

    本文链接:https://www.haomeiwen.com/subject/uoxmfxtx.html