PS:最近忙于项目的开发,一直都没有去写博客,是时候整理整理自己在其中学到的东西了...

学习内容:

1.使用圆形菜单并实现旋转效果..

    Android的圆形菜单我也是最近才接触到,由于在界面中确实是使用到了,因此就去学习了一下圆形菜单的使用,并且实现菜单的旋转效果,类似于摩天轮那样的效果,个人感觉还是蛮不错的,就是在实现的过程中有点麻烦...通过动态加载的方式,使用ViewGroup来实现了这个过程...个人感觉是一个蛮复杂的过程,最后附上源码...上面先附上效果图,其实这个图给人的感觉更像是摩天轮,转动中心位置的时候,几个附带的小圆会进行转动,通过转动我们可以看到被挡住的部分...算是为了实现一种互动吧...直接上实现过程的代码,然后在进行解释...估计看到下面的代码,很多人就恶心了...但是如果坚持看完了,那么就真正学会了...先不要看下面的代码,把代码先过掉...看下面的解释...

package com.circle.cil_212_app;import com.example.cil_212_app.R;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;@TargetApi(Build.VERSION_CODES.CUPCAKE)
public class CircleMenuLayout extends ViewGroup{//→_→ 第一部分...private int mRadius;   //定义layout的半径...//定义了两个数值...在选取半径长度的时候需要使用...private float mMaxChildDimesionRadio = 1/ 4f;private float mCenterItemDimesionRadio = 1/ 3f;private LayoutInflater inflater;  //自定义加载布局...private double StartAngle;     //定义初始角度...private String[] ItemTexts = new String[]{"HTML", "CSS", "JS","JQuery", "DOM", "TEMPLETE"};private int[] ItemImgs = new int[]{R.drawable.home_mbank_1_normal,R.drawable.home_mbank_2_normal,R.drawable.home_mbank_3_normal,R.drawable.home_mbank_4_normal,R.drawable.home_mbank_5_normal,R.drawable.home_mbank_6_normal};private int TouchSlop;/** 加速度检测* */private float DownAngle;private float TmpAngle;private long DownTime;private boolean isFling;  //判断是否在自由旋转...//→_→  第二部分..public CircleMenuLayout(Context context, AttributeSet attrs) {super(context,attrs);// TODO Auto-generated constructor stub
        inflater=LayoutInflater.from(context);for(int i=0;i<ItemImgs.length;i++){final int j=i;View view=inflater.inflate(R.layout.web_circle_1, this, false); ImageView iv=(ImageView) view.findViewById(R.id.id_circle_menu_item_image);TextView tv=(TextView) view.findViewById(R.id.id_circle_menu_item_text);iv.setImageResource(ItemImgs[i]);tv.setText(ItemTexts[i]);view.setOnClickListener(new OnClickListener() {@SuppressLint("NewApi")@Overridepublic void onClick(View v) {// TODO Auto-generated method stub
                    Toast.makeText(getContext(), ItemTexts[j], Toast.LENGTH_SHORT).show();}});addView(view);
        }TouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();}//→_→ 第三部分

    @Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){setMeasuredDimension(getSuggestedMinimumWidth(), getSuggestedMinimumHeight());mRadius=Math.max(getWidth(), getHeight());final int count =getChildCount();  int childsize=(int)(mRadius*mMaxChildDimesionRadio);int childMode=MeasureSpec.EXACTLY;for(int i=0;i<count;i++){final View child=getChildAt(i);if(child.getVisibility()==GONE){continue;}int makeMeasureSpec=-1;if(child.getId()==R.id.id_circle_menu_item_center){makeMeasureSpec = MeasureSpec.makeMeasureSpec((int) (mRadius * mCenterItemDimesionRadio), childMode);}else{makeMeasureSpec=MeasureSpec.makeMeasureSpec(childsize, childMode);}
            child.measure(makeMeasureSpec, makeMeasureSpec);}}//→_→ 第四部分
    @Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {// TODO Auto-generated method stubint layoutWidth = r - l;int layoutHeight = b - t;int layoutRadius = Math.max(layoutWidth, layoutHeight);final int childCount=getChildCount();int left,top;int radius = (int) (layoutRadius * mMaxChildDimesionRadio);
float angleDelay = 360 / (getChildCount() - 1);for (int i = 0; i < childCount; i++){final View child = getChildAt(i);if (child.getId() == R.id.id_circle_menu_item_center)continue;if (child.getVisibility() == GONE){continue;}
StartAngle %= 360;float tmp = layoutRadius * 1f / 3 - 1 / 22f * layoutRadius;left = layoutRadius/ 2+ (int) Math.round(tmp* Math.cos(Math.toRadians(StartAngle)) - 1 / 2f* radius);top = layoutRadius/ 2+ (int) Math.round(tmp* Math.sin(Math.toRadians(StartAngle)) - 1 / 2f* radius);
child.layout(left, top, left + radius, top + radius);StartAngle += angleDelay;}View cView = findViewById(R.id.id_circle_menu_item_center);cView.setOnClickListener(new OnClickListener(){@Overridepublic void onClick(View v){Toast.makeText(getContext(), "aa", Toast.LENGTH_LONG).show();}});int cl = layoutRadius / 2 - cView.getMeasuredWidth() / 2;int cr = cl + cView.getMeasuredWidth();cView.layout(cl, cl, cr, cr);}//→_→ 第五部分private float mLastX;private float mLastY;private FlingRunnable mFlingRunnable;@Overridepublic boolean dispatchTouchEvent(MotionEvent event){float x = event.getX();float y = event.getY();switch (event.getAction()){//按下操作...事件机制自带的变量...case MotionEvent.ACTION_DOWN:mLastX = x;mLastY = y;DownAngle = getAngle(x, y);DownTime = System.currentTimeMillis();  TmpAngle = 0;if (isFling){removeCallbacks(mFlingRunnable);isFling = false;return true ; }break;case MotionEvent.ACTION_MOVE:float start = getAngle(mLastX, mLastY);float end = getAngle(x, y);if (getQuadrant(x, y) == 1 || getQuadrant(x, y) == 4){StartAngle += end - start;TmpAngle += end - start;}else{StartAngle += start - end;TmpAngle += start - end;}
            requestLayout();
