前言:

忙完了结婚乐APP的开发,终于可以花一定的时间放在博客上了.好了,废话不多说,今天我们要带来的效果是苹果版本的QQ下拉刷新.首先看一下目标效果以及demo效果:

    

因为此效果实现的步骤较多,所以今天博主要实现以上效果的第一步——打造一个通用的下拉刷新控件,具体效果如下:

GIF图片比较大,还希望读者能耐心等待一下下从效果图中可以看出,我们的下拉刷新的滑动还是很流畅的,可能大多数开发者用的是XListview或者PullToRefresh控件,在此博主本着能造轮子就造轮子的原则,打算自己打造一个自己喜欢的通用下拉刷新控件;下面就由博主来说明一下此控件是如何完成的:

一、自定义LinearLayout,手动加入下拉刷新布局

首先我们得准备好我们的刷新头部的布局,布局稍微复杂一点,分两层.一个是正在刷新时候的布局,一个是刷新完成的布局,在这里我用的RelativeLayout来布局,当然啦,除了RelativeLayout之外,FrameLayout和Linearlayout都可以直接或者间接的实现布局,下面上布局文件代码:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="60dp"> <LinearLayout
android:id="@+id/ll_ok"
android:layout_width="match_parent"
android:layout_height="60dp"
android:gravity="center"
android:orientation="horizontal"
android:visibility="gone"> <ImageView
android:id="@+id/iv_ok"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/pull_ok" /> <TextView
android:id="@+id/tv_ok"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginLeft="10dp"
android:gravity="center"
android:text="刷新成功"
android:textSize="14sp"
android:textAppearance="?android:attr/textAppearance"
android:textColor="#999999"
android:textStyle="bold" />
</LinearLayout> <LinearLayout
android:id="@+id/ll_refresh"
android:layout_width="match_parent"
android:layout_height="60dp"
android:gravity="center"> <ProgressBar
android:id="@+id/pb_refresh"
style="?android:attr/progressBarStyleSmall"
android:layout_width="15dp"
android:layout_height="15dp"
android:layout_centerVertical="true"
android:layout_gravity="center"
android:indeterminate="true"
android:indeterminateDrawable="@drawable/pulling"
android:visibility="gone" /> <ImageView
android:id="@+id/iv_refresh"
android:layout_width="15dp"
android:layout_height="15dp"
android:layout_centerVertical="true"
android:src="@mipmap/pull_down"
android:layout_toRightOf="@+id/pb_refresh"
android:visibility="visible"/> <LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_toRightOf="@+id/iv_refresh"
android:gravity="center"
android:layout_marginLeft="10dp"
android:orientation="vertical"> <TextView
android:id="@+id/tv_tip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="下拉刷新"
android:singleLine="true"
android:textColor="#9D9D9B"
android:textSize="14sp"
android:textStyle="bold" /> <TextView
android:id="@+id/tv_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_marginTop="5dp"
android:text="上次刷新:"
android:singleLine="true"
android:textColor="#AEAEAC"
android:textSize="12sp" />
</LinearLayout>
</LinearLayout>
</RelativeLayout>

高度我们限制死60dp的高度,这个很重要,因为我们的刷新控件都是基于这个高度来计算的;

接下来,我们开始编写自定义View,首先我们继承LinearLayout然后在初始化中加入下拉刷新布局,并定义好一些重要参数:

