Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 安卓可滑動的自定義日歷控件的實現

安卓可滑動的自定義日歷控件的實現

編輯:關於Android編程

最近用到的一個日歷控件,記錄下來造福人類, 效果如圖

\

 

布局文件

 



    

        

        

        
    

    

        

        

        

        

        

        

        
    

    

    

    



日歷 PopCalendar.class的代碼

 

 

 

public class PopCalendar extends PopupWindow implements View.OnClickListener {
    private View contentView;
    private Context mContext;
    private WindowManager windowManager;
    private GestureDetector gestureDetector = null;
    private CalendarAdapter calV = null;
    private ViewFlipper flipper = null;
    private GridView gvCalendar = null;
    private static int jumpMonth = 0; // 每次滑動,增加或減去一個月,默認為0(即顯示當前月)
    private static int jumpYear = 0; // 滑動跨越一年,則增加或者減去一年,默認為0(即當前年)
    private int yearC = 0;
    private int monthC = 0;
    private int dayC = 0;
    private String currentDate = "";
    //當前年月,顯示在日歷頂端
    private TextView currentMonthTv;
    //上個月,下個月的圖標
    private ImageView prevMonthIv;
    private ImageView nextMonthIv;

    public PopCalendar(final Activity context) {
        this.mContext = context;
        this.windowManager = context.getWindowManager();;
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-M-d");
        currentDate = sdf.format(date); // 當期日期
        yearC = Integer.parseInt(currentDate.split("-")[0]);
        monthC = Integer.parseInt(currentDate.split("-")[1]);
        dayC = Integer.parseInt(currentDate.split("-")[2]);
        jumpMonth = 0;
        jumpYear = 0;

        //設置PopWindow的屬性
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        contentView = inflater.inflate(R.layout.pop_calendar, null);
        this.setContentView(contentView);
        this.setWidth(WindowManager.LayoutParams.FILL_PARENT);
        this.setHeight(WindowManager.LayoutParams.WRAP_CONTENT);
        this.setFocusable(true);
        this.setOutsideTouchable(true);
        this.update();
        ColorDrawable dw = new ColorDrawable(0000000000);
        this.setBackgroundDrawable(dw);

        currentMonthTv = (TextView) contentView.findViewById(R.id.currentMonth);
        prevMonthIv = (ImageView) contentView.findViewById(R.id.prevMonth);
        nextMonthIv = (ImageView) contentView.findViewById(R.id.nextMonth);
        setListener();

        gestureDetector = new GestureDetector(mContext, new MyGestureListener());
        flipper = (ViewFlipper) contentView.findViewById(R.id.flipper);
        flipper.removeAllViews();
        calV = new CalendarAdapter(mContext, mContext.getResources(), jumpMonth, jumpYear, yearC, monthC, dayC);
        addGridView();
        gvCalendar.setAdapter(calV);
        flipper.addView(gvCalendar, 0);
        addTextToTopTextView(currentMonthTv);
    }

