版本号:1.0
日期:2014.4.22
版权:© 2014 kince 转载注明出处

  这是仿Path2.0UI的一个demo的截图,我最早是在农民伯伯的这篇博客中看到的【Andorid X 项目笔记】开源项目使用(6),他说这个程序是反编译Path的。可是这次我特地看了一下代码,发现事实上不是这种。原帖地址应该是这个:

mod=viewthread&tid=187725" style="font-family: Tahoma; text-align: -webkit-auto;font-size:14px; ">http://www.eoeandroid.com/forum.php?mod=viewthread&tid=187725,作者使用的是github上的一个开源项目:Android-ScrollBarPanel,它实现的效果例如以下:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd2FuZ2ppbnl1NTAx/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" />

  已经非常接近Path的效果了。还有墨迹天气的实景也是使用了这种效果:
  并且,墨迹天气用的也是这个开源项目。效果什么基本都没改。所以以下重点说一下这个开源项目的实现。

在看它的代码之前先来分析一下这个效果该怎样实现,它就是在滚动栏(scrollbar)的旁边动态显示一个View。这个View里面显示的内容会随着滚动栏的位置变化而变化。一般像带滑动效果的容器控制都会有滚动栏,比方ScrollView、ListView、GeidView等。那这个滚动栏究竟是什么呢?它是一个View的属性,该属性是继承view的, 目的设置滚动栏显示。有以下设置none(隐藏)。horizontal(水平),vertical (垂直)。并非全部的view设置就有效果。 LinearLayout 设置也没有效果。 要想在超过一屏时拖动效果,在最外层加上ScrollView。并且能够自己定义滚动栏的样式和位置。但Path用的并非自己定义的滚动栏,它是在滚动栏旁边加的View。如图:

  若是在滚动栏的旁边加入显示View,首先须要获取滚动栏的位置,当在滑动的时候在显示滚动栏的同一时候也让加入的View显示出来,也就是说它和滚动栏的显示是同步的。

那究竟怎样实现呢。带着这些疑问看一下源代码:

