更多Android高级架构进阶视频学习请点击:https://space.bilibili.com/474380680
本篇文章将从ViewPager来介绍常用View:
文章目录

一、简介

二、基本使用

  1. xml引用
  2. page布局
  3. 创建适配器
  4. 设置适配器
  5. 标题栏
    5.1. xml引用
    5.2. 重写PagerAdapter的getTitle()方法
  6. 翻页动画
    6.1. DepthPageTransformer
    6.2. ZoomOutPageTransformer
    6.3. 自定义动画
    6.4. 开源框架ViewPagerTransforms
  7. 翻页监听
    7.1. 设置方法
    7.2. 翻页监听接口
    7.3. 重写方法
    7.4. 使用

三、与Fragment结合使用

  1. 创建Fragment及相应的xml布局
  2. 给Viewpager设置数据和适配器

四、实现轮播图效果

  1. 特点
  2. 使用介绍
    2.1. 导包 + 权限
    2.2. xml引用
    2.3. 创建图片加载器
    2.4. 设置数据

五、实现画廊效果

  1. viewpager布局
  2. pager布局
  3. Adapter
  4. vp设置adapter
  5. 问题

一、简介

Viewpager,视图翻页工具,提供了多页面切换的效果。Android 3.0后引入的一个UI控件,位于v4包中。低版本使用需要导入v4包,但是现在我们开发的APP一般不再兼容3.0及以下的系统版本,另外现在大多数使用Android studio进行开发,默认导入v7包,v7包含了v4,所以不用导包,越来越方便了。

Viewpager使用起来就是我们通过创建adapter给它填充多个view,左右滑动时,切换不同的view。Google官方是建议我们使用Fragment来填充ViewPager的,这样 可以更加方便的生成每个Page,以及管理每个Page的生命周期。

Viewpager在Android开发中使用频率还是比较高的,下面开始一起学习吧!

二、基本使用

1. xml引用

<android.support.v4.view.ViewPager
android:id="@+id/vp"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v4.view.ViewPager>

2. page布局

<?xml version="1.0" encoding="utf-8"?>
<TextView
android:id="@+id/tv"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FAE8DA"
android:gravity="center"
android:text="Hello"
android:textSize="22sp">
</TextView>

3. 创建适配器

可直接new PagerAdapter,亦可创建它的子类

public class MyPagerAdapter extends PagerAdapter {
private Context mContext;
private List<String> mData; public MyPagerAdapter(Context context ,List<String> list) {
mContext = context;
mData = list;
} @Override
public int getCount() {
return mData.size();
} @Override
public Object instantiateItem(ViewGroup container, int position) {
View view = View.inflate(mContext, R.layout.item_base,null);
TextView tv = (TextView) view.findViewById(R.id.tv);
tv.setText(mData.get(position));
container.addView(view);
return view;
} @Override
public void destroyItem(ViewGroup container, int position, Object object) {
// super.destroyItem(container,position,object); 这一句要删除,否则报错
container.removeView((View)object);
} @Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
}

4. 设置适配器

private void setVp() {
List<String> list = new ArrayList<>();
for (int i = 0; i < 3; i++) {
list.add("第"+i+"个View");
} ViewPager vp = (ViewPager) findViewById(R.id.vp);
vp.setAdapter(new MyPagerAdapter(this,list));
}

效果:

 
20180228134517956.gif

5. 标题栏

给Viewpager设置标题栏有一下几种方式:

PagerTabStrip: 带有下划线
PagerTitleStrip: 不带下划线
TabLayout:5.0后推出
TabLayout的详细使用,可以看我的另一篇文章TabLayout。

下面介绍另外两个的使用方法,没什么区别:

1. xml引用

<android.support.v4.view.ViewPager
android:id="@+id/vp"
android:layout_width="match_parent"
android:layout_height="match_parent"> <android.support.v4.view.PagerTitleStrip
android:id="@+id/pager_title"
android:layout_width="match_parent"
android:layout_height="45dp"
android:background="@android:color/white"
android:layout_gravity="top"
android:textColor="#ff0000"
android:textSize="18sp"> </android.support.v4.view.PagerTitleStrip> </android.support.v4.view.ViewPager>

 <android.support.v4.view.ViewPager