    private class MyGestureListener extends GestureDetector.SimpleOnGestureListener {
        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            if (e1.getX() - e2.getX() > 120) {
                // 像左滑動
                enterNextMonth();
                return true;
            } else if (e1.getX() - e2.getX() < -120) {
                // 向右滑動
                enterPrevMonth();
                return true;
            }
            return false;
        }
    }

    /**
     * 移動到下一個月
     *
     */
    private void enterNextMonth() {
        addGridView(); // 添加一個gridView
        jumpMonth++; // 下一個月

        calV = new CalendarAdapter(mContext, mContext.getResources(), jumpMonth, jumpYear, yearC, monthC, dayC);
        gvCalendar.setAdapter(calV);
        addTextToTopTextView(currentMonthTv); // 移動到下一月後,將當月顯示在頭標題中
        flipper.addView(gvCalendar, 1);
        flipper.setInAnimation(AnimationUtils.loadAnimation(mContext, R.anim.push_left_in));
        flipper.setOutAnimation(AnimationUtils.loadAnimation(mContext, R.anim.push_left_out));
        flipper.showNext();
        flipper.removeViewAt(0);
    }

    /**
     * 移動到上一個月
     *
     */
    private void enterPrevMonth() {
        addGridView(); // 添加一個gridView
        jumpMonth--; // 上一個月

        calV = new CalendarAdapter(mContext, mContext.getResources(), jumpMonth, jumpYear, yearC, monthC, dayC);
        gvCalendar.setAdapter(calV);
        addTextToTopTextView(currentMonthTv); // 移動到上一月後,將當月顯示在頭標題中
        flipper.addView(gvCalendar, 1);

        flipper.setInAnimation(AnimationUtils.loadAnimation(mContext, R.anim.push_right_in));
        flipper.setOutAnimation(AnimationUtils.loadAnimation(mContext, R.anim.push_right_out));
        flipper.showPrevious();
        flipper.removeViewAt(0);
    }

    /**
     * 添加頭部的年份 閏哪月等信息
     * @param view
     */
    public void addTextToTopTextView(TextView view) {
        StringBuffer textDate = new StringBuffer();
        textDate.append(calV.getShowYear()).append("年").append(calV.getShowMonth()).append("月").append("\t");
        view.setText(textDate);
    }

    private void addGridView() {
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(AbsListView.LayoutParams.MATCH_PARENT, AbsListView.LayoutParams.MATCH_PARENT);
        // 取得屏幕的寬度和高度
        Display display = windowManager.getDefaultDisplay();
        int Width = display.getWidth();
        int Height = display.getHeight();
        gvCalendar = new GridView(mContext);
        gvCalendar.setNumColumns(7);
        gvCalendar.setColumnWidth(40);
        // gridView.setStretchMode(GridView.STRETCH_COLUMN_WIDTH);
        if (Width == 720 && Height == 1280) {
            gvCalendar.setColumnWidth(40);
        }
        gvCalendar.setGravity(Gravity.CENTER_VERTICAL);
        gvCalendar.setSelector(new ColorDrawable(Color.TRANSPARENT));
        // 去除gridView邊框
        gvCalendar.setVerticalSpacing(2);
        gvCalendar.setHorizontalSpacing(2);
        gvCalendar.setOnTouchListener(new View.OnTouchListener() {
            // 將gridView中的觸摸事件回傳給gestureDetector
            public boolean onTouch(View v, MotionEvent event) {
                // TODO Auto-generated method stub
                return PopCalendar.this.gestureDetector.onTouchEvent(event);
            }
        });

        gvCalendar.setOnItemClickListener(new AdapterView.OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView arg0, View arg1, int position, long arg3) {
                // TODO Auto-generated method stub
                // 點擊任何一個item,得到這個item的日期(排除點擊的是周日到周六(點擊不響應))
                int startPosition = calV.getStartPosition();
                int endPosition = calV.getEndPosition();
                if (startPosition <= position + 7 && position <= endPosition - 7) {
                    String scheduleDay = calV.getDateByClickItem(position); // 這一天的陽歷
                    String scheduleYear = calV.getShowYear();
                    String scheduleMonth = calV.getShowMonth();
                    Toast.makeText(mContext, scheduleYear + "-" + scheduleMonth + "-" + scheduleDay, Toast.LENGTH_SHORT).show();
                }
            }
        });
        gvCalendar.setLayoutParams(params);
    }

    private void setListener() {
        prevMonthIv.setOnClickListener(this);
        nextMonthIv.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        // TODO Auto-generated method stub
        switch (v.getId()) {
            case R.id.nextMonth: // 下一個月
                enterNextMonth();
                break;
            case R.id.prevMonth: // 上一個月
                enterPrevMonth();
                break;
            default:
                break;
        }
    }

    /**
     * 顯示popWindow
     */
    public void showPopupWindow(View parent) {
        if (!this.isShowing()) {
            // 以下拉方式顯示popupwindow
            this.showAsDropDown(parent);
        } else {
            this.dismiss();
        }
    }
}

 