/**
* 下拉刷新状态
*/
public static final int REFRESH_BY_PULLDOWN=0; /**
* 松开刷新状态
*/
public static final int REFRESH_BY_RELEASE=1;
/**
* 正在刷新状态
*/
public static final int REFRESHING=2;
/**
* 刷新成功状态
*/
public static final int REFRESHING_SUCCESS=3;
/**
* 刷新失败状态
*/
public static final int REFRESHING_FAILD=4; private View refreshView;
private int refreshTargetTop;
ObjectAnimator anim; //下拉刷新相关布局
LinearLayout ll_ok;
RelativeLayout ll_refresh;
ImageView iv_refresh, iv_ok;
TextView tv_tip, tv_time, tv_ok;
ProgressBar pb_refresh; private RefreshListener refreshListener;
private int lastY;
// 是否可刷新标记
private boolean isRefreshEnabled = true;
/**
* 刷新时间
*/
Calendar LastRefreshTime; int refreshState=REFRESH_BY_PULLDOWN; private Context mContext; public YPXRefreshView(Context context) {
this(context,null); } public YPXRefreshView(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
init();
} private void init() {
LastRefreshTime = Calendar.getInstance();
//刷新视图顶端的的view
refreshView = LayoutInflater.from(mContext).inflate(R.layout.layout_refresh_header, null);
initRefreshView();
refreshTargetTop =-ScreenUtils.dpToPx(getResources(),60);
LayoutParams lp = new LayoutParams(android.view.ViewGroup.LayoutParams.MATCH_PARENT, -refreshTargetTop);
lp.topMargin = refreshTargetTop;
lp.gravity = Gravity.CENTER;
addView(refreshView, lp);
anim = ObjectAnimator.ofFloat(refreshView, "ypx", 0.0f, 1.0f); } private void initRefreshView() {
ll_ok = (LinearLayout) refreshView.findViewById(R.id.ll_ok);
ll_refresh = (RelativeLayout) refreshView.findViewById(R.id.ll_refresh);
iv_refresh = (ImageView) refreshView.findViewById(R.id.iv_refresh);
iv_ok = (ImageView) refreshView.findViewById(R.id.iv_ok);
tv_tip = (TextView) refreshView.findViewById(R.id.tv_tip);
tv_time = (TextView) refreshView.findViewById(R.id.tv_time);
tv_ok = (TextView) refreshView.findViewById(R.id.tv_ok);
pb_refresh = (ProgressBar) refreshView.findViewById(R.id.pb_refresh);
} 