mLastX = x;mLastY = y;break;case MotionEvent.ACTION_UP:
float anglePrMillionSecond = TmpAngle * 1000/ (System.currentTimeMillis() - DownTime);
if (Math.abs(anglePrMillionSecond) > 230 && !isFling){post(mFlingRunnable = new FlingRunnable(anglePrMillionSecond));}if(Math.abs(anglePrMillionSecond) >230 || isFling){return true ; }break;}return super.dispatchTouchEvent(event);}private float getAngle(float xTouch, float yTouch){double x = xTouch - (mRadius / 2d);double y = yTouch - (mRadius / 2d);return (float) (Math.asin(y / Math.hypot(x, y)) * 180 / Math.PI);}private int getQuadrant(float x, float y){int tmpX = (int) (x - mRadius / 2);int tmpY = (int) (y - mRadius / 2);if (tmpX >= 0){return tmpY >= 0 ? 4 : 1;}else{return tmpY >= 0 ? 3 : 2;}}//→_→ 第六部分private class FlingRunnable implements Runnable{private float velocity;public FlingRunnable(float velocity){this.velocity = velocity;}public void run(){if ((int) Math.abs(velocity) < 20){isFling = false;return;}isFling = true;StartAngle += (velocity / 30);velocity /= 1.0666F;postDelayed(this, 30);
            requestLayout();}}
}