android:id="@+id/vp"
android:layout_width="match_parent"
android:layout_height="match_parent"> <android.support.v4.view.PagerTabStrip
android:id="@+id/pager_tab"
android:layout_width="match_parent"
android:layout_height="45dp"
android:layout_gravity="top"
android:background="@android:color/white"
android:textColor="#ff0000">
</android.support.v4.view.PagerTabStrip> </android.support.v4.view.ViewPager>

  1. 重写PagerAdapter的getTitle()方法
 @Override
public CharSequence getPageTitle(int position) {
return mTitles[position];
}

这两种方法作为了解,不常用,项目中还没用到过

效果:

 
 
 
 

6. 翻页动画

ViewPager有个方法叫做:

setPageTransformer(boolean reverseDrawingOrder, PageTransformer transformer) 用于设置ViewPager切换时的动画效果,并且google官方还给出了两个示例(因为使用的是属性动画,所以不兼容3.0以下)。

1. DepthPageTransformer

public class DepthPageTransformer implements ViewPager.PageTransformer {
private static final float MIN_SCALE = 0.75f;
public void transformPage(View view, float position) {
int pageWidth = view.getWidth();
if (position < -1) { // [-Infinity,-1)
// This page is way off-screen to the left.
view.setAlpha(0);
} else if (position <= 0) { // [-1,0]
// Use the default slide transition when moving to the left page
view.setAlpha(1);
view.setTranslationX(0);
view.setScaleX(1);
view.setScaleY(1);
} else if (position <= 1) { // (0,1]
// Fade the page out.
view.setAlpha(1 - position);
// Counteract the default slide transition
view.setTranslationX(pageWidth * -position);
// Scale the page down (between MIN_SCALE and 1)
float scaleFactor = MIN_SCALE
+ (1 - MIN_SCALE) * (1 - Math.abs(position));
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
} else { // (1,+Infinity]
// This page is way off-screen to the right.
view.setAlpha(0);
}
}
}

调用:

vp.setPageTransformer(false,new DepthPageTransformer());

效果:

 
 

2. ZoomOutPageTransformer

public class ZoomOutPageTransformer implements ViewPager.PageTransformer
{
private static final float MIN_SCALE = 0.85f;
private static final float MIN_ALPHA = 0.5f;
@SuppressLint("NewApi")
public void transformPage(View view, float position)
{
int pageWidth = view.getWidth();
int pageHeight = view.getHeight();
Log.e("TAG", view + " , " + position + "");
if (position < -1)
{ // [-Infinity,-1)
// This page is way off-screen to the left.
view.setAlpha(0);
} else if (position <= 1) //a页滑动至b页 ; a页从 0.0 -1 ;b页从1 ~ 0.0
{ // [-1,1]
// Modify the default slide transition to shrink the page as well
float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position));
float vertMargin = pageHeight * (1 - scaleFactor) / 2;
float horzMargin = pageWidth * (1 - scaleFactor) / 2;
if (position < 0)
{
view.setTranslationX(horzMargin - vertMargin / 2);
} else
{
view.setTranslationX(-horzMargin + vertMargin / 2);
}
// Scale the page down (between MIN_SCALE and 1)
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
// Fade the page relative to its size.
view.setAlpha(MIN_ALPHA + (scaleFactor - MIN_SCALE)
/ (1 - MIN_SCALE) * (1 - MIN_ALPHA));
} else
{ // (1,+Infinity]
// This page is way off-screen to the right.
view.setAlpha(0);
}
}
}

调用:

vp.setPageTransformer(false,new ZoomOutPageTransformer());

效果:

 
 

3. 自定义动画
网上看到鸿洋大神写的

