摘要:之前實現過可簽到的日歷控件的功能,跟這篇一樣都是實現簽到打卡功能,這篇實現的是按月進行打卡做標識,本篇內容實現的按周進行簽到打卡。實現簽到規則如下連續簽到天,即可獲得額外積分獎勵。
之前實現過《Android可簽到的日歷控件》的功能,跟這篇一樣都是實現簽到打卡功能,這篇實現的是按月進行打卡做標識,本篇內容實現的按周進行簽到打卡。
實現簽到規則如下:
1、連續簽到7天,即可獲得額外積分獎勵。
2、連續簽到記錄在第8天開始時將清零重新計算。
3、如果中斷簽到,連續簽到記錄也將清零。
實現步驟:
1.效果圖 2.自定義簽到打卡View 3.主程序邏輯處理 4.主界面 5.簽到bean 6.總結
實現過程:
1.效果圖
2.自定義簽到打卡View
/** * description: 自定義簽到View. */ public class StepsView extends View { /** * 動畫執行的時間 230毫秒 */ private final static int ANIMATION_TIME = 230; /** * 動畫執行的間隔次數 */ private final static int ANIMATION_INTERVAL = 10; /** * 線段的高度 */ private float mCompletedLineHeight = CalcUtils.dp2px(getContext(), 2f); /** * 圖標寬度 */ private float mIconWidth = CalcUtils.dp2px(getContext(), 21.5f); /** * 圖標的高度 */ private float mIconHeight = CalcUtils.dp2px(getContext(), 24f); /** * UP寬度 */ private float mUpWidth = CalcUtils.dp2px(getContext(), 20.5f); /** * up的高度 */ private float mUpHeight = CalcUtils.dp2px(getContext(), 12f); /** * 線段長度 */ private float mLineWidth = CalcUtils.dp2px(getContext(), 25f); /** * 已經完成的圖標 */ private Drawable mCompleteIcon; /** * 正在進行的圖標 */ private Drawable mAttentionIcon; /** * 默認的圖標 */ private Drawable mDefaultIcon; /** * UP圖標 */ private Drawable mUpIcon; /** * 圖標中心點Y */ private float mCenterY; /** * 線段的左上方的Y */ private float mLeftY; /** * 線段的右下方的Y */ private float mRightY; /** * 數據源 */ private ListmStepBeanList; private int mStepNum = 0; /** * 圖標中心點位置 */ private List mCircleCenterPointPositionList; /** * 未完成的線段Paint */ private Paint mUnCompletedPaint; /** * 完成的線段paint */ private Paint mCompletedPaint; /** * 未完成顏色 */ private int mUnCompletedLineColor = ContextCompat.getColor(getContext(), R.color.c_d5a872); /** * 積分顏色 */ private int mUnCompletedTextColor = ContextCompat.getColor(getContext(), R.color.c_cccccc); /** * 天數顏色 */ private int mUnCompletedDayTextColor = ContextCompat.getColor(getContext(), R.color.c_736657); /** * up魅力值顏色 */ private int mCurrentTextColor = ContextCompat.getColor(getContext(), R.color.c_white); /** * 完成的顏色 */ private int mCompletedLineColor = ContextCompat.getColor(getContext(), R.color.c_d5a872); private Paint mTextNumberPaint; private Paint mTextDayPaint; /** * 是否執行動畫 */ private boolean isAnimation = false; /** * 記錄重繪次數 */ private int mCount = 0; /** * 執行動畫線段每次繪制的長度,線段的總長度除以總共執行的時間乘以每次執行的間隔時間 */ private float mAnimationWidth = (mLineWidth / ANIMATION_TIME) * ANIMATION_INTERVAL; /** * 執行動畫的位置 */ private int mPosition; private int[] mMax; public StepsView(Context context) { this(context, null); } public StepsView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public StepsView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } /** * init */ private void init() { mStepBeanList = new ArrayList<>(); mCircleCenterPointPositionList = new ArrayList<>(); //未完成文字畫筆 mUnCompletedPaint = new Paint(); mUnCompletedPaint.setAntiAlias(true); mUnCompletedPaint.setColor(mUnCompletedLineColor); mUnCompletedPaint.setStrokeWidth(2); mUnCompletedPaint.setStyle(Paint.Style.FILL); //已完成畫筆文字 mCompletedPaint = new Paint(); mCompletedPaint.setAntiAlias(true); mCompletedPaint.setColor(mCompletedLineColor); mCompletedPaint.setStrokeWidth(2); mCompletedPaint.setStyle(Paint.Style.FILL); //number paint mTextNumberPaint = new Paint(); mTextNumberPaint.setAntiAlias(true); mTextNumberPaint.setColor(mUnCompletedTextColor); mTextNumberPaint.setStyle(Paint.Style.FILL); mTextNumberPaint.setTextSize(CalcUtils.sp2px(getContext(), 10f)); //number paint mTextDayPaint = new Paint(); mTextDayPaint.setAntiAlias(true); mTextDayPaint.setColor(mUnCompletedDayTextColor); mTextDayPaint.setStyle(Paint.Style.FILL); mTextDayPaint.setTextSize(CalcUtils.sp2px(getContext(), 12f)); //已經完成的icon mCompleteIcon = ContextCompat.getDrawable(getContext(), R.drawable.sign); //正在進行的icon mAttentionIcon = ContextCompat.getDrawable(getContext(), R.drawable.unsign); //未完成的icon mDefaultIcon = ContextCompat.getDrawable(getContext(), R.drawable.unsign); //UP的icon mUpIcon = ContextCompat.getDrawable(getContext(), R.drawable.jifendikuai); } @Override protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.getSize(heightMeasureSpec)); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); setChange(); } private void setChange() { //圖標的中中心Y點 mCenterY = CalcUtils.dp2px(getContext(), 28f) + mIconHeight / 2; //獲取左上方Y的位置,獲取該點的意義是為了方便畫矩形左上的Y位置 mLeftY = mCenterY - (mCompletedLineHeight / 2); //獲取右下方Y的位置,獲取該點的意義是為了方便畫矩形右下的Y位置 mRightY = mCenterY + mCompletedLineHeight / 2; //計算圖標中心點 mCircleCenterPointPositionList.clear(); //第一個點距離父控件左邊14.5dp float size = mIconWidth / 2 + CalcUtils.dp2px(getContext(), 23f); mCircleCenterPointPositionList.add(size); for (int i = 1; i < mStepNum; i++) { //從第二個點開始,每個點距離上一個點為圖標的寬度加上線段的23dp的長度 size = size + mIconWidth + mLineWidth; mCircleCenterPointPositionList.add(size); } } @SuppressLint("DrawAllocation") @Override protected synchronized void onDraw(Canvas canvas) { super.onDraw(canvas); if (mStepBeanList.size() != 0) { if (isAnimation) { drawSign(canvas); } else { drawUnSign(canvas); } } } /** * 繪制簽到(伴隨簽到動畫) */ @SuppressLint("DrawAllocation") private void drawSign(Canvas canvas) { for (int i = 0; i < mCircleCenterPointPositionList.size(); i++) { //繪制線段 float preComplectedXPosition = mCircleCenterPointPositionList.get(i) + mIconWidth / 2; if (i != mCircleCenterPointPositionList.size() - 1) { //最后一條不需要繪制 if (mStepBeanList.get(i + 1).getState() == StepBean.STEP_COMPLETED) { //下一個是已完成,當前才需要繪制 canvas.drawRect(preComplectedXPosition, mLeftY, preComplectedXPosition + mLineWidth, mRightY, mCompletedPaint); } else { //其余繪制灰色 //當前位置執行動畫 if (i == mPosition - 1) { //綠色開始繪制的地方, float endX = preComplectedXPosition + mAnimationWidth * (mCount / ANIMATION_INTERVAL); //繪制 canvas.drawRect(preComplectedXPosition, mLeftY, endX, mRightY, mCompletedPaint); //繪制 canvas.drawRect(endX, mLeftY, preComplectedXPosition + mLineWidth, mRightY, mUnCompletedPaint); } else { canvas.drawRect(preComplectedXPosition, mLeftY, preComplectedXPosition + mLineWidth, mRightY, mUnCompletedPaint); } } } //繪制圖標 float currentComplectedXPosition = mCircleCenterPointPositionList.get(i); Rect rect = new Rect((int) (currentComplectedXPosition - mIconWidth / 2), (int) (mCenterY - mIconHeight / 2), (int) (currentComplectedXPosition + mIconWidth / 2), (int) (mCenterY + mIconHeight / 2)); StepBean stepsBean = mStepBeanList.get(i); if (i == mPosition && mCount == ANIMATION_TIME) { //當前需要繪制 mCompleteIcon.setBounds(rect); mCompleteIcon.draw(canvas); } else { if (stepsBean.getState() == StepBean.STEP_UNDO) { mDefaultIcon.setBounds(rect); mDefaultIcon.draw(canvas); } else if (stepsBean.getState() == StepBean.STEP_CURRENT) { mAttentionIcon.setBounds(rect); mAttentionIcon.draw(canvas); } else if (stepsBean.getState() == StepBean.STEP_COMPLETED) { mCompleteIcon.setBounds(rect); mCompleteIcon.draw(canvas); } } //繪制圖標 if (stepsBean.getState() == StepBean.STEP_COMPLETED || (i == mPosition && mCount == ANIMATION_TIME)) { //已經完成了或者是當前動畫完成并且需要當前位置需要改變 if (stepsBean.getNumber() != 0) { //是up的需要橙色 mTextNumberPaint.setColor(mCurrentTextColor); } else { //普通完成的顏色 mTextNumberPaint.setColor(mCompletedLineColor); } } else { //還沒簽到的,顏色均為灰色 mTextNumberPaint.setColor(mUnCompletedLineColor); } //繪制UP if (stepsBean.getNumber() != 0) { //需要UP才進行繪制 Rect rectUp = new Rect((int) (currentComplectedXPosition - mUpWidth / 2), (int) (mCenterY - mIconHeight / 2 - CalcUtils.dp2px(getContext(), 8f) - mUpHeight), (int) (currentComplectedXPosition + mUpWidth / 2), (int) (mCenterY - mIconHeight / 2 - CalcUtils.dp2px(getContext(), 1f))); mUpIcon.setBounds(rectUp); mUpIcon.draw(canvas); } //0表示不需要顯示積分,非0表示需要消失積分 if (stepsBean.getNumber() != 0) { canvas.drawText("+" + stepsBean.getNumber(), currentComplectedXPosition - CalcUtils.dp2px(getContext(), 8f), mCenterY / 2 - CalcUtils.dp2px(getContext(), 0.5f), mTextNumberPaint); } //天數文字 canvas.drawText(stepsBean.getDay(), currentComplectedXPosition - CalcUtils.dp2px(getContext(), 12f), mCenterY + CalcUtils.dp2px(getContext(), 30f), mTextDayPaint); } //記錄重繪次數 mCount = mCount + ANIMATION_INTERVAL; if (mCount <= ANIMATION_TIME) { //引起重繪 postInvalidate(); } else { //重繪完成 isAnimation = false; mCount = 0; } } /** * 繪制初始狀態的view */ @SuppressLint("DrawAllocation") private void drawUnSign(Canvas canvas) { for (int i = 0; i < mCircleCenterPointPositionList.size(); i++) { //繪制線段 float preComplectedXPosition = mCircleCenterPointPositionList.get(i) + mIconWidth / 2; if (i != mCircleCenterPointPositionList.size() - 1) { //最后一條不需要繪制 if (mStepBeanList.get(i + 1).getState() == StepBean.STEP_COMPLETED) { //下一個是已完成,當前才需要繪制 canvas.drawRect(preComplectedXPosition, mLeftY, preComplectedXPosition + mLineWidth, mRightY, mCompletedPaint); } else { //其余繪制灰色 canvas.drawRect(preComplectedXPosition, mLeftY, preComplectedXPosition + mLineWidth, mRightY, mUnCompletedPaint); } } //繪制圖標 float currentComplectedXPosition = mCircleCenterPointPositionList.get(i); Rect rect = new Rect((int) (currentComplectedXPosition - mIconWidth / 2), (int) (mCenterY - mIconHeight / 2), (int) (currentComplectedXPosition + mIconWidth / 2), (int) (mCenterY + mIconHeight / 2)); StepBean stepsBean = mStepBeanList.get(i); if (stepsBean.getState() == StepBean.STEP_UNDO) { mDefaultIcon.setBounds(rect); mDefaultIcon.draw(canvas); } else if (stepsBean.getState() == StepBean.STEP_CURRENT) { mAttentionIcon.setBounds(rect); mAttentionIcon.draw(canvas); } else if (stepsBean.getState() == StepBean.STEP_COMPLETED) { mCompleteIcon.setBounds(rect); mCompleteIcon.draw(canvas); } //繪制增加的分數數目 if (stepsBean.getState() == StepBean.STEP_COMPLETED) { //已經完成了 if (stepsBean.getNumber() != 0) { //是up的需要橙色 mTextNumberPaint.setColor(mCurrentTextColor); } else { //普通完成的顏色 mTextNumberPaint.setColor(mCompletedLineColor); } } else { //還沒簽到的,顏色均為灰色 mTextNumberPaint.setColor(mUnCompletedLineColor); } //繪制UP if (stepsBean.getNumber() != 0) { //需要UP才進行繪制 Rect rectUp = new Rect((int) (currentComplectedXPosition - mUpWidth / 2), (int) (mCenterY - mIconHeight / 2 - CalcUtils.dp2px(getContext(), 8f) - mUpHeight), (int) (currentComplectedXPosition + mUpWidth / 2), (int) (mCenterY - mIconHeight / 2 - CalcUtils.dp2px(getContext(), 1f))); mUpIcon.setBounds(rectUp); mUpIcon.draw(canvas); } //0表示不需要顯示積分,非0表示需要消失積分 if (stepsBean.getNumber() != 0) { //積分文字 canvas.drawText("+" + stepsBean.getNumber(), currentComplectedXPosition - CalcUtils.dp2px(getContext(), 8f), mCenterY / 2 - CalcUtils.dp2px(getContext(), 0.5f), mTextNumberPaint); } //天數文字 canvas.drawText(stepsBean.getDay(), currentComplectedXPosition - CalcUtils.dp2px(getContext(), 12f), mCenterY + CalcUtils.dp2px(getContext(), 30f), mTextDayPaint); } } /** * 設置流程步數 * * @param stepsBeanList 流程步數 */ public void setStepNum(List stepsBeanList) { if (stepsBeanList == null && stepsBeanList.size() == 0) { return; } mStepBeanList = stepsBeanList; mStepNum = mStepBeanList.size(); setChange();//重新繪制 //引起重繪 postInvalidate(); } /** * 執行簽到動畫 * * @param position 執行的位置 */ public void startSignAnimation(int position) { //線條從灰色變為綠色 isAnimation = true; mPosition = position; //引起重繪 postInvalidate(); } }
3.主程序邏輯處理
/** * 一周簽到規則: * 1、連續簽到7天,即可額外獲得15積分獎勵 * 2、連續簽到記錄在第8天開始時將清零重新計算 * 3、如果中斷簽到,連續簽到記錄也將清零 * * 注:可以顯示簽到的動畫,這里沒有使用動畫 * 需要動畫可以調用mStepView.startSignAnimation(int position) * position表示需要做動畫的位置 */ public class MainActivity extends AppCompatActivity { private StepsView mStepView; private RelativeLayout rl_oval; private TextView text_sign; private TextView text_lianxusign; private ArrayListmStepBeans = new ArrayList<>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); initData(); initListener(); } private void initListener() { rl_oval.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //點擊簽到按鈕,請求后臺接口數據 //模擬請求接口數據成功 requestSuccessData(); } }); } /** * 模擬請求接口數據成功后更新數據 */ private void requestSuccessData() { mStepBeans.clear();//清空初始化數據 String reponse = "{ " + " "datas": { " + " "day": 3, " + " "myPoint": 10890, " + " "signLog": { " + " "content": "每日簽到", " + " "createTime": "2019-05-29 09:42:05", " + " "familyId": "0", " + " "id": "951660", " + " "integral": "4", " + " "logType": "3", " + " "orderId": "0", " + " "type": "1", " + " "userId": "43431" " + " }, " + " "signState": true, " + " "userSingninList": [ " + " { " + " "createTime": "2019-05-27 18:04:15", " + " "day": "1", " + " "familyId": "0", " + " "id": "278904", " + " "seriesDay": "1", " + " "type": "0", " + " "userId": "43431" " + " }, " + " { " + " "createTime": "2019-05-28 09:31:02", " + " "day": "2", " + " "familyId": "0", " + " "id": "278905", " + " "seriesDay": "2", " + " "type": "0", " + " "userId": "43431" " + " }, " + " { " + " "createTime": "2019-05-29 09:42:05", " + " "day": "3", " + " "familyId": "0", " + " "id": "278907", " + " "seriesDay": "3", " + " "type": "0", " + " "userId": "43431" " + " } " + " ] " + " }, " + " "msg": "success!", " + " "ret": 0 " + "}"; //解析后臺請求數據 SignListReq signListReq = new Gson().fromJson(reponse, SignListReq.class); if (signListReq.getRet() == 0) { rl_oval.setBackgroundResource(R.drawable.lianxusign_bg); text_sign.setText("已簽到"); text_lianxusign.setVisibility(View.VISIBLE); text_lianxusign.setText("連續" + signListReq.getDatas().getDay() + "天"); setSignData(signListReq.getDatas()); } } private void initView() { mStepView = findViewById(R.id.step_view); rl_oval = findViewById(R.id.rl_oval); text_sign = findViewById(R.id.text_sign); text_lianxusign = findViewById(R.id.text_lianxusign); } private void initData() { //初始化模擬請求后臺數據 String reponse = "{ " + " "datas": { " + " "day": 2, " + " "myPoint": 10886, " + " "signLog": { " + " "content": "每日簽到", " + " "createTime": "2019-05-28 09:31:02", " + " "familyId": "0", " + " "id": "951656", " + " "integral": "9", " + " "logType": "3", " + " "orderId": "0", " + " "type": "1", " + " "userId": "43431" " + " }, " + " "signState": true, " + " "userSingninList": [ " + " { " + " "createTime": "2019-05-27 18:04:15", " + " "day": "1", " + " "familyId": "0", " + " "id": "278904", " + " "seriesDay": "1", " + " "type": "0", " + " "userId": "43431" " + " }, " + " { " + " "createTime": "2019-05-28 09:31:02", " + " "day": "2", " + " "familyId": "0", " + " "id": "278905", " + " "seriesDay": "2", " + " "type": "0", " + " "userId": "43431" " + " } " + " ] " + " }, " + " "msg": "success!", " + " "ret": 0 " + "}"; //解析后臺請求數據 SignListReq signListReq = new Gson().fromJson(reponse, SignListReq.class); if (signListReq.getRet() == 0) { setSignData(signListReq.getDatas()); } } /** * 數據處理 * * @param datas */ private void setSignData(SignListReq.DatasBean datas) { //處理已簽到的數據 //先添加已簽到的日期到集合中 if (datas.getUserSingninList().size() != 0) { for (int i = 0; i < datas.getUserSingninList().size(); i++) { //時間格式:2019-05-27 18:04:15 String createTime = datas.getUserSingninList().get(i).getCreateTime(); SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date d1 = null; try { d1 = df.parse(createTime); } catch (ParseException e) { e.printStackTrace(); } String timeString = df.format(d1); //獲取日期的月、日 String[] timeList = timeString.split(" "); String[] split = timeList[0].split("-"); String month = split[1];//月 String day = split[2];//日 //判斷是否需要顯示積分圖標,number表示-- 0為不顯示積分,非0為顯示積分 if (datas.getSignLog() != null && datas.getUserSingninList().get(i).getCreateTime().equals(datas.getSignLog().getCreateTime())) { mStepBeans.add(new StepBean(StepBean.STEP_COMPLETED, Integer.parseInt(datas.getSignLog().getIntegral()), month + "." + day)); } else { mStepBeans.add(new StepBean(StepBean.STEP_COMPLETED, 0, month + "." + day)); } } } //添加未簽到的數據,填充為最近一周數據 if (mStepBeans.size() < 7) { //獲取當前時間的月日 Calendar now = Calendar.getInstance(); int currentMonth = now.get(Calendar.MONTH) + 1;//當月 int currentDay = now.get(Calendar.DAY_OF_MONTH);//當天 String currentTime = setData(currentMonth) + "." + setData(currentDay); //后臺有簽到集合數據 if (datas.getUserSingninList().size() != 0) { String createTime = datas.getUserSingninList().get(datas.getUserSingninList().size() - 1).getCreateTime(); SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date d1 = null; try { d1 = df.parse(createTime); } catch (ParseException e) { e.printStackTrace(); } String timeString = df.format(d1); String[] timeList = timeString.split(" "); String[] split = timeList[0].split("-"); String month = split[1];//月 String day = split[2];//日 for (int i = mStepBeans.size(); i < 7; i++) { int parseInt = Integer.parseInt(day) + i - 1; //判斷累積的天數是否超過當月的總天數 if (parseInt <= getDayOfMonth()) { String time = setData(Integer.parseInt(month)) + "." + setData(parseInt); if (currentTime.equals(time)) { mStepBeans.add(new StepBean(StepBean.STEP_CURRENT, 0, time)); } else { mStepBeans.add(new StepBean(StepBean.STEP_UNDO, 0, time)); } } else { String time = setData((Integer.parseInt(month) + 1)) + "." + setData(parseInt - getDayOfMonth()); if (currentTime.equals(time)) { mStepBeans.add(new StepBean(StepBean.STEP_CURRENT, 0, time)); } else { mStepBeans.add(new StepBean(StepBean.STEP_UNDO, 0, time)); } } } } else {//后臺沒有簽到集合數據,沒有的話從當天時間開始添加未來一周的日期數據 for (int i = 0; i < 7; i++) { int parseInt = currentDay + i; //判斷累積的天數是否超過當月的總天數 if (parseInt <= getDayOfMonth()) { String time = setData(currentMonth) + "." + setData(parseInt); if (currentTime.equals(time)) { mStepBeans.add(new StepBean(StepBean.STEP_CURRENT, 0, time)); } else { mStepBeans.add(new StepBean(StepBean.STEP_UNDO, 0, time)); } } else { String time = setData((currentMonth + 1)) + "." + setData(parseInt - getDayOfMonth()); if (currentTime.equals(time)) { mStepBeans.add(new StepBean(StepBean.STEP_CURRENT, 0, time)); } else { mStepBeans.add(new StepBean(StepBean.STEP_UNDO, 0, time)); } } } } } mStepView.setStepNum(mStepBeans); } /** * 獲取最大天數 * * @return */ public int getDayOfMonth() { Calendar aCalendar = Calendar.getInstance(Locale.CHINA); int day = aCalendar.getActualMaximum(Calendar.DATE); return day; } /** * 日月份處理 * * @param day * @return */ public String setData(int day) { String time = ""; if (day < 10) { time = "0" + day; } else { time = "" + day; } return time; } }
4.主界面布局文件
5.簽到bean
package com.sorgs.stepview.bean; /** * description: 簽到bean. */ public class StepBean { /** * 未完成 */ public static final int STEP_UNDO = -1; /** * 正在進行 */ public static final int STEP_CURRENT = 0; /** * 已完成 */ public static final int STEP_COMPLETED = 1; private int state; private int number;//0為不顯示積分,非0為顯示積分 private String day; public StepBean(int state, int number, String day) { this.state = state; this.number = number; this.day = day; } public int getNumber() { return number; } public void setNumber(int number) { this.number = number; } public int getState() { return state; } public void setState(int state) { this.state = state; } public String getDay() { return day; } public void setDay(String day) { this.day = day; } }
6.總結
該篇的功能是根據需求進行功能的處理,自定義View是實現了簽到時的動畫效果的,不過我們的需求不需要動畫,所以這里就沒調用演示,需要的可以自行調用
需要Demo源碼的童鞋可以在底部的公眾號回復:"StepView"即可獲取。
以下是個人公眾號(longxuanzhigu),之后發布的文章會同步到該公眾號,方便交流學習Android知識及分享個人愛好文章:
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/77755.html
摘要:說明群機器人是釘釘群的高級擴展功能。目前,大部分機器人在添加后,還需要進行配置,才可正常使用配置說明詳見操作流程中的幫助鏈接。安裝配置在使用本擴展之前,你需要去群機器人獲取相關信息。 說明 群機器人是釘釘群的高級擴展功能。群機器人可以將第三方服務的信息聚合到群聊中,實現自動化的信息同步。目前,大部分機器人在添加后,還需要進行Webhook配置,才可正常使用(配置說明詳見操作流程中的幫助...
摘要:前言之前我寫過一篇如何少寫爛代碼感覺很多新人對此不太理解。今天以打卡功能為例去講解其中的奧秘。那篇文章講過代碼開發的過程中分幾種類型。增刪改的需求查的需求經過多次實際開發驗證后,發現完全是多次一舉。所以在這里更正下,取消。 showImg(https://segmentfault.com/img/bVbflEV?w=700&h=267); 前言 之前我寫過一篇如何少寫PHP 爛代碼 h...
閱讀 1914·2023-04-26 01:56
閱讀 3110·2021-11-18 10:02
閱讀 3049·2021-09-09 11:35
閱讀 1283·2021-09-03 10:28
閱讀 3407·2019-08-29 18:36
閱讀 2846·2019-08-29 17:14
閱讀 832·2019-08-29 16:10
閱讀 1616·2019-08-26 13:45