变量注释很详细,首先我们定义好下拉刷新的五种状态,分别代表了:下拉刷新、松开刷新、正在刷新、刷新成功、刷新失败五种样式.定义好我们的属性动画用作滑动动画,最后就是手动塞入我们的布局,代码很简单,下面上一下五中刷新状态对应的显示代码:

	/**
* 下拉刷新状态
*/
public void pullDownToRefresh() {
setRefreshState(REFRESH_BY_PULLDOWN);
ll_refresh.setVisibility(View.VISIBLE);
ll_ok.setVisibility(View.GONE);
tv_tip.setText("下拉刷新");
getRefreshTime();
RotateAnimation anim1 = new RotateAnimation(0, 180,
RotateAnimation.RELATIVE_TO_SELF, 0.5f,
RotateAnimation.RELATIVE_TO_SELF, 0.5f);
anim1.setDuration(300);
anim1.setFillAfter(true);
iv_refresh.clearAnimation();
iv_refresh.startAnimation(anim1);
pb_refresh.setVisibility(View.GONE);
iv_refresh.setVisibility(View.VISIBLE);
Log.i("下拉刷新","下拉刷新");
} /**
* 松开刷新状态
*/
public void pullUpToRefresh() {
setRefreshState(REFRESH_BY_RELEASE);
ll_refresh.setVisibility(View.VISIBLE);
ll_ok.setVisibility(View.GONE);
tv_tip.setText("松开刷新");
getRefreshTime();
iv_refresh.setImageDrawable(mContext.getResources().getDrawable(R.mipmap.pull_up));
RotateAnimation anim1 = new RotateAnimation(180, 0,
RotateAnimation.RELATIVE_TO_SELF, 0.5f,
RotateAnimation.RELATIVE_TO_SELF, 0.5f);
anim1.setDuration(300);
anim1.setFillAfter(true);
iv_refresh.clearAnimation();
iv_refresh.startAnimation(anim1);
pb_refresh.setVisibility(View.GONE);
iv_refresh.setVisibility(View.VISIBLE);
Log.i("松开刷新", "松开刷新");
} /**
* 正在刷新状态
*/
public void refreshing() {
setRefreshState(REFRESHING);
ll_refresh.setVisibility(View.VISIBLE);
ll_ok.setVisibility(View.GONE);
tv_tip.setText("正在刷新......");
getRefreshTime();
SPUtil.getInstance(mContext).setRefreshTime("MyMobile", "" +
DateUtils.getDate(DateUtils.MM_DD_HH_MM, System.currentTimeMillis()));
iv_refresh.clearAnimation();
iv_refresh.setVisibility(View.GONE);
pb_refresh.setVisibility(View.VISIBLE);
} /**
* 刷新成功状态
*/
public void refreshOK() {
setRefreshState(REFRESHING_SUCCESS);
ll_refresh.setVisibility(View.GONE);
ll_ok.setVisibility(View.VISIBLE);
tv_ok.setText("刷新成功");
iv_ok.setImageDrawable(getResources().getDrawable(R.mipmap.pull_ok));
} /**
* 刷新失败状态
*/
public void refreshFailed() {
setRefreshState(REFRESHING_FAILD);
ll_refresh.setVisibility(View.GONE);
ll_ok.setVisibility(View.VISIBLE);
tv_ok.setText("刷新失败");
iv_ok.setImageDrawable(getResources().getDrawable(R.mipmap.pull_failure));
} public void getRefreshTime(){
String time = SPUtil.getInstance(mContext).getRefreshTime("MyMobile");
if (time == null || "".equals(time)) {
tv_time.setVisibility(View.GONE);
tv_tip.setGravity(Gravity.CENTER | Gravity.LEFT);
ll_refresh.setGravity(Gravity.CENTER);
} else {
tv_time.setVisibility(View.VISIBLE);
ll_refresh.setGravity(Gravity.CENTER | Gravity.LEFT);
tv_time.setText("上次刷新:" + time);
tv_tip.setGravity(Gravity.BOTTOM|Gravity.LEFT);
}
} 

五种刷新状态对应五种不同的布局,简单明了!

二、下拉刷新的原理以及逻辑实现

首先我们介绍一下我们的刷新控件的原理:

  1. 监听滑动手势,使用LayoutParams的topMargin属性,动态改变topMargin的值达到滑动效果
  2. 通过滑动的高度判断当前的状态为哪种刷新状态
  3. 滑动结束,通过属性动画收回,回到初始样式

原理很简单,难点在于滑动手势的判断,废话不多说,先上一下滑动手势的代码:

	@Override
public boolean onTouchEvent(MotionEvent event) {
int y = (int) event.getRawY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//记录下y坐标
lastY = y;
break; case MotionEvent.ACTION_MOVE:
//y移动坐标
int m = y - lastY;
doMovement(m);
//记录下此刻y坐标
this.lastY = y;
break; case MotionEvent.ACTION_UP:
fling();
break;
}
return true;
} /**
* 下拉move事件处理
*
* @param moveY
*/
private void doMovement(int moveY) {
LayoutParams lp = (LayoutParams) refreshView.getLayoutParams();
float f1 = lp.topMargin;
int i = (int) (f1 + moveY * 0.4F);
if (i >= refreshTargetTop) {//如果下拉大于-60dp的高度,动态刷新子视图
lp.topMargin = i;
refreshView.setLayoutParams(lp);
refreshView.invalidate();
invalidate();
} if (lp.topMargin > 0) {//松开刷新状态
if(refreshState!=REFRESH_BY_RELEASE) {
pullUpToRefresh();
setRefreshState(REFRESH_BY_RELEASE);
}
} else {//下拉刷新状态
if(refreshState!=REFRESH_BY_PULLDOWN) {
setRefreshState(REFRESH_BY_PULLDOWN);
pullDownToRefresh();
} } }  