public class RotateDownPageTransformer implements ViewPager.PageTransformer {
private static final float ROT_MAX = 20.0f;
private float mRot; public void transformPage(View view, float position)
{
Log.e("TAG", view + " , " + position + "");
if (position < -1)
{ // [-Infinity,-1)
// This page is way off-screen to the left.
view.setRotation(0);
} else if (position <= 1) // a页滑动至b页 ; a页从 0.0 ~ -1 ;b页从1 ~ 0.0
{ // [-1,1]
// Modify the default slide transition to shrink the page as well
if (position < 0)
{
mRot = (ROT_MAX * position);
view.setPivotX(view.getMeasuredWidth() * 0.5f);
view.setPivotY(view.getMeasuredHeight());
view.setRotation( mRot);
} else
{
mRot = (ROT_MAX * position);
view.setPivotX(view.getMeasuredWidth() * 0.5f);
view.setPivotY(view.getMeasuredHeight());
view.setRotation( mRot);
}
// Scale the page down (between MIN_SCALE and 1)
// Fade the page relative to its size.
} else
{ // (1,+Infinity]
// This page is way off-screen to the right.
view.setRotation( 0);
}
}
}

效果:

 
 

position说明:
当前显示页为0,前一页为-1,后一页为1,滑动过程中数值不断变大或变小,所以为float类型

4. 开源框架ViewPagerTransforms
里面有十几种翻页动画,基本够用了
Github地址:ViewPagerTransforms

7. 翻页监听

1. 设置方法

addOnPageChangeListener()

2. 翻页监听接口

ViewPager.OnPageChangeListener

3. 重写方法
onPageScrolled(int position, float positionOffset, int positionOffsetPixels)

页面滑动状态停止前一直调用

position:当前点击滑动页面的位置
positionOffset:当前页面偏移的百分比
positionOffsetPixels:当前页面偏移的像素位置

onPageSelected(int position)

滑动后显示的页面和滑动前不同,调用

position:选中显示页面的位置

onPageScrollStateChanged(int state)

页面状态改变时调用

state:当前页面的状态

SCROLL_STATE_IDLE:空闲状态
SCROLL_STATE_DRAGGING:滑动状态
SCROLL_STATE_SETTLING:滑动后滑翔的状态

  1. 使用
vp.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
Log.e("vp","滑动中=====position:"+ position + " positionOffset:"+ positionOffset + " positionOffsetPixels:"+positionOffsetPixels);
} @Override
public void onPageSelected(int position) {
Log.e("vp","显示页改变=====postion:"+ position);
} @Override
public void onPageScrollStateChanged(int state) {
switch (state) {
case ViewPager.SCROLL_STATE_IDLE:
Log.e("vp","状态改变=====SCROLL_STATE_IDLE====静止状态");
break;
case ViewPager.SCROLL_STATE_DRAGGING:
Log.e("vp","状态改变=====SCROLL_STATE_DRAGGING==滑动状态");
break;
case ViewPager.SCROLL_STATE_SETTLING:
Log.e("vp","状态改变=====SCROLL_STATE_SETTLING==滑翔状态");
break;
}
}
});

Log:

 
 

三、与Fragment结合使用

与Fragment结合使用其实也一样,只是用Fragment代替原先的View,填充Viewpager;然后就是Adapter不一样,配合Fragment使用的有两个Adapter:FragmentPagerAdapter和FragmentStatePagerAdapter。

相同点:
FragmentPagerAdapter和FragmentStatePagerAdapter都继承自PagerAdapter

不同点:
卸载不再需fragment时,各自采用的处理方法有所不同

FragmentStatePagerAdapter会销毁不需要的fragment。事务提交后, activity的FragmentManager中的fragment会被彻底移除。 FragmentStatePagerAdapter类名中的“state”表明:在销毁fragment时,可在onSaveInstanceState(Bundle)方法中保存fragment的Bundle信息。用户切换回来时,保存的实例状态可用来恢复生成新的fragment

FragmentPagerAdapter有不同的做法。对于不再需要的fragment, FragmentPagerAdapter会选择调用事务的detach(Fragment)方法来处理它,而非remove(Fragment)方法。也就是说, FragmentPagerAdapter只是销毁了fragment的视图, fragment实例还保留在FragmentManager中。因此,FragmentPagerAdapter创建的fragment永远不会被销毁

也就是:在destroyItem()方法中,FragmentStatePagerAdapter调用的是remove()方法,适用于页面较多的情况;FragmentPagerAdapter调用的是detach()方法,适用于页面较少的情况。但是有页面数据需要刷新的情况,不管是页面少还是多,还是要用FragmentStatePagerAdapter,否则页面会因为没有重建得不到刷新