在这里开始进行正式的解释,我把代码分成了六个部分...这六个部分最核心的地方就属于第三部分和第四部分和第五部分了,因此我就先解释三四五部分...首先是第三个部分,第三个部分是测量部分,因为这个布局中,这七个彩色圆圈图需要我们动态的添加到我们的布局上,为什么要动态布局,而不是静态,因为后面我们需要实现旋转效果,可能有人不明白为什么旋转就要用动态加载布局,其实旋转就是对布局的样式进行持续刷新,每一次刷新都会导致控件的位置的改变,我们总不能把旋转一圈的布局文件全写完吧?因此动态的添加是为了有更高的灵活性..因此我们需要一个测量的过程,因为动态的加载控件时,系统需要对每一个控件的位置进行计算,找到一个合适的ViewGroup(ViewGroup我们可以把它理解成一个容器,这个容器可以放入组件,也可以放入子容器),然后将控件放入到其中,但是系统计算的数据往往不一定是我们想要的那样...因此我在这里使用了第三部分进行计算...计算每一个控件需要多大的空间才能够放得下...这就是第三部分的完整解释...

    //→_→ 第三部分//在动态加载布局的时候,我们需要人为的进行计算...布局的大小...
    @Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){/** 调用这个方法的目的是为View设置大小...* 直接设置成系统根据父容器算出的一个推荐的最小值...* */setMeasuredDimension(getSuggestedMinimumWidth(), getSuggestedMinimumHeight());//获取半径...mRadius=Math.max(getWidth(), getHeight());final int count =getChildCount(); //获取子控件的数量,这里是7... int childsize=(int)(mRadius*mMaxChildDimesionRadio);/* 这里涉及到了一个测量的模式,这个模式有三种属性...* * MeasureSpec.UNSPECIFIED,父视图不对子视图施加任何限制,子视图可以得到任意想要的大小;** MeasureSpec.EXACTLY,父视图希望子视图的大小是specSize中指定的大小;*    * MeasureSpec.AT_MOST,子视图的大小最多是specSize中的大小。* */int childMode=MeasureSpec.EXACTLY;//对所有的子View进行迭代测量...说白了就是这7个View都得进行测量...for(int i=0;i<count;i++){final View child=getChildAt(i);//子控件不可显示,直接跳过..if(child.getVisibility()==GONE){continue;}int makeMeasureSpec=-1;//子控件为中心图标的时候,设置其半径大小为1/3父容器半径的大小...//如果子控件是其他,也就表示为周围空间的时候,设置为父容器半径的1/4大小...//测量的步骤在于下面的代码块...if(child.getId()==R.id.id_circle_menu_item_center){//此步骤是对数据和模式的一个封装...返回一个48位的int值,高32位表示模式,低16位表示数值...makeMeasureSpec = MeasureSpec.makeMeasureSpec((int) (mRadius * mCenterItemDimesionRadio), childMode);}else{makeMeasureSpec=MeasureSpec.makeMeasureSpec(childsize, childMode);}//这个步骤才是真正的计算过程...传递过去的仍然是一个48位的值,系统会根据传递过去的模式来对View进行参数设置...
            child.measure(makeMeasureSpec, makeMeasureSpec);}}

 第四部分其实就是正式进行布局了,但是布局我们不能随便去布,否则不会出现想要的效果,这里涉及到了一个数学上的知识...中心位置的圆圈是很好测的,但是如何测中心圆旁边的小圆位置才是关键..因此这里用了一个数学知识...