在这里我们设置了一个0.4的滑动阻力值,在手势滑动的时候,我们通过累加topMargin的值从而达到下拉的目的,如果下拉大于-60dp(即我们一开始设置的下拉刷新头部高度),则进入刷新状态,动态改变页面.同样原理我们可以判断滑动的高度是向下还是向上,从而进行下拉刷新和松开刷新的判断,在这里,博主在改变状态之前先加入判断,这样可以过滤掉很多不必要的点,从而使我们的刷新头部箭头动画流畅,不会导致状态混乱问题.

到目前为止,我们的刷新控件基本上已经可以下拉和上拉了,怎么样,原理是不是很简单,最后,我们来看一下核心代码,就是手指离开后的处理:

	/**
* up事件处理
*/
private void fling() {
LayoutParams lp = (LayoutParams) refreshView.getLayoutParams();
if (lp.topMargin > 0) {//拉到了触发可刷新事件
refresh();
} else {//收回
animRefreshView(lp.topMargin,refreshTargetTop,300);
}
} private void refresh() {
LayoutParams lp = (LayoutParams) this.refreshView.getLayoutParams();
int i = lp.topMargin;
animRefreshView(i,0,200);
refreshing();
if (refreshListener != null) {
refreshListener.onRefresh();
setRefreshState(REFRESHING); }
} /**
* 从开始位置滑动到结束位置
*
* @param startHeight
* @param endHeight
*/
public void animRefreshView(final int startHeight,final int endHeight,int duration){
anim.start();
anim.setDuration(duration);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
{
@Override
public void onAnimationUpdate(ValueAnimator animation){
float cVal = (Float) animation.getAnimatedValue();
LayoutParams lp = (LayoutParams)refreshView.getLayoutParams();
int k =startHeight+(int)(cVal*(endHeight-startHeight));
lp.topMargin = k;
refreshView.setLayoutParams(lp);
refreshView.invalidate();
invalidate();
}
}); }  

首先我们判断是否拉到了可触发刷新的高度,如果触发到了,即显示刷新状态,开启收回动画,因为当前用户很可能滑动到了超过刷新头的高度,这时候我们需要先收回到刷新的高度,即屏幕中显示正在刷新时候的样式.重点在于属性动画,其实这里博主之前没有使用属性动画,而是使用了Scroller滑动器来实现收回,虽然效果大差不差,但是滑动和收回的感觉总感觉不是那么的平滑,所以我首先想到的是用属性动画来收回,如果有不熟悉属性动画的朋友们,可以自行百度一下,使用很简单,有许多的动画监听和回调,它可以返回当前每一帧的offset,然后通过改变某个状态值来刷新整个页面,上面的addUpdateListener就是它的一个动画监听方法,如何得到我们的offset呢,很简单,只需要:

(Float) animation.getAnimatedValue()

即可,我们得到了偏移量之后就可以通过当前的高度和要回到的高度来动态设置topMargin,从而达到平滑的收回

到此,我们的刷新控件完成了四分之三,是不是觉得很简单呢!

三、刷新结束回调以及使用

当然了,因为我们的控件是下拉刷新,当然少不了刷新时候的回调,当刷新完成的时候,我们还要收回我们的刷新控件,代码很简单, 在这里,博主就直接贴代码了:

/**
* 刷新监听接口
*
* @author Nono
*/
public interface RefreshListener {
void onRefresh();
} /**
* 设置刷新回调
* @param listener
*/
public void setRefreshListener(RefreshListener listener) {
this.refreshListener = listener;
} /**
* 结束刷新事件
*/
public void finishRefresh(boolean isOK) {
LayoutParams lp = (LayoutParams) this.refreshView.getLayoutParams();
final int i = lp.topMargin;
if (isOK) {
refreshOK();
} else {
refreshFailed();
}
if(!anim.isRunning()&&refreshState!=REFRESHING){
new Handler().postDelayed(new Runnable(){
public void run() {
animRefreshView(i,refreshTargetTop,500);
}
}, 300);
}
} 