使用如下:

1. 创建Fragment及相应的xml布局

public class PagerFragment extends Fragment {
String mContent; @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
mContent = (String) getArguments().get("content");
View view = inflater.inflate(R.layout.fragment_pager, container, false) ;
TextView textView = (TextView) view.findViewById(R.id.tv);
textView.setText(mContent);
return view;
} }

<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.strivestay.viewpagerdemo.PagerFragment"> <TextView
android:id="@+id/tv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textSize="18sp"
android:text="@string/hello_blank_fragment"/> </FrameLayout>

2. 给Viewpager设置数据和适配器

private void setVp() {
final List<PagerFragment> list = new ArrayList<>();
for (int i = 0; i < 5; i++) {
PagerFragment fragment = new PagerFragment();
Bundle bundle = new Bundle();
bundle.putString("content","第"+i+"个Fragment");
fragment.setArguments(bundle); list.add(fragment);
} ViewPager vp = (ViewPager) findViewById(R.id.vp);
// vp.setAdapter(new FragmentPagerAdapter(getSupportFragmentManager()) {
// @Override
// public Fragment getItem(int position) {
// return list.get(position);
// }
//
// @Override
// public int getCount() {
// return list.size();
// }
// }); vp.setAdapter(new FragmentStatePagerAdapter(getSupportFragmentManager()) {
@Override
public Fragment getItem(int position) {
return list.get(position);
} @Override
public int getCount() {
return list.size();
}
}); }

效果:

 
 

四、实现轮播图效果

这里我就不自己实现了,介绍一个轮播图开源控件:banner

1. 特点

支持无限循环和多种主题
可以灵活设置轮播样式、动画、轮播和切换时间、位置、图片加载框架

2. 使用介绍

1. 导包 + 权限

implementation 'com.youth.banner:banner:1.4.10'

<!-- 加载网络图片需要权限 -->
<uses-permission android:name="android.permission.INTERNET" /> <!-- 加载本地图片需要权限-->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

2. xml引用

<com.youth.banner.Banner
android:id="@+id/banner"
android:layout_width="match_parent"
android:layout_height="自己设定"/>

3. 创建图片加载器

/**
* 图片轮播加载
*/
public class GlideImageLoader extends ImageLoader { @Override // path随便传,我这里最终传的是个对象,拿到图片Url
public void displayImage(Context context, Object path, ImageView imageView) { //Glide 加载图片,Fresco也好、加载本地图片也好,这个类功能就是加载图片
Glide.with(context).load(((AdList.DataBean)path).image).into(imageView); }
}

4. 设置数据

/**
* 设置banner
* @param data
*/
private void setBanner(List<AdList.DataBean> data) {
// banner样式
banner.setBannerStyle(BannerConfig.NOT_INDICATOR);
// 设置图片加载器
banner.setImageLoader(new GlideImageLoader());
// 设置图片集合
banner.setImages(data);
// 翻页特效
banner.setBannerAnimation(Transformer.Default);
// 设置轮播时间
banner.setDelayTime(4000);
// banner设置方法全部调用完毕时最后调用
banner.start();
} @Override
public void onResume() {
super.onResume();
//开始自动翻页
banner.startAutoPlay();
} @Override
public void onPause() {
super.onPause();
//停止翻页
banner.stopAutoPlay();
}

以上是简单使用,更详细的用法可以直接到GitHub上去看,文档是中文的,很方便,API也很简单,上面已经给出链接

效果:(项目里截图不方便,直接拿的示例图)

 
 

五、实现画廊效果

效果如下:

 
 
 
 

实现步骤:
1. viewpager布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:clipChildren="false"
tools:context="com.strivestay.viewpagerdemo.FourthActivity"> <include layout="@layout/layout_toolbar"/> <android.support.v4.view.ViewPager
android:id="@+id/vp"
android:layout_width="match_parent"
android:layout_height="180dp"
android:layout_marginTop="100dp"
android:layout_marginLeft="30dp"
android:layout_marginRight="30dp"
android:clipChildren="false">
</android.support.v4.view.ViewPager> </LinearLayout>

要点:
给viewpager和它的父布局都设置属性android:clipChildren=“false”