package com.dafruits.android.library.widgets;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.AnimationUtils;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ListView; import com.dafruits.android.library.R; public class ExtendedListView extends ListView implements OnScrollListener { public static interface OnPositionChangedListener { public void onPositionChanged(ExtendedListView listView, int position, View scrollBarPanel); } private OnScrollListener mOnScrollListener = null; private View mScrollBarPanel = null;
private int mScrollBarPanelPosition = 0; private OnPositionChangedListener mPositionChangedListener;
private int mLastPosition = -1; private Animation mInAnimation = null;
private Animation mOutAnimation = null; private final Handler mHandler = new Handler(); private final Runnable mScrollBarPanelFadeRunnable = new Runnable() { @Override
public void run() {
if (mOutAnimation != null) {
mScrollBarPanel.startAnimation(mOutAnimation);
}
}
}; /*
* keep track of Measure Spec
*/
private int mWidthMeasureSpec;
private int mHeightMeasureSpec; public ExtendedListView(Context context) {
this(context, null);
} public ExtendedListView(Context context, AttributeSet attrs) {
this(context, attrs, android.R.attr.listViewStyle);
} public ExtendedListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle); super.setOnScrollListener(this); final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ExtendedListView);
final int scrollBarPanelLayoutId = a.getResourceId(R.styleable.ExtendedListView_scrollBarPanel, -1);
final int scrollBarPanelInAnimation = a.getResourceId(R.styleable.ExtendedListView_scrollBarPanelInAnimation, R.anim.in_animation);
final int scrollBarPanelOutAnimation = a.getResourceId(R.styleable.ExtendedListView_scrollBarPanelOutAnimation, R.anim.out_animation);
a.recycle(); if (scrollBarPanelLayoutId != -1) {
setScrollBarPanel(scrollBarPanelLayoutId);
} final int scrollBarPanelFadeDuration = ViewConfiguration.getScrollBarFadeDuration(); if (scrollBarPanelInAnimation > 0) {
mInAnimation = AnimationUtils.loadAnimation(getContext(), scrollBarPanelInAnimation);
} if (scrollBarPanelOutAnimation > 0) {
mOutAnimation = AnimationUtils.loadAnimation(getContext(), scrollBarPanelOutAnimation);
mOutAnimation.setDuration(scrollBarPanelFadeDuration); mOutAnimation.setAnimationListener(new AnimationListener() { @Override
public void onAnimationStart(Animation animation) {
} @Override
public void onAnimationRepeat(Animation animation) { } @Override
public void onAnimationEnd(Animation animation) {
if (mScrollBarPanel != null) {
mScrollBarPanel.setVisibility(View.GONE);
}
}
});
}
} @Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if (mOnScrollListener != null) {
mOnScrollListener.onScrollStateChanged(view, scrollState);
}
} @Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if (null != mPositionChangedListener && null != mScrollBarPanel) { // Don't do anything if there is no itemviews
if (totalItemCount > 0) {
/*
* from android source code (ScrollBarDrawable.java)
*/
final int thickness = getVerticalScrollbarWidth();
int height = Math.round((float) getMeasuredHeight() * computeVerticalScrollExtent() / computeVerticalScrollRange());
int thumbOffset = Math.round((float) (getMeasuredHeight() - height) * computeVerticalScrollOffset() / (computeVerticalScrollRange() - computeVerticalScrollExtent()));
final int minLength = thickness * 2;
if (height < minLength) {
height = minLength;
}
thumbOffset += height / 2; /*
* find out which itemviews the center of thumb is on
*/
final int count = getChildCount();
for (int i = 0; i < count; ++i) {
final View childView = getChildAt(i);
if (childView != null) {
if (thumbOffset > childView.getTop() && thumbOffset < childView.getBottom()) {
/*
* we have our candidate
*/
if (mLastPosition != firstVisibleItem + i) {
mLastPosition = firstVisibleItem + i; /*
* inform the position of the panel has changed
*/
mPositionChangedListener.onPositionChanged(this, mLastPosition, mScrollBarPanel); /*
* measure panel right now since it has just changed
*
* INFO: quick hack to handle TextView has ScrollBarPanel (to wrap text in
* case TextView's content has changed)
*/
measureChild(mScrollBarPanel, mWidthMeasureSpec, mHeightMeasureSpec);
}
break;
}
}
} /*
* update panel position
*/
mScrollBarPanelPosition = thumbOffset - mScrollBarPanel.getMeasuredHeight() / 2;
final int x = getMeasuredWidth() - mScrollBarPanel.getMeasuredWidth() - getVerticalScrollbarWidth();
mScrollBarPanel.layout(x, mScrollBarPanelPosition, x + mScrollBarPanel.getMeasuredWidth(),
mScrollBarPanelPosition + mScrollBarPanel.getMeasuredHeight());
}
} if (mOnScrollListener != null) {
mOnScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
}
} public void setOnPositionChangedListener(OnPositionChangedListener onPositionChangedListener) {
mPositionChangedListener = onPositionChangedListener;
} @Override
public void setOnScrollListener(OnScrollListener onScrollListener) {
mOnScrollListener = onScrollListener;
} public void setScrollBarPanel(View scrollBarPanel) {
mScrollBarPanel = scrollBarPanel;
mScrollBarPanel.setVisibility(View.GONE);
requestLayout();
} public void setScrollBarPanel(int resId) {
setScrollBarPanel(LayoutInflater.from(getContext()).inflate(resId, this, false));
} public View getScrollBarPanel() {
return mScrollBarPanel;
} @Override
protected boolean awakenScrollBars(int startDelay, boolean invalidate) {
final boolean isAnimationPlayed = super.awakenScrollBars(startDelay, invalidate); if (isAnimationPlayed == true && mScrollBarPanel != null) {
if (mScrollBarPanel.getVisibility() == View.GONE) {
mScrollBarPanel.setVisibility(View.VISIBLE);
if (mInAnimation != null) {
mScrollBarPanel.startAnimation(mInAnimation);
}
} mHandler.removeCallbacks(mScrollBarPanelFadeRunnable);
mHandler.postAtTime(mScrollBarPanelFadeRunnable, AnimationUtils.currentAnimationTimeMillis() + startDelay);
} return isAnimationPlayed;
} @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec); if (mScrollBarPanel != null && getAdapter() != null) {
mWidthMeasureSpec = widthMeasureSpec;
mHeightMeasureSpec = heightMeasureSpec;
measureChild(mScrollBarPanel, widthMeasureSpec, heightMeasureSpec);
}
} @Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom); if (mScrollBarPanel != null) {
final int x = getMeasuredWidth() - mScrollBarPanel.getMeasuredWidth() - getVerticalScrollbarWidth();
mScrollBarPanel.layout(x, mScrollBarPanelPosition, x + mScrollBarPanel.getMeasuredWidth(),
mScrollBarPanelPosition + mScrollBarPanel.getMeasuredHeight());
}
} @Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas); if (mScrollBarPanel != null && mScrollBarPanel.getVisibility() == View.VISIBLE) {
drawChild(canvas, mScrollBarPanel, getDrawingTime());
}
} @Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow(); mHandler.removeCallbacks(mScrollBarPanelFadeRunnable);
}
}