其中结束刷新事件中我们添加了延时,因为刷新成功或者失败要给用户一个反馈,所以我们需要延时0.5秒给用户.当我们的刷新完成后,只需要调用一下finishRefresh的方法,告诉控件滑动完成了,可以收回了.

使用很简单,因为我们是继承LinearLayout的,所以我们可以直接在布局中套在ScrollView上,使用的时候直接findViewByID绑定实现刷新方法即可下面贴上布局代码:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.ypx.jiehunle.ypx_bezierqqrefreshdemo.YPXRefreshView
android:id="@+id/refreshableView1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:visibility="visible"> <ScrollView
android:id="@+id/scrollView1"
android:layout_width="match_parent"
android:layout_height="match_parent"> <LinearLayout
android:id="@+id/ll_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
</LinearLayout>
</ScrollView>
</com.ypx.jiehunle.ypx_bezierqqrefreshdemo.YPXRefreshView>
</RelativeLayout> 

使用时的Activity代码:

public class MainActivity extends Activity {
YPXRefreshView refreshableView;
LinearLayout layout;
final int SUCCESS = 1;
final int FAILED = 0;
@SuppressLint("HandlerLeak")
Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case SUCCESS:
refreshableView.finishRefresh(true);
TextView textView = new TextView(MainActivity.this);
textView.setTextColor(Color.BLACK);
textView.setTextSize(20);
textView.setText("这是刷新的文本");
layout.addView(textView,0);
break;
case FAILED:
refreshableView.finishRefresh(false);
break;
default:
break;
}
};
}; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initData();
} private void initData() {
layout.removeAllViews();
for (int i = 0; i < 50; i++) {
final TextView textView = new TextView(MainActivity.this);
textView.setTextColor(Color.BLACK);
textView.setTextSize(20);
textView.setText("这是第" + i + "个文本");
textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(MainActivity.this,textView.getText(),0).show();
}
});
layout.addView(textView);
}
refreshableView.setRefreshListener(new YPXRefreshView.RefreshListener() { @Override
public void onRefresh() {
handler.postDelayed(new Runnable() { @Override
public void run() {
handler.sendEmptyMessage(SUCCESS); }
}, 500);
}
});
} private void initView() {
refreshableView = (YPXRefreshView) findViewById(R.id.refreshableView1);
layout = (LinearLayout) findViewById(R.id.ll_layout);
refreshableView.setRefreshEnabled(true);
} }

到这里,我们的刷新控件差不多完成了四分之三点五了,什么?还没有结束吗?当然,因为题目是打造通用的刷新控件,所以我们还有最后的环节!

四、事件拦截处理,达到通用效果

什么是通用,因为我们的控件是下拉刷新,所以应该支持所有的可滑动布局才对,这就涉及到了事件分发机制,还不了解的小伙伴们,可以自行去补习一下,这里博主就不赘述了.言归正传,既然我们要实现通用的刷新,必然要进行事件拦截,首先想到的就是重写ViewGroup的onInterceptTouchEvent方法了,那么我们研究一下什么时候需要拦截,什么时候不需要拦截呢?

其实很简单,当我们内部的滑动控件(ListView或ScrollView等)滑动到最顶部的时候,这时候我们需要触发下拉刷新,反之则不拦截,给子View自己处理,当然,在进行这一切的时候,我们要先判断是否存在子View以及判断子View是继承哪一种滑动布局,在这里博主只是简单的给个例子.所以如果要实现更多的滑动布局刷新,要添加判断,比如WebView、GridView、RecyclerView等,判断它们是否滑动到顶部即可,下面上博主的代码:

	@Override