. pager布局

item_banner_samll.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:orientation="vertical"> <ImageView
android:id="@+id/iv_banner"
android:layout_width="200dp"
android:layout_height="180dp"
android:background="#009999"
android:scaleType="centerCrop"/>
</LinearLayout>

item_banner.xml

<?xml version="1.0" encoding="utf-8"?>
<ImageView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/iv_banner"
android:layout_width="match_parent"
android:layout_height="180dp"
android:background="#009999"
android:scaleType="centerCrop"/>

区别:
宽度,一个占满viewpager的宽度,一个小于viewpager的宽度

3. Adapter

/**
* 画廊效果,page宽度占满vp
* @author StriveStay
* @date 2018/2/24
*/
public class FourthPageAdapter extends PagerAdapter {
private Context mContext; public FourthPageAdapter(Context context) {
mContext = context;
} @Override
public int getCount() {
return Integer.MAX_VALUE;
} @Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
} @Override
public Object instantiateItem(ViewGroup container, int position) {
// 就4张图片
position %= 4; View view = View.inflate(mContext,R.layout.item_banner,null);
ImageView iv = (ImageView) view.findViewById(R.id.iv_banner);
int resourceId = mContext.getResources().getIdentifier("img" + (position + 1), "drawable", mContext.getPackageName());
Glide.with(mContext).load(resourceId).into(iv);
// iv.setImageResource(resourceId);
container.addView(view);
return view;
} @Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View)object);
} }

如果是page宽度 < vp宽度,需要重写getPageWidth()方法,用于计算page占据vp的百分比

@Override
public float getPageWidth(int position) {
float itemWidth = (mContext.getResources().getDisplayMetrics().density * 200);
float vpWidth = (mContext.getResources().getDisplayMetrics().widthPixels - mContext.getResources().getDisplayMetrics().density * 60);
return itemWidth / vpWidth;
}

3. vp设置adapter

private void setVp() {
ViewPager vp = (ViewPager) findViewById(R.id.vp); // 设置适配器
// vp.setAdapter(new FourthPageAdapter(this));
vp.setAdapter(new FourthSmallPageAdapter(this)); // page 边距
vp.setPageMargin((int)(getResources().getDisplayMetrics().density * 15)); // 为了左右无限滑动,显示在中间,且显示第一张
int i = Integer.MAX_VALUE/2%4;
vp.setCurrentItem(Integer.MAX_VALUE/2 + (4-i)); }

4. 问题
当page宽度 < vp宽度,且page的数量较少,没有占满vp,这时滑动vp,会出现闪屏,如下:

 
 

解决办法:

当明确知道vp放不下2个page时,可以如下处理

@Override
public float getPageWidth(int position) {
// 加上这句
if(getCount() < 2){
return super.getPageWidth(position);
} float itemWidth = (mContext.getResources().getDisplayMetrics().density * 200);
float vpWidth = (mContext.getResources().getDisplayMetrics().widthPixels - mContext.getResources().getDisplayMetrics().density * 60); Log.e("比例",vpWidth+"==="+itemWidth+"==="+(int)(vpWidth/itemWidth)); return itemWidth / vpWidth; }

当vp可以放置两个以上的page时,也是个通用的方法

vp.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
// vp中最多能放下2个page,则让vp中page个数 < 3时,让vp不能滑动
if(vp.getChildCount() < 3 && event.getAction() == MotionEvent.ACTION_MOVE){
return true;
}
return false;
}
});

更多Android高级架构进阶视频学习请点击:https://space.bilibili.com/474380680
原文链接:https://blog.csdn.net/weixin_39251617/article/details/79399592