通过阅读源代码发现,这是一个自己定义的ListView,并且继承了OnScrollListener接口。这个接口是在AbsListView.java里面定义的。主要是负责滑动事件的处理,它的代码例如以下:

 /**
* Interface definition for a callback to be invoked when the list or grid
* has been scrolled.
*/
public interface OnScrollListener { /**
* The view is not scrolling. Note navigating the list using the trackball counts as
* being in the idle state since these transitions are not animated.
*/
public static int SCROLL_STATE_IDLE = 0; /**
* The user is scrolling using touch, and their finger is still on the screen
*/
public static int SCROLL_STATE_TOUCH_SCROLL = 1; /**
* The user had previously been scrolling using touch and had performed a fling. The
* animation is now coasting to a stop
*/
public static int SCROLL_STATE_FLING = 2; /**
* Callback method to be invoked while the list view or grid view is being scrolled. If the
* view is being scrolled, this method will be called before the next frame of the scroll is
* rendered. In particular, it will be called before any calls to
* {@link Adapter#getView(int, View, ViewGroup)}.
*
* @param view The view whose scroll state is being reported
*
* @param scrollState The current scroll state. One of {@link #SCROLL_STATE_IDLE},
* {@link #SCROLL_STATE_TOUCH_SCROLL} or {@link #SCROLL_STATE_IDLE}.
*/
public void onScrollStateChanged(AbsListView view, int scrollState); /**
* Callback method to be invoked when the list or grid has been scrolled. This will be
* called after the scroll has completed
* @param view The view whose scroll state is being reported
* @param firstVisibleItem the index of the first visible cell (ignore if
* visibleItemCount == 0)
* @param visibleItemCount the number of visible cells
* @param totalItemCount the number of items in the list adaptor
*/
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
int totalItemCount);
}

OnScrollListener定义了三个常量。分别表示当屏幕停止滚动时为0;当屏幕滚动且用户使用的触碰或手指还在屏幕上时为1;由于用户的操作。屏幕产生惯性滑动时为2。详细解释例如以下:

new OnScrollListener() {
boolean isLastRow = false; @Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
//滚动时一直回调,直到停止滚动时才停止回调。单击时回调一次。
//firstVisibleItem:当前能看见的第一个列表项ID(从0開始)
//visibleItemCount:当前能看见的列表项个数(小半个也算)
//totalItemCount:列表项共数 //推断是否滚到最后一行
if (firstVisibleItem + visibleItemCount == totalItemCount && totalItemCount > 0) {
isLastRow = true;
}
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
//正在滚动时回调,回调2-3次,手指没抛则回调2次。 scrollState = 2的这次不回调
//回调顺序例如以下
//第1次:scrollState = SCROLL_STATE_TOUCH_SCROLL(1) 正在滚动
//第2次:scrollState = SCROLL_STATE_FLING(2) 手指做了抛的动作(手指离开屏幕前,用力滑了一下)
//第3次:scrollState = SCROLL_STATE_IDLE(0) 停止滚动
//当屏幕停止滚动时为0;当屏幕滚动且用户使用的触碰或手指还在屏幕上时为1。
//由于用户的操作,屏幕产生惯性滑动时为2 //当滚到最后一行且停止滚动时,运行载入
if (isLastRow && scrollState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE) {
//载入元素
...... isLastRow = false;
}
}
}

了解完OnScrollListener这个接口再回头看一下代码,首先定义了一个回调:

   public static interface OnPositionChangedListener {

          public void onPositionChanged(ExtendedListView listView, int position,
View scrollBarPanel); }
  这个用来在Activity中设置监听事件的,Activity的代码例如以下:
