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")
@Override
public 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();
} //→_→ 第三部分 @Override
protected 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);
}
} //→_→ 第四部分
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// TODO Auto-generated method stub
int 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()
{
@Override
public 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; @Override
public 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我们可以把它理解成一个容器,这个容器可以放入组件,也可以放入子容器),然后将控件放入到其中,但是系统计算的数据往往不一定是我们想要的那样...因此我在这里使用了第三部分进行计算...计算每一个控件需要多大的空间才能够放得下...这就是第三部分的完整解释...

    //→_→ 第三部分

    //在动态加载布局的时候,我们需要人为的进行计算...布局的大小...
@Override
protected 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和小圆圆心坐标...算出了这个坐标点的位置,这样就可以进行放置了,这个坐标点的位置是一点点找出来的...需要进行尝试,只是一个计算的过程,有心的人只要研究就能弄懂...无心的人给他解释也是白搭...这就是第四部分的目的,就是为了算出位置...

    //→_→ 第四部分
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// TODO Auto-generated method stub
int 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()
{
@Override
public 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; //定义了一个线程...为实现第六部分定义了一个对象... @Override
public 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 { @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.web_circle);
} @Override
public 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); }
@Override
public 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" >
<LinearLayout
android: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" > <TextView
android: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" /> <TextView
android: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> <FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content" > <com.circle.cil_212_app.CircleMenuLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/turnplate_bg_right" > <RelativeLayout
android:id="@id/id_circle_menu_item_center"
android:layout_width="wrap_content"
android:layout_height="wrap_content" > <ImageView
android:layout_width="104.0dip"
android:layout_height="104.0dip"
android:layout_centerInParent="true"
android:background="@drawable/turnplate_center_unlogin" /> <!-- <ImageView
android: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(6):XML方式 & PopUp菜单

    目录(?)[-] 利用XML创建菜单 XML的有关属性 onClick事件 Pop-up菜单 利用XML创建菜单 在代码中对每个菜单项进行设置,繁琐且修改不灵活,不能适配多国语言的要求,可以利用资源进 ...

  2. 【转】 Pro Android学习笔记(三三):Menu(4):Alternative菜单

    目录(?)[-] 什么是Alternative menu替代菜单 小例子说明 Alternative menu代码 关于Category和规范代码写法 关于flags 多个匹配的itemId等参数 什 ...

  3. Pro Android学习笔记 ActionBar(1):Home图标区

     Pro Android学习笔记(四八):ActionBar(1):Home图标区 2013年03月10日 ⁄ 综合 ⁄ 共 3256字 ⁄ 字号 小 中 大 ⁄ 评论关闭 ActionBar在A ...

  4. 【转】 Pro Android学习笔记(五二):ActionBar(5):list模式

    可以在action bar中加入spinner的下来菜单,有关spinner,可以参考Pro Android学习笔记(二十):用户界面和控制(8):GridView和Spinner. list的样式和 ...

  5. 【转】Pro Android学习笔记(三十):Menu(1):了解Menu

    目录(?)[-] 创建Menu MenuItem的属性itemId MenuItem的属性groupId MenuItem的属性orderId MenuItem的属性可选属性 Menu触发 onOpt ...

  6. 【转】Pro Android学习笔记(十):了解Intent(上)

    目录(?)[-] Intent基本含义 系统的Intent Android引入了Intent的概念来唤起components,component包括:1.Activity(UI元件) 2.Servic ...

  7. Android学习笔记(一)

    目录 Android学习笔记(一) 一.JDK.Android SDK 二.部分项目结构 三.字符串引用 四.外层build.gradle详解 五.app->build.gradle详解 六.日 ...

  8. Android 学习笔记之Volley(七)实现Json数据加载和解析...

    学习内容: 1.使用Volley实现异步加载Json数据...   Volley的第二大请求就是通过发送请求异步实现Json数据信息的加载,加载Json数据有两种方式,一种是通过获取Json对象,然后 ...

  9. Android学习笔记进阶之在图片上涂鸦(能清屏)

    Android学习笔记进阶之在图片上涂鸦(能清屏) 2013-11-19 10:52 117人阅读 评论(0) 收藏 举报 HandWritingActivity.java package xiaos ...

随机推荐

  1. Java 多线程(2)-Executor

    public interface Executor{ void executor(Runnable command); } 如上所写,Executor实际上是一个接口,他提供了唯一的接口方法execu ...

  2. iOS 7.1 UITableView添加footerView 后 最后一行分割线无法显示

    今天用故事版 遇到个奇怪的问题: 我要用 tbView(tableView)展示写信息.最后一行我要显示些文案什么的.考虑用 footerView ,开心coding ..,show下 哪里有些不对吧 ...

  3. Scala 深入浅出实战经典 第46讲: ClassTag 、Manifest、ClasMainifest TagType实战

    王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-64讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...

  4. c++中typename和class的区别介绍

    "typename"是一个C++程序设计语言中的关键字.相当用于泛型编程时是另一术语"class"的同义词.这个关键字用于指出模板声明(或定义)中的非独立名称( ...

  5. 将w3cplus网站中的文章页面提取并导出为pdf文档

    最近在看一些关于CSS3方面的知识,主要是平时看到网页中有很多用CSS3实现的很炫的效果,所以就打算系统的学习一下.在网上找到很多的文章,但都没有一个好的整理性,比较凌乱.昨天看到w3cplus网站中 ...

  6. 【规范】javascript 变量命名规则

    javascript 有三大经典的变量命名法:匈牙利命名法,驼峰式命名法和帕斯卡命名法.今天主要介绍下这三种命名方式. 匈牙利命名法 语法 变量名 = 类型 + 对象描述 类型指变量的类型 对象描述指 ...

  7. 阿里云 Redis 服务遇到的问题

    ERR unknown command eval 说明: 执行当前 Web 请求期间,出现未经处理的异常.请检查堆栈跟踪信息,以了解有关该错误以及代码中导致错误的出处的详细信息. 异常详细信息: St ...

  8. 处理XML

    虽然被JSON抢了风头,但XML仍旧非常重要.看得见的,看不见的,XML在很广泛的领域对我们发挥着影响. 修改XML文件,是我经常遇到的事情.方式从手动在Visual Studio或者Notepad+ ...

  9. SQL Server 几种锁的区别

    NOLOCK(不加锁)    此选项被选中时,SQL  Server  在读取或修改数据时不加任何锁.  在这种情况下,用户有可能读取到未完成事务(Uncommited  Transaction)或回 ...

  10. Source Insight 使用

    1.括号配对高亮:“在前括号左侧,后括号左侧” 双击鼠标左键,可以选定匹配括号和其中内容(<>,(),L{R},[]之间) 2.让{ 和 } 不缩进:Options -> Docum ...