public boolean onInterceptTouchEvent(MotionEvent e) {
if(!isRefreshEnabled){
return false;
}
int action = e.getAction();
int y = (int) e.getRawY();
switch (action) {
case MotionEvent.ACTION_DOWN:
lastY = y;
break; case MotionEvent.ACTION_MOVE:
if (y > lastY && canScroll()) {
return true;
}
//记录下此刻y坐标
this.lastY = y;
break;
}
return false;
} private boolean canScroll() {
View childView;
if (getChildCount() > 1) {
childView = this.getChildAt(1);
if (childView instanceof ListView) {
int top = ((ListView) childView).getChildAt(0).getTop();
int pad = ((ListView) childView).getListPaddingTop();
if ((Math.abs(top - pad)) < 3 &&
((ListView) childView).getFirstVisiblePosition() == 0) {
return true;
} else {
return false;
}
} else if (childView instanceof ScrollView) {
if (((ScrollView) childView).getScrollY() == 0) {
return true;
} else {
return false;
}
}else if (childView instanceof WebView) {
if (((WebView) childView).getScrollY() == 0) {
return true;
} else {
return false;
}
}else if (childView instanceof GridView) {
int top = ((GridView) childView).getChildAt(0).getTop();
int pad = ((GridView) childView).getListPaddingTop();
if ((Math.abs(top - pad)) < 3 &&
((GridView) childView).getFirstVisiblePosition() == 0) {
return true;
} else {
return false;
}
}else if (childView instanceof RecyclerView) {
RecyclerView.LayoutManager manager=((RecyclerView)childView).getLayoutManager();
int top=0;
if(manager instanceof LinearLayoutManager){
top = ((LinearLayoutManager)manager).findFirstVisibleItemPosition();
}else if(manager instanceof StaggeredGridLayoutManager){
top = ((StaggeredGridLayoutManager)manager).findFirstVisibleItemPositions(null)[0];
} if(((RecyclerView)childView).getChildAt(0).getY()==0 &&top==0){
return true;
} else {
return false;
} } }
return false;
} 

可以看到在canScroll函数中博主添加了很多判断, 这里只要判断了字View类型是否是滑动布局类型,其中包括,ScrollView、ListView、WebView、GridView、RecyclerView等,其中判断很简单,就是当前用户如果滑动到顶部,则交给外部下拉刷新处理,其余则放给字View处理.如果用户有自己自定义的滑动布局的话,可以在此基础上手动添加即可.到这里,总算完成了我们的刷新控件.

五、总结

总的来说,博主实现的下拉刷新还是非常简单易懂的,滑动流畅,使用简单,当然,这不是博主的目的,正如前言所说,博主的目的是为了实现仿IOS的QQ下拉刷新,本篇下拉刷新只是实现的第一步,下一步将会在下一篇博客(安卓仿IOS版QQ下拉刷新(二) ——二维贝塞尔远没有你想的那么复杂)中给大家带来一点关于贝塞尔曲线的实现,期待的朋友们欢迎支持一下博主哦~

感谢大家的支持,谢谢!

QQ:313930500

下载地址:http://download.csdn.net/detail/qq_16674697/9741375

转载请注明出处~谢谢~