package com.dafruits.android.samples;

import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView; import com.dafruits.android.library.widgets.ExtendedListView;
import com.dafruits.android.library.widgets.ExtendedListView.OnPositionChangedListener; public class DemoScrollBarPanelActivity extends Activity implements OnPositionChangedListener { private ExtendedListView mListView; @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); setContentView(R.layout.main); mListView = (ExtendedListView) findViewById(android.R.id.list);
mListView.setAdapter(new DummyAdapter());
mListView.setCacheColorHint(Color.TRANSPARENT);
mListView.setOnPositionChangedListener(this);
} private class DummyAdapter extends BaseAdapter { private int mNumDummies = 100; @Override
public int getCount() {
return mNumDummies;
} @Override
public Object getItem(int position) {
return position;
} @Override
public long getItemId(int position) {
return position;
} @Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = LayoutInflater.from(DemoScrollBarPanelActivity.this).inflate(R.layout.list_item, parent,
false);
} TextView textView = (TextView) convertView;
textView.setText("" + position); return convertView;
}
} @Override
public void onPositionChanged(ExtendedListView listView, int firstVisiblePosition, View scrollBarPanel) {
((TextView) scrollBarPanel).setText("Position " + firstVisiblePosition);
}
}
  接着看一下第三个构造方法,由于这个自己定义的ListView定义了自己的属性。所以须要从attrs文件里来取出这些属性。自己定义的属性包含三个部分,一是在ListView滑动时弹出的View,二是这个View弹出时的动画,三是这个View消失时的动画。然后開始设置这个弹出的View:
  if (scrollBarPanelLayoutId != -1) {
setScrollBarPanel(scrollBarPanelLayoutId);
}

看一下设置的方法。

  public void setScrollBarPanel(View scrollBarPanel) {
mScrollBarPanel = scrollBarPanel;
mScrollBarPanel.setVisibility(View.GONE);
requestLayout();
} public void setScrollBarPanel(int resId) {
setScrollBarPanel(LayoutInflater.from(getContext()).inflate(resId,
this, false));
}

  先是调用以下这种方法。从xml文件里载入弹出View的布局,在这个地方须要说一下假设自己定义的View不须要手动绘制的话,那么就能够使用LayoutInflater去在xml中载入一个已经配置好的视图,本例中就是使用这个方式。这样mScrollBarPanel就储存了弹出的View。然后设置为不可见。使用requestLayout()刷新一下视图。再接着就是载入两个弹出的动画。特别的。在mOutAnimation动画中设置了监听器,在动画结束的时候设置弹出的View不可见。

  回到第三个构造方法中,在第二行设置了super.setOnScrollListener(this),这种方法是效果实现的关键。为什么这么说。先看一下它的源代码。

它是在AbsListView中定义的。

   /**
* Set the listener that will receive notifications every time the list scrolls.
*
* @param l the scroll listener
*/
public void setOnScrollListener(OnScrollListener l) {
mOnScrollListener = l;
invokeOnItemScrollListener();
}

设置这种方法后,会传递一个OnScrollListener对象给mOnScrollListener,然后调用invokeOnItemScrollListener()方法,它的代码例如以下:

 /**
* Notify our scroll listener (if there is one) of a change in scroll state
*/
void invokeOnItemScrollListener() {
if (mFastScroller != null) {
mFastScroller.onScroll(this, mFirstPosition, getChildCount(), mItemCount);
}
if (mOnScrollListener != null) {
mOnScrollListener.onScroll(this, mFirstPosition, getChildCount(), mItemCount);
}
onScrollChanged(0, 0, 0, 0); // dummy values, View's implementation does not use these.
}