这就是如何测出中心圆圈到小圆圆心距离的测量方法...其实就是为了求出r和小圆圆心坐标...算出了这个坐标点的位置,这样就可以进行放置了,这个坐标点的位置是一点点找出来的...需要进行尝试,只是一个计算的过程,有心的人只要研究就能弄懂...无心的人给他解释也是白搭...这就是第四部分的目的,就是为了算出位置...

    //→_→ 第四部分
    @Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {// TODO Auto-generated method stubint layoutWidth = r - l;int layoutHeight = b - t;//对父容器进行布局...int layoutRadius = Math.max(layoutWidth, layoutHeight);final int childCount=getChildCount();int left,top;int radius = (int) (layoutRadius * mMaxChildDimesionRadio);//根据子元素的个数,设置角度...float angleDelay = 360 / (getChildCount() - 1);for (int i = 0; i < childCount; i++){final View child = getChildAt(i);if (child.getId() == R.id.id_circle_menu_item_center)continue;if (child.getVisibility() == GONE){continue;}//取角度值..StartAngle %= 360;float tmp = layoutRadius * 1f / 3 - 1 / 22f * layoutRadius;left = layoutRadius/ 2+ (int) Math.round(tmp* Math.cos(Math.toRadians(StartAngle)) - 1 / 2f* radius);top = layoutRadius/ 2+ (int) Math.round(tmp* Math.sin(Math.toRadians(StartAngle)) - 1 / 2f* radius);// Log.e("TAG", "left = " + left + " , top = " + top);//由于前面还有1/8长度用来放置那个文本框...因此需要求出整体父容器的定位点...child.layout(left, top, left + radius, top + radius);StartAngle += angleDelay;}View cView = findViewById(R.id.id_circle_menu_item_center);cView.setOnClickListener(new OnClickListener(){@Overridepublic void onClick(View v){Toast.makeText(getContext(), "aa", Toast.LENGTH_LONG).show();}});//设置中心...int cl = layoutRadius / 2 - cView.getMeasuredWidth() / 2;int cr = cl + cView.getMeasuredWidth();cView.layout(cl, cl, cr, cr);}

  第五部分和三四没有关联,第五部分是实现旋转过程的一个重要过程...这里我重写了dispatchTouchEvent来实现...这和上一篇是存在关联的...第五部分其实就很简单了,就是实现旋转,旋转时我们需要获取旋转的角度值和坐标值,获取坐标值的目的是为了判断角度值,角度值获取到了后,传递给第六部分开启线程...系统才会按照指定的角度对布局进行持续的刷新...

    //→_→ 第五部分private float mLastX;private float mLastY;private FlingRunnable mFlingRunnable; //定义了一个线程...为实现第六部分定义了一个对象...
    @Overridepublic boolean dispatchTouchEvent(MotionEvent event){//随手指滑动特效...float x = event.getX();float y = event.getY();switch (event.getAction()){//按下操作...事件机制自带的变量...case MotionEvent.ACTION_DOWN:mLastX = x;mLastY = y;DownAngle = getAngle(x, y);//获取角度...DownTime = System.currentTimeMillis();  //系统的当前时间...TmpAngle = 0;//如果当前在进行快速滚动,那么移除对快速移动的回调...其实就是如果这个界面正在旋转,在旋转的期间我DOWN了一下,那么直接就停止旋转...if (isFling){removeCallbacks(mFlingRunnable);isFling = false;return true ; }break;//移动操作...case MotionEvent.ACTION_MOVE://获取开始和结束后的角度...我们这里移动的是角度...因此需要获取角度...float start = getAngle(mLastX, mLastY);float end = getAngle(x, y);//判断x,y的值是否在1,4象限...象限相比大家都明白,是为了获取角度值...if (getQuadrant(x, y) == 1 || getQuadrant(x, y) == 4){//在一四象限角度为正...StartAngle += end - start;TmpAngle += end - start;}else{StartAngle += start - end;TmpAngle += start - end;}//重新对布局进行设置...其实就是不断刷新布局的一个过程...
            requestLayout();//将初始值设置为旋转后的值...mLastX = x;mLastY = y;break;//抬起操作...case MotionEvent.ACTION_UP://计算每秒钟移动的角度...float anglePrMillionSecond = TmpAngle * 1000/ (System.currentTimeMillis() - DownTime);//如果数值大于这个指定的数值,那么就会认为是加速滚动...if (Math.abs(anglePrMillionSecond) > 230 && !isFling){//开启一个新的线程,让其进行自由滚动...post(mFlingRunnable = new FlingRunnable(anglePrMillionSecond));}if(Math.abs(anglePrMillionSecond) >230 || isFling){return true ; }break;}return super.dispatchTouchEvent(event);}//这里用来测试旋转的角度...算出角度之后返回...返回给上面的方法...private float getAngle(float xTouch, float yTouch){double x = xTouch - (mRadius / 2d);double y = yTouch - (mRadius / 2d);return (float) (Math.asin(y / Math.hypot(x, y)) * 180 / Math.PI);}//在这里我们对坐标值进行一个判断..然后把坐标值返回...目的是测试角度...private int getQuadrant(float x, float y){int tmpX = (int) (x - mRadius / 2);int tmpY = (int) (y - mRadius / 2);if (tmpX >= 0){return tmpY >= 0 ? 4 : 1;}else{return tmpY >= 0 ? 3 : 2;}}

  而第六部分其实就没什么了,因为这个界面在旋转的时候,我们不能让他一直转,迟早要停下来,因此我们需要有一个线程来帮助我们持续对界面刷新,并且控制刷新的速度,随着velocity这个值越来越小刷新的速度也就越来越慢,最后就静止不动,这样给人的感觉就是一个减速的过程...

    //→_→ 第六部分private class FlingRunnable implements Runnable{private float velocity;public FlingRunnable(float velocity){this.velocity = velocity;}public void run(){if ((int) Math.abs(velocity) < 20){isFling = false;return;}//减速旋转...isFling = true;StartAngle += (velocity / 30);velocity /= 1.0666F;postDelayed(this, 30);//需要保证时刻对页面进行刷新..因为始终要进行新的布局...
            requestLayout();}}
}

  第二部分其实就是加载旁边那个TextView和其背景的一个过程,并定义了一些相关资源...第一部分就更不用说了,一些变量的定义...看懂了三四五六部分,自然知道那些变量的作用了...最后贴一下xml文件和Activity的源代码....