日歷的內容是一個GridView,可以自定義類似簽到效果的圖標

 

 



    

    



日歷的adapter

 

 

 

public class CalendarAdapter extends BaseAdapter {
    private boolean isLeapYear = false; // 是否為閏年
    private int daysOfMonth = 0; // 某月的天數
    private int dayOfWeek = 0; // 具體某一天是星期幾
    private int lastDaysOfMonth = 0; // 上一個月的總天數
    private Context context;
    private String[] dayNumber = new String[42]; // 一個gridview中的日期存入此數組中
    private SpecialCalendar sc = null;
    private Resources res = null;

    private String currentYear = "";
    private String currentMonth = "";

    private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-M-d");
    private int currentFlag = -1; // 用於標記當天

    private String showYear = ""; // 用於在頭部顯示的年份
    private String showMonth = ""; // 用於在頭部顯示的月份

    // 系統當前時間
    private String sysDate = "";
    private String sys_year = "";
    private String sys_month = "";
    private String sys_day = "";
    public CalendarAdapter() {
        Date date = new Date();
        sysDate = sdf.format(date); // 當期日期
        sys_year = sysDate.split("-")[0];
        sys_month = sysDate.split("-")[1];
        sys_day = sysDate.split("-")[2];
    }

    public CalendarAdapter(Context context, Resources rs, int jumpMonth, int jumpYear, int year_c, int month_c, int day_c) {
        this();
        this.context = context;
        sc = new SpecialCalendar();
        this.res = rs;

        int stepYear = year_c + jumpYear;
        int stepMonth = month_c + jumpMonth;
        if (stepMonth > 0) {
            // 往下一個月滑動
            if (stepMonth % 12 == 0) {
                stepYear = year_c + stepMonth / 12 - 1;
                stepMonth = 12;
            } else {
                stepYear = year_c + stepMonth / 12;
                stepMonth = stepMonth % 12;
            }
        } else {
            // 往上一個月滑動
            stepYear = year_c - 1 + stepMonth / 12;
            stepMonth = stepMonth % 12 + 12;
            if (stepMonth % 12 == 0) {

            }
        }

        currentYear = String.valueOf(stepYear); // 得到當前的年份
        currentMonth = String.valueOf(stepMonth); // 得到本月
        // (jumpMonth為滑動的次數,每滑動一次就增加一月或減一月)

        getCalendar(Integer.parseInt(currentYear), Integer.parseInt(currentMonth));

    }

    @Override
    public int getCount() {
        // TODO Auto-generated method stub
        return dayNumber.length;
    }

    @Override
    public Object getItem(int position) {
        // TODO Auto-generated method stub
        return position;
    }