假设mOnScrollListener不为空的话,就调用mOnScrollListener的onScroll方法。而onScroll方法正是OnScrollListener接口定义的抽象方法,由于我们在ListView中继承了OnScrollListener接口,重载了onScroll方法,所以将会调用我们自己实现的onScroll方法。就是这样一个流程。

  然后看一下onScroll方法的实现,
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
Log.i("onScroll", "onScroll");
if (null != mPositionChangedListener && null != mScrollBarPanel) { // Don't do anything if there is no itemviews
if (totalItemCount > 0) {
/*
* from android source code (ScrollBarDrawable.java)
*/
final int thickness = getVerticalScrollbarWidth();
int height = Math.round((float) getMeasuredHeight()
* computeVerticalScrollExtent()
/ computeVerticalScrollRange());
int thumbOffset = Math
.round((float) (getMeasuredHeight() - height)
* computeVerticalScrollOffset()
/ (computeVerticalScrollRange() - computeVerticalScrollExtent()));
final int minLength = thickness * 2;
if (height < minLength) {
height = minLength;
}
thumbOffset += height / 2; /*
* find out which itemviews the center of thumb is on
*/
final int count = getChildCount();
for (int i = 0; i < count; ++i) {
final View childView = getChildAt(i);
if (childView != null) {
if (thumbOffset > childView.getTop()
&& thumbOffset < childView.getBottom()) {
/*
* we have our candidate
*/
if (mLastPosition != firstVisibleItem + i) {
mLastPosition = firstVisibleItem + i; /*
* inform the position of the panel has changed
*/
mPositionChangedListener.onPositionChanged(
this, mLastPosition, mScrollBarPanel); /*
* measure panel right now since it has just
* changed
*
* INFO: quick hack to handle TextView has
* ScrollBarPanel (to wrap text in case
* TextView's content has changed)
*/
measureChild(mScrollBarPanel,
mWidthMeasureSpec, mHeightMeasureSpec);
}
break;
}
}
} /*
* update panel position
*/
mScrollBarPanelPosition = thumbOffset
- mScrollBarPanel.getMeasuredHeight() / 2;
final int x = getMeasuredWidth()
- mScrollBarPanel.getMeasuredWidth()
- getVerticalScrollbarWidth();
mScrollBarPanel.layout(
x,
mScrollBarPanelPosition,
x + mScrollBarPanel.getMeasuredWidth(),
mScrollBarPanelPosition
+ mScrollBarPanel.getMeasuredHeight());
}
} if (mOnScrollListener != null) {
mOnScrollListener.onScroll(view, firstVisibleItem,
visibleItemCount, totalItemCount);
}
}
  上面已经说到。这个onScroll是随着滑动而一直调用的,而我们的需求就是在滑动的时候弹出一个View来。所以这种方法正是处理问题的关键位置。能够在这里绘制弹出View的视图。从上面的代码也能够看出,就是在这里进行弹出View大小的计算以及位置的设定等。
   最后就是之前说的自己定义ViewGroup的问题了。重载onMeasure()、onLayout()、ondispatchDraw()方法了,这个在本例中也是有所体现的,只是都比較简单,相信都看得懂。

可是这几个方法都是在View初始化的时候调用的,并且仅仅是调用一次。这样并不适合动态的绘制视图。所以这也是为什么本样例继承了OnScrollListener,然后在其onScroll方法中去绘制视图。由于onScroll方法在滑动的时候会调用,所以在滑动的时候就会绘制视图了。

因此也能够看出本例採用的是动态画图的方式,不是显示隐藏的方式。

   