高级UI晋升之常用View(三)中篇的更多相关文章

  1. 高级UI晋升之常用View(三)下篇

    更多Android高级架构进阶视频学习请点击:https://space.bilibili.com/474380680本篇文章将从WebView来介绍常用View: 一.WebView介绍 Andro ...

  2. 高级UI晋升之常用View(三)上篇

    更多Android高级架构进阶视频学习请点击:https://space.bilibili.com/474380680本篇文章将先从以下两个内容来介绍常用View: [RecycleView] [Ca ...

  3. 高级UI晋升之自定义View实战(五)

    更多Android高级架构进阶视频学习请点击:https://space.bilibili.com/474380680本篇文章将从自定义View利器Canvas和Paint来进行详解 一.Canvas ...

  4. 高级UI晋升之自定义view实战(七)

    更多Android高级架构进阶视频学习请点击:https://space.bilibili.com/474380680本篇文章自定义ViewGroup实现瀑布流效果来进行详解dispatchTouch ...

  5. 高级UI晋升之自定义View实战(六)

    更多Android高级架构进阶视频学习请点击:https://space.bilibili.com/474380680本篇文章将从Android 自定义属性动画&Camera动画来介绍自定义V ...

  6. 高级UI晋升之自定义View实战(九)

    更多Android高级架构进阶视频学习请点击:https://space.bilibili.com/474380680 1.前言: 本文采用自定义view的方法来实现一键清除的动画这个功能. 2.效果 ...

  7. 高级UI晋升之自定义View实战(八)

    更多Android高级架构进阶视频学习请点击:https://space.bilibili.com/474380680本篇文章自定义流式布局来进行介绍: 一般常见的流式布局由两种,一种是横向的个数固定 ...

  8. 高级UI晋升之布局ViewGroup(四)

    更多Android高级架构进阶视频学习请点击:https://space.bilibili.com/474380680本篇文章将从LinearLayout.RelativeLayout.FrameLa ...

  9. 高级UI晋升之View渲染机制(二)

    更多Android高级架构进阶视频学习请点击:https://space.bilibili.com/474380680 优化性能一般从渲染,运算与内存,电量三个方面进行,今天开始说聊一聊Android ...

随机推荐

  1. upc组队赛1 小C的数学问题【单调栈】(POJ2796)

    小C的数学问题 题目描述 小C是个云南中医学院的大一新生,在某个星期二,他的高数老师扔给了他一个问题. 让他在1天的时间内给出答案. 但是小C不会这问题,现在他来请教你. 请你帮他解决这个问题. 有n ...

  2. 使用 U 盘装个 winXP 原版镜像玩红警

    winXP 自身是不支持 U 盘启动的,所以用 poweriso 直接制作的 U 盘是没用的 可以使用 wintoflash 操作,下载地址: https://wintoflash.en.softon ...

  3. Http,Socket,TCP/IP 协议简述

    Http,Socket,TCP/IP 协议简述:https://blog.csdn.net/gordohu/article/details/54097841 TCP/IP协议,HTTP协议与webSo ...

  4. 大型项目必备IPC之Binder机制原理(一)

    阿里P7Android高级架构进阶视频免费学习请点击:https://space.bilibili.com/474380680 摘要 Binder是Android系统进程间通信(IPC)方式之一.Li ...

  5. python 根据余弦定理计算两边的夹角

    前面写过C#的. import numpy def GetAngle(sta_point, mid_point, end_point): ma_x = sta_point.X-mid_point.X ...

  6. mac 卸载编辑器卸不干净

    Configuration ~/Library/Preferences/ Caches ~/Library/Caches/ Plugins ~/Library/Application Support/ ...

  7. ReactOS 代码更新后的编译安装

    其实四月份就已经更新过了,最新版应该是0.4.11+,具体去GITHUB上去看. 至于编译,其实在最早的0.2版本时代,ReactOS就曾经给出过一套完整的编译方式, 并且给出过一个完整的编译环境,版 ...

  8. 前后台 工作切换---------------Linux 任务管理器(一)

    继续下一章... 发现了一个好东东.就是前后台的切换.例如我们现在要vim一个文件.然后又要查找一些命令的时候,以前不知道,都是退出后,查完了,在vim进入.现在我们可以将该vim拿到后台,然后查完了 ...

  9. Codeforces 1156D 带权并查集

    题意:给你一颗树,树边的权值可能是0或1,问先走0边,再走1边,或者只走1边的路径有多少条? 思路:对于一个点,假设通过0边相连的点一共有x个(包括自己),通过1边相连的有y个(包括自己),那么对答案 ...

  10. Django 自定义扩展命令

    import datetime import logger from django.conf import settings from django.db.models import Q from d ...