Android 사용자 정의 View GitHub 를 모방 한 활성 표 제출

설명 하 다.
본 고 는 Canvas,Paint,Path,Rect 등 기본 적 인 지식 이 필요 할 수 있 습 니 다.익숙 하지 않 은 학생 들 은 GcsSloop 안 드 로 이 드 사용자 정의 View 튜 토리 얼 디 렉 터 리 를 배 울 수 있 도록 권장 합 니 다.
github.jpg
위의 그림 은 github 의 제출 표 입 니 다.직관 적 으로 보면 몇 부분 으로 나 누 어 그 릴 수 있 습 니 다.
(1)각 달의 작은 칸,그리고 색 채 는 제출 횟수 에 따라 옅 은 것 에서 깊 은 것 으로 변화 한다.
(2)오른쪽 아래 에 있 는 색 표 지 는 우리 가 오른쪽 을 맞 추 면 된다.
(3)왼쪽 주,원 도 는 일요일 부터 토요일 까지,우 리 는 월요일 부터 일요일 까지.
(4)위의 달,우 리 는 1-12 월 만 그 렸 다.
(5)클릭 시 팝 업 당일 제출 상황 은 작은 삼각형 과 사각형 으로 구성 되 어 있 습 니 다.
해결 해 야 할 계산 문제:
(1)임의의 1 년 의 모든 일 을 생 성 합 니 다.년 월 일 주,제출 횟수,색상 블록 색상,좌 표를 포함 합 니 다.
(1)1 년 동안 모든 작은 격자 좌표
(2)오른쪽 아래 색 표지 좌표
(3)왼쪽 요일 좌표
(4)상 월 좌표
(5)팝 업 된 알림 상자 와 텍스트 좌 표를 클릭
년 소유 일수 생 성
매일 정 보 를 우 리 는 하나의 종류 로 포장 해 야 합 니 다.코드 는 다음 과 같 습 니 다.

/**
 * Created by Administrator on 2017/1/13.
 *        ,            
 */
public class Day implements Serializable{
 /** **/
 public int year;
 /** **/
 public int month;
 /** **/
 public int date;
 /**  **/
 public int week;
 /**    ,  0**/
 public int contribution = 0;
 /**    ,        **/
 public int colour = 0xFFEEEEEE;
 /**    ,   ,   ,      **/
 public float startX;
 public float startY;
 public float endX;
 public float endY;
 @Override
 public String toString() {
  //           
  return ""+year+" "+month+" "+date+"  "+week+","+contribution+" ";
 }
}
먼저 표를 그 리 려 면 모든 날 짜 를 계산 해 야 합 니 다.여기 서 1 년 중의 모든 날 짜 를 계산 해 야 합 니 다.우 리 는 그해 1 월 1 일부 터 12 월 31 일 까지 계산 해 야 합 니 다.주 는 연속 이기 때문에 우 리 는 특정한 해 의 1 월 1 일 을 주 몇 일 로 제공 해 야 합 니 다.예 를 들 어 2016 년 1 월 1 일 은 주 5 이 고 여기 서 필요 한 매개 변 수 는 2016 과 주 5 입 니 다.그러면 우 리 는 한 가지 유형 으로 이 방법 을 실현 해 야 합 니 다.코드 는 다음 과 같 습 니 다:

public class DateFactory {
 /**  map,       **/
 private static HashMap<Integer,Integer> monthMap = new LinkedHashMap<>(12);
 /**  map,       **/
 private static HashMap<Integer,Integer> leapMonthMap = new LinkedHashMap<>(12);
 static {
  //   map,  2    
  monthMap.put(1,31);leapMonthMap.put(1,31);
  monthMap.put(2,28);leapMonthMap.put(2,29);
  monthMap.put(3,31);leapMonthMap.put(3,31);
  monthMap.put(4,30);leapMonthMap.put(4,30);
  monthMap.put(5,31);leapMonthMap.put(5,31);
  monthMap.put(6,30);leapMonthMap.put(6,30);
  monthMap.put(7,31);leapMonthMap.put(7,31);
  monthMap.put(8,31);leapMonthMap.put(8,31);
  monthMap.put(9,30);leapMonthMap.put(9,30);
  monthMap.put(10,31);leapMonthMap.put(10,31);
  monthMap.put(11,30);leapMonthMap.put(11,30);
  monthMap.put(12,31);leapMonthMap.put(12,31);
 }
 /**
  *      1 1    
  *    366 ,   365 
  * @param year   
  * @param weekday   1 1    
  * @return   1 1  12 31      
  */
 public static List<Day> getDays(int year, int weekday) {
  List<Day> days = new ArrayList<>();
  boolean isLeapYear = isLeapYear(year);
  int dayNum = isLeapYear ? 366 : 365;
  Day day;
  int lastWeekday = weekday;
  for (int i = 1; i <= dayNum; i++) {
   day = new Day();
   day.year = year;
   //       ,    7   1
   day.week = lastWeekday<= 7 ? lastWeekday : 1;
   //         
   int[] monthAndDay = getMonthAndDay(isLeapYear, i);
   day.month = monthAndDay[0];
   day.date = monthAndDay[1];
   //         +1
   lastWeekday = day.week;
   lastWeekday++;
   days.add(day);
  }
  checkDays(days);
  return days;
 }
 /**
  *      
  * @param isLeapYear     
  * @param currentDay     
  * @return         
  */
 public static int[] getMonthAndDay(boolean isLeapYear,int currentDay) {
  HashMap<Integer,Integer> maps = isLeapYear?leapMonthMap:monthMap;
  Set<Map.Entry<Integer,Integer>> set = maps.entrySet();
  int count = 0;
  Map.Entry<Integer, Integer> month = null;
  for (Map.Entry<Integer, Integer> entry : set) {
   count+=entry.getValue();
   if (currentDay<=count){
    month = entry;
    break;
   }
  }
  if (month == null){
   throw new IllegalStateException("        ");
  }
  int day = month.getValue()-(count-currentDay);
  return new int[]{month.getKey(),day};
 }
 /**
  *          
  * @param year   
  * @return true    
  */
 public static boolean isLeapYear(int year) {
  return year % 4 == 0 && year % 100 != 0 || year % 400 == 0;
 }
 /**
  *            
  * @param days
  */
 private static void checkDays(List<Day> days) {
  if (days == null) {
   throw new IllegalArgumentException("    ");
  }
  if (days.size() != 365 && days.size() != 366) {
   throw new IllegalArgumentException("    :" + days.size());
  }
 }
 public static void main(String[] args){
  //test
  List<Day> days = DateFactory.getDays(2016, 5);
  for (int i = 0; i < days.size(); i++) {
   System.out.println(days.get(i).toString());
  }
 }
}
구체 적 인 계산 논 리 는 코드 를 볼 수 있다.그리 어렵 지 않다.그러면 우 리 는 어느 해 의 모든 날 을 얻 을 수 있다.
일수 칸 그리 기
이 view 는 비교적 길 기 때문에 가로 화면 표시 가 필요 합 니 다.편리 하 게 볼 수 있 습 니 다.여기 서 저 희 는 view 의 측정 계산 도 하지 않 고 사용자 정의 속성 도 하지 않 으 며 핵심 논리 에 만 관심 을 가지 면 됩 니 다.
우선 필요 한 구성원 변 수 를 정의 해 야 합 니 다.

 /**         **/
 private final static int DEFAULT_BOX_COLOUR = 0xFFEEEEEE;
 /**       **/
 private final static int[] COLOUR_LEVEL =
   new int[]{0xFF1E6823, 0xFF44A340, 0xFF8CC665, 0xFFD6E685, DEFAULT_BOX_COLOUR};
 /**  **/
 private String[] weeks = new String[]{"Mon", "Wed", "Fri", "Sun"};
 /**  **/
 private String[] months =
   new String[]{"Jan", "Feb", "Mar", "Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
 /**   padding,         **/
 private int padding = 24;
 /**        **/
 private int boxSide = 8;
 /**         **/
 private int boxInterval = 2;
 /**      **/
 private int column = 0;
 private List<Day> mDays;//       
 private Paint boxPaint;//    
 private Paint textPaint;//    
 private Paint infoPaint;//     
 private Paint.FontMetrics metrics;//    
 private float downX;//     X  
 private float downY;//     Y  
 private Day clickDay;//       
이 추출 변 수 는 천천히 증가 합 니 다.사용자 정의 할 때 생각 이 불완전 할 때 먼저 쓰 고 일부 변 수 를 사용 할 때 추출 할 수 있 습 니 다.
그리고 데 이 터 를 초기 화 합 니 다.

public GitHubContributionView(Context context, AttributeSet attrs, int defStyleAttr) {
  super(context, attrs, defStyleAttr);
  initView();
 }
 public void initView() {
  mDays = DateFactory.getDays(2016, 5);
  //    
  boxPaint = new Paint();
  boxPaint.setStyle(Paint.Style.FILL);
  boxPaint.setStrokeWidth(2);
  boxPaint.setColor(DEFAULT_BOX_COLOUR);
  boxPaint.setAntiAlias(true);
  //    
  textPaint = new Paint();
  textPaint.setStyle(Paint.Style.FILL);
  textPaint.setColor(Color.GRAY);
  textPaint.setTextSize(12);
  textPaint.setAntiAlias(true);
  //         
  infoPaint = new Paint();
  infoPaint.setStyle(Paint.Style.FILL);
  infoPaint.setColor(0xCC888888);
  infoPaint.setTextSize(12);
  infoPaint.setAntiAlias(true);
  //      px
  padding = UI.dp2px(getContext(), padding);
  boxSide = UI.dp2px(getContext(), boxSide);
  metrics = textPaint.getFontMetrics();
 }
여기 서 2016 년 에 예 를 들 어 mDays 는 2016 년 의 모든 날 의 집합 을 가 져 오 는 것 입 니 다.(매개 변 수 는 사용자 정의 속성 으로 추출 할 수 있 습 니 다)관련 Paint 도 초기 화 되 었 습 니 다.그 다음 에 onDraw 방법 에 그 려 야 합 니 다.먼저 모든 격자 와 월 표 지 를 그 려 야 합 니 다.

 /**
  *   1-12           
  * @param canvas   
  */
 private void drawBox(Canvas canvas) {
  //         
  float startX, startY, endX, endY;
  //     1 
  int month = 1;
  for (int i = 0; i < mDays.size(); i++) {
   Day day = mDays.get(i);
   if (i == 0){
    // 1      ,     x=padding,y=padding-boxSide/2(  ),y         
    canvas.drawText(months[0],padding,padding-boxSide/2,textPaint);
   }
   if (day.week == 1 && i != 0) {
    //      1,         
    column++;
    //          ,         
    if (day.month>month){
     month = day.month;
     //         ,x     , y       ,boxSide/2(  )
     canvas.drawText(months[month-1],padding+column*(boxSide+boxInterval),padding-boxSide/2,textPaint);
    }
   }
   //       ,x           ,y           
   startX = padding + column * (boxSide + boxInterval);
   startY = padding + (day.week - 1) * (boxSide + boxInterval);
   endX = startX + boxSide;
   endY = startY + boxSide;
   //           ,                   
   day.startX = startX;
   day.startY = startY;
   day.endX = endX;
   day.endY = endY;
   //           
   boxPaint.setColor(day.colour);
   canvas.drawRect(startX, startY, endX, endY, boxPaint);
  }
  boxPaint.setColor(DEFAULT_BOX_COLOUR);//      
 }
여 기 는 주로 하행 수열 수의 변화 와 월 좌표 의 계산 에 주의 하고 칸 을 그 렸 다.
요일 텍스트 그리 기
우 리 는 왼쪽 요일 텍스트 를 다시 그립 니 다.

/**
  *       
  * @param canvas   
  */
 private void drawWeek(Canvas canvas) {
  //      ,        
  float textLength = 0;
  for (String week : weeks) {
   float tempLength = textPaint.measureText(week);
   if (textLength < tempLength) {
    textLength = tempLength;
   }
  }
  //        ,   x=padding-    -        ,y       
  canvas.drawText(weeks[0], padding - textLength - 2, padding + boxSide - metrics.descent, textPaint);
  canvas.drawText(weeks[1], padding - textLength - 2, padding + 3 * (boxSide + boxInterval) - metrics.descent, textPaint);
  canvas.drawText(weeks[2], padding - textLength - 2, padding + 5 * (boxSide + boxInterval) - metrics.descent, textPaint);
  canvas.drawText(weeks[3], padding - textLength - 2, padding + 7 * (boxSide + boxInterval) - metrics.descent, textPaint);
 }
색상 깊이 표시
그리고 표 의 높이 에 따라 오른쪽 아래 의 색 깊이 표 지 를 그립 니 다.

/**
  *             ,                
  * @param canvas   
  */
 private void drawTag(Canvas canvas) {
  //            
  float moreLength = textPaint.measureText("More");
  float lessLength = textPaint.measureText("Less");
  //  More   ,x  =padding+(  +1)*(    +    )-      -    
  float moreX = padding + (column + 1) * (boxSide + boxInterval) - boxInterval - moreLength;
  //y  =padding+(    +1,         )*(    +    )+   ascent  
  float moreY = padding + 8 * (boxSide + boxInterval) + Math.abs(metrics.ascent);
  canvas.drawText("More", moreX, moreY, textPaint);
  //     ,       More        
  float interval = boxSide - 2;//         
  float leftX = moreX - interval - boxSide;
  float topY = moreY - boxSide;
  float rightX = moreX - interval;
  float bottomY = moreY;//   Y      
  for (int i = 0; i < COLOUR_LEVEL.length; i++) {
   boxPaint.setColor(COLOUR_LEVEL[i]);
   canvas.drawRect(leftX - i * (boxSide + boxInterval), topY, rightX - i * (boxSide + boxInterval), bottomY, boxPaint);
  }
  //    Less   ,    
  canvas.drawText("Less", leftX - 4 * (boxSide + boxInterval) - interval - lessLength, moreY, textPaint);
 }
이렇게 해서 전체 표 의 주 체 를 그립 니 다.
클릭 이벤트 처리
다음은 클릭 이 벤트 를 처리 하고 클릭 한 좌표 가 격자 안에 있 으 면 텍스트 상자 가 팝 업 됩 니 다.먼저 클릭 이 벤트 를 처리 합 니 다.

 @Override
 public boolean onTouchEvent(MotionEvent event) {
  //  ACTION_DOWN   ,        ,   ・
  if (MotionEvent.ACTION_DOWN == event.getAction()) {
   downX = event.getX();
   downY = event.getY();
   findClickBox();
  }
  //             ,              
  return super.onTouchEvent(event);
 }
격자 안에 있 는 지 판단 하기:

 /**
  *           
  */
 private void findClickBox() {
  for (Day day : mDays) {
   //             ,       
   if (downX >= day.startX && downX <= day.endX && downY >= day.startY && downY <= day.endY) {
    clickDay = day;//       
    break;
   }
  }
  //      ,           ,             
  refreshView();
 }
 /**
  *         
  */
 private void refreshView() {
  invalidate();
 }
팝 업 텍스트 상자 그리 기
그리고 팝 업 텍스트 상자 의 그리 기 를 보십시오:

/**
  *          
  * @param canvas   
  */
 private void drawPopupInfo(Canvas canvas) {
  if (clickDay != null) {//      null    
   //              ,         
   Path infoPath = new Path();
   //      
   infoPath.moveTo(clickDay.startX + boxSide / 2, clickDay.startY + boxSide / 2);
   //         
   infoPath.lineTo(clickDay.startX, clickDay.startY);
   //         
   infoPath.lineTo(clickDay.endX, clickDay.startY);
   //    
   canvas.drawPath(infoPath,infoPaint);
   //         
   textPaint.setColor(Color.WHITE);
   //         
   String popupInfo = clickDay.toString();
   System.out.println(popupInfo);
   //                   
   float infoHeight = metrics.descent - metrics.ascent;
   float infoLength = textPaint.measureText(popupInfo);
   Log.e("height",infoHeight+"");
   Log.e("length",infoLength+"");
   //        x=    x+  /2-(    /2+       )
   float leftX = (clickDay.startX + boxSide / 2 ) - (infoLength / 2 + boxSide);
   //        y=    y+  /2-(    +         )
   float topY = clickDay.startY-(infoHeight+2*boxSide);
   //         x=leftX+    +          
   float rightX = leftX+infoLength+2*boxSide;
   //         y=    y
   float bottomY = clickDay.startY;
   System.out.println(""+leftX+"/"+topY+"/"+rightX+"/"+bottomY);
   RectF rectF = new RectF(leftX, topY, rightX, bottomY);
   canvas.drawRoundRect(rectF,4,4,infoPaint);
   //    ,x=leftX+       ,y=topY+         +        
   canvas.drawText(popupInfo,leftX+boxSide,topY+boxSide+Math.abs(metrics.ascent),textPaint);
   clickDay = null;//    ,           
   textPaint.setColor(Color.GRAY);//      
  }
 }
이렇게 주체 논리 가 완성 되 었 으 나 어느 날 제출 횟수 를 설정 하 는 방법 을 개방 해 야 합 니 다.

/**
  *        
  * @param year  
  * @param month  
  * @param day  
  * @param contribution   
  */
 public void setData(int year,int month,int day,int contribution){
  //       ,           
  for (Day d : mDays) {
   if (d.year == year && d.month == month && d.date == day){
    d.contribution = contribution;
    d.colour = getColour(contribution);
    break;
   }
  }
  refreshView();
 }
 /**
  *             
  * @param contribution      
  * @return    
  */
 private int getColour(int contribution){
  int colour = 0;
  if (contribution <= 0){
   colour = COLOUR_LEVEL[4];
  }
  if (contribution == 1){
   colour = COLOUR_LEVEL[3];
  }
  if (contribution == 2){
   colour = COLOUR_LEVEL[2];
  }
  if (contribution == 3){
   colour = COLOUR_LEVEL[1];
  }
  if (contribution >= 4){
   colour = COLOUR_LEVEL[0];
  }
  return colour;
 }
자,모든 논리 가 완성 되 었 습 니 다.주로 계산,전체 코드 와 관련 됩 니 다.

/**
 * Created by Administrator on 2017/1/13.
 *  GitHub      
 *     
 */
public class GitHubContributionView extends View {
 /**         **/
 private final static int DEFAULT_BOX_COLOUR = 0xFFEEEEEE;
 /**       **/
 private final static int[] COLOUR_LEVEL =
   new int[]{0xFF1E6823, 0xFF44A340, 0xFF8CC665, 0xFFD6E685, DEFAULT_BOX_COLOUR};
 /**  **/
 private String[] weeks = new String[]{"Mon", "Wed", "Fri", "Sun"};
 /**  **/
 private String[] months =
   new String[]{"Jan", "Feb", "Mar", "Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
 /**   padding,         **/
 private int padding = 24;
 /**        **/
 private int boxSide = 8;
 /**         **/
 private int boxInterval = 2;
 /**      **/
 private int column = 0;
 private List<Day> mDays;//       
 private Paint boxPaint;//    
 private Paint textPaint;//    
 private Paint infoPaint;//     
 private Paint.FontMetrics metrics;//    
 private float downX;//     X  
 private float downY;//     Y  
 private Day clickDay;//       
 public GitHubContributionView(Context context) {
  this(context, null);
 }
 public GitHubContributionView(Context context, AttributeSet attrs) {
  this(context, attrs, 0);
 }
 public GitHubContributionView(Context context, AttributeSet attrs, int defStyleAttr) {
  super(context, attrs, defStyleAttr);
  initView();
 }
 public void initView() {
  mDays = DateFactory.getDays(2016, 5);
  //    
  boxPaint = new Paint();
  boxPaint.setStyle(Paint.Style.FILL);
  boxPaint.setStrokeWidth(2);
  boxPaint.setColor(DEFAULT_BOX_COLOUR);
  boxPaint.setAntiAlias(true);
  //    
  textPaint = new Paint();
  textPaint.setStyle(Paint.Style.FILL);
  textPaint.setColor(Color.GRAY);
  textPaint.setTextSize(12);
  textPaint.setAntiAlias(true);
  //         
  infoPaint = new Paint();
  infoPaint.setStyle(Paint.Style.FILL);
  infoPaint.setColor(0xCC888888);
  infoPaint.setTextSize(12);
  infoPaint.setAntiAlias(true);
  //      px
  padding = UI.dp2px(getContext(), padding);
  boxSide = UI.dp2px(getContext(), boxSide);
  metrics = textPaint.getFontMetrics();
 }
 @Override
 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
  super.onSizeChanged(w, h, oldw, oldh);
 }
 @Override
 protected void onDraw(Canvas canvas) {
  super.onDraw(canvas);
  column = 0;
  canvas.save();
  drawBox(canvas);
  drawWeek(canvas);
  drawTag(canvas);
  drawPopupInfo(canvas);
  canvas.restore();
 }
 /**
  *   1-12           
  * @param canvas   
  */
 private void drawBox(Canvas canvas) {
  //         
  float startX, startY, endX, endY;
  //     1 
  int month = 1;
  for (int i = 0; i < mDays.size(); i++) {
   Day day = mDays.get(i);
   if (i == 0){
    // 1      ,     x=padding,y=padding-boxSide/2(  ),y         
    canvas.drawText(months[0],padding,padding-boxSide/2,textPaint);
   }
   if (day.week == 1 && i != 0) {
    //      1,         
    column++;
    //          ,         
    if (day.month>month){
     month = day.month;
     //         ,x     , y       ,boxSide/2(  )
     canvas.drawText(months[month-1],padding+column*(boxSide+boxInterval),padding-boxSide/2,textPaint);
    }
   }
   //       ,x             ,y           
   startX = padding + column * (boxSide + boxInterval);
   startY = padding + (day.week - 1) * (boxSide + boxInterval);
   endX = startX + boxSide;
   endY = startY + boxSide;
   //           ,                   
   day.startX = startX;
   day.startY = startY;
   day.endX = endX;
   day.endY = endY;
   //           
   boxPaint.setColor(day.colour);
   canvas.drawRect(startX, startY, endX, endY, boxPaint);
  }
  boxPaint.setColor(DEFAULT_BOX_COLOUR);//      
 }
 /**
  *       
  * @param canvas   
  */
 private void drawWeek(Canvas canvas) {
  //      ,        
  float textLength = 0;
  for (String week : weeks) {
   float tempLength = textPaint.measureText(week);
   if (textLength < tempLength) {
    textLength = tempLength;
   }
  }
  //        ,   x=padding-    -        ,y       
  canvas.drawText(weeks[0], padding - textLength - 2, padding + boxSide - metrics.descent, textPaint);
  canvas.drawText(weeks[1], padding - textLength - 2, padding + 3 * (boxSide + boxInterval) - metrics.descent, textPaint);
  canvas.drawText(weeks[2], padding - textLength - 2, padding + 5 * (boxSide + boxInterval) - metrics.descent, textPaint);
  canvas.drawText(weeks[3], padding - textLength - 2, padding + 7 * (boxSide + boxInterval) - metrics.descent, textPaint);
 }
 /**
  *             ,                
  * @param canvas   
  */
 private void drawTag(Canvas canvas) {
  //            
  float moreLength = textPaint.measureText("More");
  float lessLength = textPaint.measureText("Less");
  //  More   ,x  =padding+(  +1)*(    +    )-      -    
  float moreX = padding + (column + 1) * (boxSide + boxInterval) - boxInterval - moreLength;
  //y  =padding+(    +1,         )*(    +    )+   ascent  
  float moreY = padding + 8 * (boxSide + boxInterval) + Math.abs(metrics.ascent);
  canvas.drawText("More", moreX, moreY, textPaint);
  //     ,       More        
  float interval = boxSide - 2;//         
  float leftX = moreX - interval - boxSide;
  float topY = moreY - boxSide;
  float rightX = moreX - interval;
  float bottomY = moreY;//   Y      
  for (int i = 0; i < COLOUR_LEVEL.length; i++) {
   boxPaint.setColor(COLOUR_LEVEL[i]);
   canvas.drawRect(leftX - i * (boxSide + boxInterval), topY, rightX - i * (boxSide + boxInterval), bottomY, boxPaint);
  }
  //    Less   ,    
  canvas.drawText("Less", leftX - 4 * (boxSide + boxInterval) - interval - lessLength, moreY, textPaint);
 }
 @Override
 public boolean onTouchEvent(MotionEvent event) {
  //         ,        ,   ・
  if (MotionEvent.ACTION_DOWN == event.getAction()) {
   downX = event.getX();
   downY = event.getY();
   findClickBox();
  }
  return super.onTouchEvent(event);
 }
 /**
  *           
  */
 private void findClickBox() {
  for (Day day : mDays) {
   //             ,       
   if (downX >= day.startX && downX <= day.endX && downY >= day.startY && downY <= day.endY) {
    clickDay = day;//       
    break;
   }
  }
  //      ,           ,             
  refreshView();
 }
 /**
  *         
  */
 private void refreshView() {
  invalidate();
 }
 /**
  *          
  * @param canvas   
  */
 private void drawPopupInfo(Canvas canvas) {
  if (clickDay != null) {
   //              ,         
   Path infoPath = new Path();
   //      
   infoPath.moveTo(clickDay.startX + boxSide / 2, clickDay.startY + boxSide / 2);
   //         
   infoPath.lineTo(clickDay.startX, clickDay.startY);
   //         
   infoPath.lineTo(clickDay.endX, clickDay.startY);
   //    
   canvas.drawPath(infoPath,infoPaint);
   //         
   textPaint.setColor(Color.WHITE);
   //         
   String popupInfo = clickDay.toString();
   System.out.println(popupInfo);
   //                   
   float infoHeight = metrics.descent - metrics.ascent;
   float infoLength = textPaint.measureText(popupInfo);
   Log.e("height",infoHeight+"");
   Log.e("length",infoLength+"");
   //        x=    x+  /2-(    /2+       )
   float leftX = (clickDay.startX + boxSide / 2 ) - (infoLength / 2 + boxSide);
   //        y=    y+  /2-(    +         )
   float topY = clickDay.startY-(infoHeight+2*boxSide);
   //         x=leftX+    +          
   float rightX = leftX+infoLength+2*boxSide;
   //         y=    y
   float bottomY = clickDay.startY;
   System.out.println(""+leftX+"/"+topY+"/"+rightX+"/"+bottomY);
   RectF rectF = new RectF(leftX, topY, rightX, bottomY);
   canvas.drawRoundRect(rectF,4,4,infoPaint);
   //    ,x=leftX+       ,y=topY+         +        
   canvas.drawText(popupInfo,leftX+boxSide,topY+boxSide+Math.abs(metrics.ascent),textPaint);
   clickDay = null;//    ,           
   textPaint.setColor(Color.GRAY);//      
  }
 }
 /**
  *        
  * @param year  
  * @param month  
  * @param day  
  * @param contribution   
  */
 public void setData(int year,int month,int day,int contribution){
  //       ,           
  for (Day d : mDays) {
   if (d.year == year && d.month == month && d.date == day){
    d.contribution = contribution;
    d.colour = getColour(contribution);
    break;
   }
  }
  refreshView();
 }
 /**
  *             
  * @param contribution      
  * @return    
  */
 private int getColour(int contribution){
  int colour = 0;
  if (contribution <= 0){
   colour = COLOUR_LEVEL[4];
  }
  if (contribution == 1){
   colour = COLOUR_LEVEL[3];
  }
  if (contribution == 2){
   colour = COLOUR_LEVEL[2];
  }
  if (contribution == 3){
   colour = COLOUR_LEVEL[1];
  }
  if (contribution >= 4){
   colour = COLOUR_LEVEL[0];
  }
  return colour;
 }
}
이렇게 레이아웃 테스트 를 해 보 세 요.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
 xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:gravity="center"
 android:orientation="vertical"
 >
 <com.franky.custom.view.GitHubContributionView
  android:id="@+id/cc_chart"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  />
</LinearLayout>
무 작위 데이터 만 들 기:

public class MainActivity extends AppCompatActivity {
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  GitHubContributionView github = (GitHubContributionView) findViewById(R.id.cc_chart);
  github.setData(2016,12,9,2);
  github.setData(2016,11,9,1);
  github.setData(2016,10,5,10);
  github.setData(2016,8,9,3);
  github.setData(2016,4,20,2);
  github.setData(2016,12,13,3);
  github.setData(2016,12,14,3);
  github.setData(2016,2,15,4);
 }
}
효과.
gif 가 잘 녹음 되 지 않 았 습 니 다.그림 효 과 를 보 세 요.
效果.png
원본 코드 보기
위 에서 말 한 것 은 소 편 이 소개 한 안 드 로 이 드 사용자 정의 View 가 GitHub 를 모방 한 활성 표 제출 을 실현 하 는 것 입 니 다.여러분 에 게 도움 이 되 기 를 바 랍 니 다.궁금 한 점 이 있 으 면 메 시 지 를 남 겨 주세요.소 편 은 바로 답 해 드 리 겠 습 니 다.여기 서도 저희 사이트 에 대한 여러분 의 지지 에 감 사 드 립 니 다!

좋은 웹페이지 즐겨찾기