Android Path Time ScrollBar(Path 时间轴)的更多相关文章

  1. android项目解刨之时间轴

    近期开发的app中要用到时间轴这东西.须要实现的效果例如以下: 想想这个东西应该能够用listview实现吧. 然后近期就模拟着去写了: 首先写  listview的item的布局: listview ...

  2. Android 时间轴

    最近开发的app中要用到时间轴这东西,需要实现的效果如下: 想想这个东西应该可以用listview实现吧.然后最近就模拟着去写了: 首先写  listview的item的布局: listview_it ...

  3. android 简易时间轴(实质是ListView)

    ListView的应用 1.在很多时候是要用到时间轴的,有些处理的时间轴比较复杂,这里就给出一个比较简单的时间轴,其实就是ListView里面的Item的设计. 直接上代码: ListView,ite ...

  4. Android 类似时间轴的实现

    想要实现图片中的的时间轴的效果,设定了三种颜色,但是出来的只有一个黑色,还不是设定好的,而且长度很长的话不能滚动,下面上代码: 布局文件: <LinearLayout xmlns:android ...

  5. Android自定义指示器时间轴

    指示器时间轴在外卖.购物类的APP里会经常用到,效果大概就像下面这样,看了网上很多文章,大都是自己绘制,太麻烦,其实通过ListView就可以实现.   在Activity关联的布局文件activit ...

  6. Android实训案例(三)——实现时间轴效果的ListView,加入本地存储,实现恋爱日记的效果!

    Android实训案例(三)--实现时间轴效果的ListView,加入本地存储,实现恋爱日记的效果! 感叹离春节将至,也同时感叹时间不等人,一年又一年,可是我依然是android道路上的小菜鸟,这篇讲 ...

  7. android 开发 View _10_ Path之基本操作

    转载地址:http://www.gcssloop.com/customview/Path_Basic/ 安卓自定义View进阶-Path之基本操作 在上一篇Canvas之图片文字中我们了解了如何使用C ...

  8. 【已解决】mac上appium报错:“Could not find aapt Please set the ANDROID_HOME environment variable with the Android SDK root directory path”

    按照网上教程配置完appium环境后,真机跑自动化过程,遇到如下报错: appium报错如下: [ADB] Checking whether aapt is present [ADB] The AND ...

  9. Android 时间轴的实现

    时间轴 时间轴,顾名思义就是将发生的事件按照时间顺序罗列起来,给用户带来一种更加直观的体验.京东和淘宝的物流顺序就是一个时间轴(如图),想必大家都不陌生. 时间轴的初探 初次见到这种UI,感觉整个布局 ...

  10. Android实现时间轴

    昨天群里有讨论时间轴的项目,没有接触过,以为非常吊,研究之后才知道表面都是忽悠人的,使用listview就能实现了,也没有什么新奇的东西 废话少说,直接上图 图片和文字都能够私人订制 没什么好说的,直 ...

随机推荐

  1. idea心得

    概述 Intellij IDEA真是越用越觉得它强大,它总是在我们写代码的时候,不时给我们来个小惊喜.出于对Intellij IDEA的喜爱,我决定写一个与其相关的专栏或者系列,把一些好用的Intel ...

  2. MyEclipse文本对比界面样式修改

    MyEclipse刚安装好,使用文件对比的时候,发现两边的对比颜色非常浅,不同的地方不容易发现,可以通过以下配置将显示颜色调深一点. 配置 效果

  3. Es官方文档整理-3.Doc Values和FieldData

    Es官方文档整理-3.Doc Values和FieldData 1.Doc Values 聚合使用一个叫Doc Values的数据结构.Doc Values使聚合更快.更高效且内存友好. Doc Va ...

  4. LeetCode517. Super Washing Machines

    You have n super washing machines on a line. Initially, each washing machine has some dresses or is ...

  5. hdu 5137 去掉一个点 使得最短路最大(2014广州现场赛 K题)

    题意:从2~n-1这几个点中任意去掉一个点,使得从1到n的最短路径最大,如果任意去掉一个点1~n无通路输出Inf. Sample Input4 51 2 31 3 71 4 502 3 43 4 23 ...

  6. day6作业--游戏人生

    本节作业: 熟练使用类和模块,写一个交互性强.有冲突的程序. 思路: 1.各个模块之间的调用关系,如何使用类,各种方法的使用上面: 2.学了类,以为能用来解决所有问题,东西都要写在类里面: 3.下面自 ...

  7. 【POJ】2043.Area of Polygons

    原题戳这里 开始一小段时间的POJ计算几何练习计划(估计很快就会被恶心回去) 题解 用一条平行于y轴的扫描线,计算两条扫描线之间多少格子被覆盖了 精度可tm变态了,可能是因为题目要求的关系吧,需要上取 ...

  8. Kylin启动时错误:Failed to find metadata store by url: kylin_metadata@hbase 解决办法

    一.问题背景 安装kylin后使用命令 $ kylin.sh start 后出现Failed to find metadata store by url: kylin_metadata@hbase的错 ...

  9. Cygwin镜像使用

    前言:Cygwin是一个在windows平台上运行的类UNIX模拟环境,可以自己安装想用的插件 Cygwin镜像使用帮助 收录架构 x86 x86_64 收录版本 所有版本 更新时间 每12小时更新一 ...

  10. C++ shared_ptr

    晕晕乎乎,其他的再补充 1.shared_ptr 主要是为了方便管理内存而存在的,C++程序中不会再出现new 和 delete,内存的分配和析构全部由shared_ptr进行管理 2.当程序中对某个 ...