    @Override
    public long getItemId(int position) {
        // TODO Auto-generated method stub
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        if (convertView == null) {
            convertView = LayoutInflater.from(context).inflate(R.layout.calendar_item, null);
        }
        TextView textView = (TextView) convertView.findViewById(R.id.tv_text);
        ImageView ivPen = (ImageView) convertView.findViewById(R.id.iv_pen);
        String d = dayNumber[position];

        SpannableString sp = new SpannableString(d);
        sp.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), 0, d.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        sp.setSpan(new RelativeSizeSpan(1.2f), 0, d.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

        textView.setText(sp);
        textView.setTextColor(Color.BLACK);// 字體設黑
        if (position % 7 == 0 || position % 7 == 6) {
            // 當前月信息顯示
            textView.setTextColor(res.getColor(R.color.green));// 周末字體設綠色
        }

        if (position >= dayOfWeek && position < daysOfMonth + dayOfWeek
                && (Integer.parseInt(sys_month) >= Integer.parseInt(currentMonth)&&Integer.parseInt(sys_year)==Integer.parseInt(currentYear)
                ||Integer.parseInt(sys_year)> Integer.parseInt(currentYear))) {
            // 當前月信息顯示
            int a[] = {2, 6, 29};//每個月不標記的天數
            for (int i = 0; i < a.length; i++) {
                if (position == a[i]+dayOfWeek-1) {
                    textView.setBackgroundColor(res.getColor(R.color.yellow));//為寫日記日期填充黃色
                    ivPen.setVisibility(View.INVISIBLE);
                    break;
                } else {
                    ivPen.setVisibility(View.VISIBLE);
                }
            }
        } else if (position < dayOfWeek || position >= daysOfMonth + dayOfWeek) {
            textView.setTextColor(res.getColor(R.color.bg_gray));
        }

        if (Integer.parseInt(sys_year)==Integer.parseInt(currentYear)
                &&Integer.parseInt(sys_month) == Integer.parseInt(currentMonth)&& currentFlag < position) {
            // 設置本月當天之後的背景
            textView.setBackgroundColor(res.getColor(R.color.bg_gray));//全部填充灰色
            ivPen.setVisibility(View.INVISIBLE);
        }

        if (currentFlag == position) {
            //設置當天的背景
            textView.setBackgroundColor(res.getColor(R.color.blue));
            textView.setTextColor(Color.WHITE);
        }
        return convertView;
    }

    // 得到某年的某月的天數且這月的第一天是星期幾
    public void getCalendar(int year, int month) {
        isLeapYear = sc.isLeapYear(year); // 是否為閏年
        daysOfMonth = sc.getDaysOfMonth(isLeapYear, month); // 某月的總天數
        dayOfWeek = sc.getWeekdayOfMonth(year, month); // 某月第一天為星期幾
        lastDaysOfMonth = sc.getDaysOfMonth(isLeapYear, month - 1); // 上一個月的總天數
        getWeek(year, month);
    }

    // 將一個月中的每一天的值添加入數組dayNuber中
    private void getWeek(int year, int month) {
        int j = 1;
        // 得到當前月的所有日程日期(這些日期需要標記)
        for (int i = 0; i < dayNumber.length; i++) {
            if (i < dayOfWeek) { // 前一個月
                int temp = lastDaysOfMonth - dayOfWeek + 1;
                dayNumber[i] = (temp + i) + "" ;
            } else if (i < daysOfMonth + dayOfWeek) { // 本月
                String day = String.valueOf(i - dayOfWeek + 1); // 得到的日期
                dayNumber[i] = i - dayOfWeek + 1 + "";
                // 對於當前月才去標記當前日期
                if (sys_year.equals(String.valueOf(year)) && sys_month.equals(String.valueOf(month)) && sys_day.equals(day)) {
                    // 標記當前日期
                    currentFlag = i;
                }
                setShowYear(String.valueOf(year));
                setShowMonth(String.valueOf(month));
            } else { // 下一個月
                dayNumber[i] = j + "";
                j++;
            }
        }
    }

    /**
     * 點擊每一個item時返回item中的日期
     * @param position
     * @return
     */
    public String getDateByClickItem(int position) {
        return dayNumber[position];
    }

    /**
     * 在點擊gridView時,得到這個月中第一天的位置
     * @return
     */
    public int getStartPosition() {
        return dayOfWeek + 7;
    }

    /**
     * 在點擊gridView時,得到這個月中最後一天的位置
     * @return
     */
    public int getEndPosition() {
        return (dayOfWeek + daysOfMonth + 7) - 1;
    }

    public String getShowYear() {
        return showYear;
    }

    public void setShowYear(String showYear) {
        this.showYear = showYear;
    }

    public String getShowMonth() {
        return showMonth;
    }

    public void setShowMonth(String showMonth) {
        this.showMonth = showMonth;
    }
}

 

在MainActivity點擊顯示日歷,可以指定PopWindow在哪一個控件的下方出現

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final Button button = (Button)findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                PopCalendar popCalendar = new PopCalendar(MainActivity.this);
                popCalendar.showPopupWindow(button);
            }
        });
    }
}

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved