├── .gitignore ├── .idea ├── .name ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── encodings.xml ├── gradle.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── zoe │ │ │ └── jiaen │ │ │ └── zhihuanswer │ │ │ ├── AirActivity.java │ │ │ ├── MainActivity.java │ │ │ ├── QQHealthActivity.java │ │ │ └── view │ │ │ ├── AirConditionerView.java │ │ │ └── QQHealthView.java │ └── res │ │ ├── layout │ │ ├── activity_air_conditioner.xml │ │ ├── activity_main.xml │ │ └── activity_qq_health.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-v21 │ │ └── styles.xml │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── zoe │ └── jiaen │ └── zhihuanswer │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | ZhihuAnswer -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 知乎回答用到的代码 2 | 3 | [1](https://www.zhihu.com/question/38523925) 4 | 5 | [2](https://www.zhihu.com/question/38598212) 6 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "23.0.1" 6 | 7 | defaultConfig { 8 | applicationId "zoe.jiaen.zhihuanswer" 9 | minSdkVersion 15 10 | targetSdkVersion 23 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | testCompile 'junit:junit:4.12' 25 | compile 'com.android.support:appcompat-v7:23.0.1' 26 | compile 'com.android.support:design:23.0.1' 27 | } 28 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 22 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/java/zoe/jiaen/zhihuanswer/AirActivity.java: -------------------------------------------------------------------------------- 1 | package zoe.jiaen.zhihuanswer; 2 | 3 | import android.os.Bundle; 4 | import android.support.v7.app.AppCompatActivity; 5 | 6 | /** 7 | * Created by Liujilong on 2015/12/18. 8 | * liujilong.me@gmail.com 9 | */ 10 | public class AirActivity extends AppCompatActivity { 11 | @Override 12 | protected void onCreate(Bundle savedInstanceState) { 13 | super.onCreate(savedInstanceState); 14 | setContentView(R.layout.activity_air_conditioner); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/zoe/jiaen/zhihuanswer/MainActivity.java: -------------------------------------------------------------------------------- 1 | package zoe.jiaen.zhihuanswer; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.view.View; 7 | 8 | public class MainActivity extends AppCompatActivity { 9 | 10 | @Override 11 | protected void onCreate(Bundle savedInstanceState) { 12 | super.onCreate(savedInstanceState); 13 | setContentView(R.layout.activity_main); 14 | } 15 | 16 | public void qq_health(View v){ 17 | startActivity(new Intent(this,QQHealthActivity.class)); 18 | } 19 | public void air_conditioning(View v){ 20 | startActivity(new Intent(this,AirActivity.class)); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/zoe/jiaen/zhihuanswer/QQHealthActivity.java: -------------------------------------------------------------------------------- 1 | package zoe.jiaen.zhihuanswer; 2 | 3 | 4 | import android.support.v7.app.AppCompatActivity; 5 | import android.os.Bundle; 6 | 7 | public class QQHealthActivity extends AppCompatActivity { 8 | 9 | @Override 10 | protected void onCreate(Bundle savedInstanceState) { 11 | super.onCreate(savedInstanceState); 12 | setContentView(R.layout.activity_qq_health); 13 | } 14 | } -------------------------------------------------------------------------------- /app/src/main/java/zoe/jiaen/zhihuanswer/view/AirConditionerView.java: -------------------------------------------------------------------------------- 1 | package zoe.jiaen.zhihuanswer.view; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.Color; 6 | import android.graphics.Paint; 7 | import android.graphics.RectF; 8 | import android.graphics.SweepGradient; 9 | import android.util.AttributeSet; 10 | import android.view.MotionEvent; 11 | import android.view.View; 12 | 13 | /** 14 | * Created by Liujilong on 2015/12/18. 15 | * liujilong.me@gmail.com 16 | */ 17 | public class AirConditionerView extends View { 18 | private float mTemperature = 24f; 19 | 20 | private Paint mArcPaint; 21 | private Paint mLinePaint; 22 | private Paint mTextPaint; 23 | 24 | private float mMinSize; 25 | private float mGapWidth; 26 | private float mInnerRadius; 27 | private float mRadius; 28 | private float mCenter; 29 | 30 | private RectF mArcRect; 31 | private SweepGradient mSweepGradient; 32 | 33 | public AirConditionerView(Context context) { 34 | super(context, null); 35 | } 36 | 37 | public AirConditionerView(Context context, AttributeSet attrs) { 38 | this(context, attrs, 0); 39 | } 40 | 41 | public AirConditionerView(Context context, AttributeSet attrs, int defStyleAttr) { 42 | super(context, attrs, defStyleAttr); 43 | init(); 44 | } 45 | 46 | private void init(){ 47 | mArcPaint = new Paint(); 48 | mArcPaint.setStyle(Paint.Style.STROKE); 49 | mArcPaint.setAntiAlias(true); 50 | 51 | mLinePaint = new Paint(); 52 | mLinePaint.setStyle(Paint.Style.STROKE); 53 | mLinePaint.setAntiAlias(true); 54 | mLinePaint.setColor(0xffdddddd); 55 | 56 | mTextPaint = new Paint(); 57 | mTextPaint.setAntiAlias(true); 58 | mTextPaint.setColor(0xff64646f); 59 | } 60 | 61 | private void initSize(){ 62 | mGapWidth = 56*mMinSize; 63 | mInnerRadius = 180*mMinSize; 64 | mCenter = 300*mMinSize; 65 | mRadius = 208*mMinSize; 66 | 67 | mArcRect = new RectF(mCenter-mRadius,mCenter-mRadius,mCenter+mRadius,mCenter+mRadius); 68 | int[] colors = {0xFFE5BD7D,0xFFFAAA64, 69 | 0xFFFFFFFF, 0xFF6AE2FD, 70 | 0xFF8CD0E5, 0xFFA3CBCB, 71 | 0xFFBDC7B3, 0xFFD1C299, 0xFFE5BD7D, }; 72 | float[] positions = {0,1f/8,2f/8,3f/8,4f/8,5f/8,6f/8,7f/8,1}; 73 | mSweepGradient = new SweepGradient(mCenter, mCenter, colors , positions); 74 | } 75 | 76 | @Override 77 | protected void onDraw(Canvas canvas) { 78 | // draw arc 79 | mArcPaint.setStrokeWidth(mGapWidth); 80 | int gapDegree = getDegree(); 81 | mArcPaint.setShader(mSweepGradient); 82 | canvas.drawArc(mArcRect, -225, gapDegree + 225, false, mArcPaint); 83 | mArcPaint.setShader(null); 84 | mArcPaint.setColor(Color.WHITE); 85 | canvas.drawArc(mArcRect, gapDegree, 45 - gapDegree, false, mArcPaint); 86 | 87 | // draw line 88 | mLinePaint.setStrokeWidth(mMinSize*1.5f); 89 | for(int i = 0; i<120;i++){ 90 | if(i<=45 || i >= 75){ 91 | float top = mCenter-mInnerRadius-mGapWidth; 92 | if(i%15==0){ 93 | top = top - 20*mMinSize; 94 | } 95 | canvas.drawLine(mCenter, mCenter - mInnerRadius, mCenter, top, mLinePaint); 96 | } 97 | canvas.rotate(3,mCenter,mCenter); 98 | } 99 | // draw text 100 | mTextPaint.setTextSize(mMinSize*30); 101 | mTextPaint.setTextAlign(Paint.Align.CENTER); 102 | for(int i = 16; i<29; i+=2){ 103 | float r = mInnerRadius+mGapWidth + 40*mMinSize; 104 | float x = (float) (mCenter + r*Math.cos((26-i)/2*Math.PI/4)); 105 | float y = (float) (mCenter - r*Math.sin((26-i)/2*Math.PI/4)); 106 | canvas.drawText(""+i,x,y - ((mTextPaint.descent() + mTextPaint.ascent()) / 2),mTextPaint); 107 | } 108 | } 109 | 110 | private int getDegree(){ 111 | checkTemperature(mTemperature); 112 | return -225 + (int)((mTemperature-16)/12*90+0.5f)*3; 113 | } 114 | private void checkTemperature(float t){ 115 | if(t<16 || t > 28){ 116 | throw new RuntimeException("Temperature out of range"); 117 | } 118 | } 119 | 120 | public void setTemperature(float t){ 121 | checkTemperature(t); 122 | mTemperature = t; 123 | invalidate(); 124 | } 125 | 126 | @Override 127 | public boolean onTouchEvent(MotionEvent event) { 128 | float x = event.getX(); 129 | float y = event.getY(); 130 | double distance = Math.sqrt((x - mCenter) * (x - mCenter) + (y - mCenter) * (y - mCenter)); 131 | if(distance < mInnerRadius || distance > mInnerRadius + mGapWidth){ 132 | return false; 133 | } 134 | double degree = Math.atan2(-(y-mCenter),x-mCenter); 135 | if(-3*Math.PI/4 maxBar){ 172 | maxBar = step; 173 | } 174 | } 175 | float length; 176 | mTextPaint.setColor(Color.WHITE); 177 | mTextPaint.setTextSize(18*mMinSize); 178 | mTextPaint.setTextAlign(Paint.Align.CENTER); 179 | for(int i = 0; i < mSteps.length; i++){ 180 | xPos = (2*i+1)* halfBarGap + 30 *mMinSize; 181 | length = (yPos - maxLength) * mSteps[i]*1f/maxBar; 182 | canvas.drawLine(xPos, yPos, xPos, yPos -length, mBarPaint ); 183 | String date = String.format("%02d日",8+i); 184 | canvas.drawText(date,xPos, 520*mMinSize, mTextPaint ); 185 | } 186 | 187 | // 6.draw text below 188 | mTextPaint.setTextAlign(Paint.Align.LEFT); 189 | mTextPaint.setColor(Color.WHITE); 190 | mTextPaint.setTextSize(23*mMinSize); 191 | canvas.drawText("这是被隐藏的内容",30 * mMinSize,610*mMinSize,mTextPaint); 192 | mTextPaint.setTextAlign(Paint.Align.RIGHT); 193 | mTextPaint.setColor(0xFF63CFEC); 194 | canvas.drawText("查看 >", 540*mMinSize, 610*mMinSize, mTextPaint); 195 | } 196 | 197 | private void drawUpRoundRect(float left, float top, float right, float bottom, float radius, Paint paint, Canvas canvas) { 198 | Path path = new Path(); 199 | path.moveTo(left, top); 200 | path.lineTo(right-radius, top); 201 | path.quadTo(right,top,right, top+radius); 202 | path.lineTo(right, bottom); 203 | path.lineTo(left, bottom); 204 | path.lineTo(left, top + radius); 205 | path.quadTo(left, top, left + radius, top); 206 | canvas.drawPath(path, paint); 207 | } 208 | private void drawBelowRoundRect(float left, float top, float right, float bottom, float radius, Paint paint, Canvas canvas) { 209 | Path path = new Path(); 210 | path.moveTo(left, top); 211 | path.lineTo(right, top); 212 | path.lineTo(right, bottom-radius); 213 | path.quadTo(right, bottom,right-radius,bottom); 214 | path.lineTo(left+radius, bottom); 215 | path.quadTo(left,bottom,left,bottom-radius); 216 | path.lineTo(left, top); 217 | canvas.drawPath(path, paint); 218 | } 219 | 220 | 221 | 222 | @Override 223 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 224 | int desiredWidth = Integer.MAX_VALUE; 225 | int widthMode = MeasureSpec.getMode(widthMeasureSpec); 226 | int widthSize = MeasureSpec.getSize(widthMeasureSpec); 227 | int heightMode = MeasureSpec.getMode(heightMeasureSpec); 228 | int heightSize = MeasureSpec.getSize(heightMeasureSpec); 229 | 230 | int width; 231 | int height; 232 | 233 | //Measure Width 234 | if (widthMode == MeasureSpec.EXACTLY) { 235 | //Must be this size 236 | width = widthSize; 237 | } else if (widthMode == MeasureSpec.AT_MOST) { 238 | width = Math.min(desiredWidth, widthSize); 239 | } else { 240 | //Be whatever you want 241 | width = desiredWidth; 242 | } 243 | mMinSize = width/570.f; 244 | int desiredHeight = (int) (mMinSize*650); 245 | initSize(); 246 | //Measure Height 247 | if (heightMode == MeasureSpec.EXACTLY) { 248 | //Must be this size 249 | height = heightSize; 250 | } else if (heightMode == View.MeasureSpec.AT_MOST) { 251 | //Can't be bigger than... 252 | height = Math.min(desiredHeight, heightSize); 253 | } else { 254 | //Be whatever you want 255 | height = desiredHeight; 256 | } 257 | 258 | //MUST CALL THIS 259 | setMeasuredDimension(width, height); 260 | } 261 | 262 | 263 | } -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_air_conditioner.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 |