Activity....

package com.example.cil_212_app;import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.view.KeyEvent;
import android.view.Menu;public class Web extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.web_circle);}@Overridepublic boolean onKeyDown(int keyCode, KeyEvent event){if(keyCode==KeyEvent.KEYCODE_BACK){Intent intent=new Intent(Web.this,CoverActivity.class);startActivity(intent);this.finish();}return super.onKeyDown(keyCode, event);}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.android, menu);return true;}}

xml...补充一点就是我自己定义了一个资源文件...用来存放id信息使用的....这样可以在布局中直接进行引用....

<?xml version="1.0" encoding="utf-8"?>
<resources><item name="id_circle_menu_item_image" type="id"/><item name="id_circle_menu_item_text" type="id"/><item name="id_circle_menu_item_center" type="id"/>
</resources>

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="wrap_content"android:layout_height="wrap_content"android:gravity="center_horizontal"android:orientation="vertical" ><ImageView android:id="@id/id_circle_menu_item_image"android:layout_height="wrap_content"android:layout_width="wrap_content"/><TextView android:id="@id/id_circle_menu_item_text"android:layout_height="wrap_content"android:layout_width="wrap_content"android:textColor="@android:color/black"android:textSize="14dip"/>
</LinearLayout>

<?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:background="@drawable/web_bg"android:gravity="center_vertical"android:orientation="horizontal" ><LinearLayoutandroid:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1.0"android:background="@drawable/turnplate_bg_left"android:gravity="center"android:orientation="vertical" ><TextViewandroid:layout_width="fill_parent"android:layout_height="wrap_content"android:gravity="center"android:text="Web 开发"android:textColor="#236B8E"android:textStyle="bold|italic"android:textSize="18dp" /><TextViewandroid:layout_width="fill_parent"android:gravity="center"android:layout_height="wrap_content"android:textAlignment="textStart"android:layout_marginTop="5dp"android:textStyle="bold|italic"android:text="Web页面开发,快速学会前台页面制作."android:textColor="#236B8E"android:textSize="13.5dip" /></LinearLayout><FrameLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content" ><com.circle.cil_212_app.CircleMenuLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@drawable/turnplate_bg_right" ><RelativeLayoutandroid:id="@id/id_circle_menu_item_center"android:layout_width="wrap_content"android:layout_height="wrap_content" ><ImageViewandroid:layout_width="104.0dip"android:layout_height="104.0dip"android:layout_centerInParent="true"android:background="@drawable/turnplate_center_unlogin" /><!--  <ImageViewandroid:layout_width="116.0dip"android:layout_height="116.0dip"android:layout_centerInParent="true"android:background="@drawable/turnplate_mask_unlogin_normal" />--></RelativeLayout></com.circle.cil_212_app.CircleMenuLayout></FrameLayout>
</LinearLayout>

源码地址:http://files.cnblogs.com/files/RGogoing/com_Draker.zip

Android学习笔记之如何使用圆形菜单实现旋转效果...相关推荐

  1. Pro Android学习笔记(三三):Menu(4):Alternative菜单

    什么是Alternative menu(替代菜单) 举个例子,Activity显示一个文本文件.如果用户想对文本文件进行编辑,Activity不提供编辑能力,但可由其他activity或者其他应用提供 ...

  2. Android学习笔记之(一)开发环境搭建

    Android学习笔记之(一)开发环境搭建 zouxy09@qq.com http://blog.csdn.net/zouxy09 至于说Android是什么之类的俺就不啰嗦了,因为它离我们太近了.直 ...

  3. Android学习笔记09:Paint及Canvas的简单应用

    2019独角兽企业重金招聘Python工程师标准>>> Android学习笔记09:Paint及Canvas的简单应用 在Android中需要通过graphics类来显示2D图形. ...

  4. Android学习笔记之AndroidManifest.xml文件解析(摘自皮狼的博客)

    Android学习笔记之AndroidManifest.xml文件解析 一.关于AndroidManifest.xml AndroidManifest.xml 是每个android程序中必须的文件.它 ...

  5. Android学习笔记 2.5.3 实例——使用SimpleAdapter创建ListView 2.5.4 自动完成文本框(AutoCompleteTextView)的功能与用法

    Android学习笔记 疯狂Android讲义 文章目录 Android学习笔记 疯狂Android讲义 第2章 Android 应用的界面编程 2.5 第4组 UI组件:AdapterView及其子 ...

  6. Android学习笔记-常用的一些源码,防止忘记了

    Android学习笔记-常用的一些源码,防止忘记了... 设置拨打电话 StringdialUri="tell:"+m_currentTelNumble; IntentcallIn ...

  7. Android学习笔记21:ImageView获取网络图片

    Android平台有3种网络接口可以使用,它们分别是:java.net.*(标准java接口).org.apache(Apache接口)和android.net.*(Android网络接口).本文将使 ...

  8. Android学习笔记(七):多个Activity和Intent

    根据www.mars-droid.com:Andriod开发视频教学,先跳过书本<Beginning Android 2>的几个章,我是这两个资源一起看,需要进行一下同步.先初步了解一下应 ...

  9. Android学习笔记26:图片切换控件ImageSwitcher的使用

    在Windows操作系统中,要查看多张图片,可以通过使用"Windows照片查看器"在"上一张"和"下一张"之间切换,进行多张图片的浏览. ...

最新文章

  1. 仿麦包包首页table轮换图jQuery(转自www.jqueryba.com)
  2. 缺陷漏测分析:测试过程改进
  3. HAAR、LBP分类器训练
  4. 桂林电子科技大学 计算机学院,桂林电子科技大学信息科技学院
  5. SRV05-4二极管参数
  6. 2021 ACDU China Tour-上海站暨数据库大咖讲坛(第4期)成功举办!(附视频回放PPT下载)...
  7. Wireshark-001基本设置
  8. kafka 基础知识梳理-kafka是一种高吞吐量的分布式发布订阅消息系统
  9. Spring Boot不指定包路径就可以扫描启动类所在包及其子包下的类是怎么做到的?
  10. 解决安卓4.4webview的兼容性问题
  11. 51单片机的篮球计分器设计
  12. 计算机如何进入ping,电脑怎么ping网络,教你电脑怎么ping网络
  13. linux转置的命令,转置文件(awk)
  14. PCL库学习笔记——使用变换矩阵变换点云
  15. ORA-01455: converting column overflows integer datatype
  16. HDU-2544 最短路【最短路】
  17. jquery $.fn $.fx是什么意思有什么用
  18. sublime的一些使用技巧
  19. CSS3干货28:妙用 transition 实现中英文切换导航
  20. Linux ssh命令详解,连ssh命令都不了解就别说自己会用Linux了

热门文章

  1. KSQL DB 学习笔记2
  2. 全排列牛客和L46,L47
  3. 正常计算机的c盘空间多大,电脑C盘应该留多大空间?
  4. 28.找出字符串中第一个匹配项的下标
  5. 单片机定时器计数原理
  6. P1008 [NOIP1998 普及组] 三连击
  7. 怎么用U盘制作原版系统启动盘
  8. 如何成为稀缺性人才?
  9. EditPlus v2.12 注册过程分析(转)
  10. TVS和一般的稳压二极管有什么区别? (转)