Android仿苹果版QQ下拉刷新实现(一) ——打造简单平滑的通用下拉刷新控件的更多相关文章

  1. Android仿苹果版QQ下拉刷新实现(二) ——贝塞尔曲线开发"鼻涕"下拉粘连效果

    前言 接着上一期Android仿苹果版QQ下拉刷新实现(一) ——打造简单平滑的通用下拉刷新控件 的博客开始,同样,在开始前我们先来看一下目标效果: 下面上一下本章需要实现的效果图: 大家看到这个效果 ...

  2. swing实现QQ登录界面1.0( 实现了同一张图片只加载一次)、(以及实现简单的布局面板添加背景图片控件的标签控件和添加一个关闭按钮控件)

    swing实现QQ登录界面1.0( 实现了同一张图片只加载一次).(以及实现简单的布局面板添加背景图片控件的标签控件和添加一个关闭按钮控件) 代码思路分析: 1.(同一张图片仅仅需要加载一次就够了,下 ...

  3. [Android]仿新版QQ的tab下面拖拽标记为已读的效果

    以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/4182929.html 可拖拽的红点,(仿新版QQ,tab下面拖 ...

  4. Android仿微信QQ等实现锁屏消息提醒

    demo代码如下: import android.content.Intent; import android.os.Bundle; import android.support.v7.app.App ...

  5. bootstrap-table之通用方法( 时间控件,导出,动态下拉框, 表单验证 ,选中与获取信息)

    1.bootstrap-table 单击单行选中 $('#gzrwTable').on('click-row.bs.table', function(e, row, $element) { $('.s ...

  6. jquery on事件在IE8下失效的一种情况,及解决方法/bootstrap空间绑定控件事件不好用

    同事在复制bootstrap中的select控件之后,发现用$('.selectpicker').selectpicker();刷新下拉框控件不好使,后来发现是用原生js克隆的方法obj.cloneN ...

  7. Android 自定义View修炼-打造完美的自定义侧滑菜单/侧滑View控件

    一.概述 在App中,经常会出现侧滑菜单,侧滑滑出View等效果,虽然说Android有很多第三方开源库,但是实际上 咱们可以自己也写一个自定义的侧滑View控件,其实不难,主要涉及到以下几个要点: ...

  8. android屏幕适配的全攻略3-动态获取手机屏幕宽高及动态设置控件宽高

    1.获取手机屏幕宽高: DisplayMetrics dm = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetr ...

  9. 仿淘宝分页按钮效果简单美观易使用的JS分页控件

    分页按钮思想:  1.少于9页,全部显示  2.大于9页,1.2页显示,中间页码当前页为中心,前后各留两个页码  附件中有完整例子的压缩包下载.已更新到最新版本  先看效果图:  01输入框焦点效果  ...

随机推荐

  1. zuul学习

    1.zuul可以代理界面所需的后端服务,可以解决CORS(Cross-Origion-Resource-Sharing)和认证问题(authentication)问题 2.zuul是使用ribbon来 ...

  2. Hadoop生态圈-phoenix(HBase)的索引配置

    Hadoop生态圈-phoenix(HBase)的索引配置 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 创建索引是为了优化查询,我们可以在phoenix上配置索引方式. 一.修改 ...

  3. codevs 3160 最长公共子串

    3160 最长公共子串 http://codevs.cn/problem/3160/  时间限制: 2 s  空间限制: 128000 KB   题目描述 Description 给出两个由小写字母组 ...

  4. git 第一次关联远程仓库

    1.首先需要先git pull origin master 2.然后合并两个无关的仓库 git pull origin master --allow-unrelated-histories

  5. IEnumerable 与 IQueryable

    无论是在ado.net EF或者是在其他的Linq使用中,我们经常会碰到两个重要的静态类Enumerable.Queryable,他们在System.Linq命名空间下.那么这两个类是如何定义的,又是 ...

  6. 关于ES6 Class语法相关总结

    关于ES6,其实网上已经有很多的资料可供查询,教程可参考阮一峰大神的ES6入门,本文只是对Class这一语法做一个总结: 一.Class基本语法 constructor方法 constructor是类 ...

  7. C# XML序列化和反序列化

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.I ...

  8. Linux/Unix系统编程手册 第一章:历史和标准

    Unix的开发不受控于某一个厂商或者组织,是由诸多商业和非商业团体共同贡献进行演化的.这导致两个结果:一是Unix集多种特性于一身,二是由于参与者众多,随着时间推移,Unix实现方式逐渐趋于分裂. 由 ...

  9. 2016.5.16——leetcode:Rotate Array,Factorial Trailing Zeroe

    Rotate Array 本题目收获: 题目: Rotate an array of n elements to the right by k steps. For example, with n = ...

  10. equals方法变量和常量位置区别

    对于字符串比较,我的习惯用法是   变量.equals(常量) 比如:     a.equals("a") 今天看视频才知道变量在前面与后面有很大影响,正确的写法是常量放前面(可以 ...