Android学习路线(二十四)ActionBar Fragment运用最佳实践
转载请注明出处:http://blog.csdn.net/sweetvvck/article/details/38645297
通过前面的几篇博客。大家看到了Google是怎样解释action bar和fragment以及推荐的使用方法。俗话说没有demo的博客不是好博客,以下我会介绍一下action bar和fragment在实战中的应用,以及相关demo源代码,希望和大家相互交流。
了解过fragment的同学们应该都知道,fragment是android 3.0版本号才出现的的,因此假设要在支持android 3.0一下版本号的project中使用fragment的话是须要加入Support Library的。详细怎样加入我就不再赘述。能够看我前面的博客Android学习路线(二十一)运用Fragment构建动态UI——创建一个Fragment,以下的项目支持到API
Level最低为8,所以项目中也会使用到Support Library。
作为一个有上进心的Android开发人员,我们是希望项目的设计符合Android Design的。Android Design是Google官方推荐的应用设计原则,不了解Android Design的同学能够去了解下。我这里有官方翻译文档。
我发现“知乎”的App设计是符合Android Design的。那么我们的项目就来模仿知乎的主界面。首先看下效果图:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc3dlZXR2dmNr/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast">
我们来分析一下这种界面应该怎么实现。从上图能够看出“知乎”android端使用了action bar和drawerlayout,同一时候drawer中item切换主界面应该是fragment。
新建一个projectFakeZhihu:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc3dlZXR2dmNr/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast">
从上图能够看到,使用最新的adt插件创建android项目时。假设选择的Minimum Required SDK为8,而Target SDK大于它的话。系统会自己主动在项目中导入Support v4包;在创建项目向导最后一步能够选择Navigation Type,假设选择了Navigation Drawer。adt工具会在创建项目时自己主动生成DrawerLayout相关演示样例代码。但因为DrawerLayout是在高版本号的API中出现的,因此adt工具会帮助导入Support
v7 appcompat包,这样DrawerLayout就能够兼容到Android2.2了。没有使用最新版的adt工具也没有关系。我提供的demo里有Support v4包和Support v7包,大家能够直接使用。
以下来看看代码怎样实现,android默认的holo主题仅仅提供两种色调,和官方的action bar比較能够看出“知乎”的action bar的颜色以及action bar上action item的颜色以及title的字体大小都是自己定义的,那么我们来模仿它自己定义一下action bar。
首先我们打开res文件夹下的style文件,自己定义一个主题和action bar的style。然后在自己定义主题中引用自己定义的action bar的style:
<? xml version="1.0" encoding="utf-8"?>
<resources>
<!-- the theme applied to the application or activity -->
<style name="CustomActionBarTheme"
parent="@style/Theme.AppCompat.Light.DarkActionBar">
<item name="android:actionBarStyle">@style/MyActionBar</item> <!-- Support library compatibility -->
<item name="actionBarStyle">@style/MyActionBar</item>
</style> <!-- ActionBar styles -->
<style name="MyActionBar"
parent="@style/Widget.AppCompat.Light.ActionBar.Solid.Inverse">
<item name="android:background">@drawable/actionbar_background</item>
<item name="android:titleTextStyle">@style/MyTitleStyle</item> <!-- Support library compatibility -->
<item name="background">@drawable/actionbar_background</item>
<item name="titleTextStyle">@style/MyTitleStyle</item>
</style>
<style name="MyTitleStyle"
parent="@android:style/TextAppearance.Holo.Widget.ActionBar.Title.Inverse">
<item name="android:textSize">20dp</item>
</style>
</resources>
这里要注意的是不管是在自己定义主题还是自己定义style时。要依据情况加上parent属性,假设没有加上对应的parent属性的话就不能使用父style中没有被覆盖的样式。详细怎样设置action bar的style能够參考Android学习路线(九)为Action Bar加入Style。
完毕自己定义主题和style后要记得在manifest文件里应用:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.sweetvvck.fakezhihu"
android:versionCode="1"
android:versionName="1.0" > <uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="19" /> <application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/CustomActionBarTheme" >
<activity
android:name="com.sweetvvck.fakezhihu.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application> </manifest>
这里能够让整个应用都使用自己定义的主题。也能够指定单个activity使用,使用android:theme属性来指定。
接下来要给app加入DrawerLayout了。改动MainActivity的布局文件,加入一个DrawerLayout。内容很easy,当中包括一个Drawer和内容布局的Container:
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.sweetvvck.fakezhihu.MainActivity" > <FrameLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent" /> <fragment
android:id="@+id/navigation_drawer"
android:name="com.sweetvvck.fakezhihu.NavigationDrawerFragment"
android:layout_width="@dimen/navigation_drawer_width"
android:layout_height="match_parent"
android:layout_gravity="start" /> </android.support.v4.widget.DrawerLayout>
注意。以下那个fragment就是app的Drawer,当中的属性android:layout_gravity在这里表示Drawer从哪一側划出,start代表左側,end代表右側;还能够定义两个fragment,然后一个左側划出一个右側划出,DrawerLayout在之后会具体解说,这里先简单了解怎样使用。
创建完DrawerLayout布局后,我们来为Drawer定义一个fragment,我们能够看到知乎的Drawer中仅仅是包括了一个ListView。这个ListView的第一项和其他项的布局不一样,我们能够想到用ListView加上headerView来实现。知道这些后。我们来创建一个NavigationDrawerFragment继承自Fragment。这个fragment的布局包括一个ListView:
<ListView 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"
android:background="#fff"
android:choiceMode="singleChoice"
android:divider="#c3c3c3"
android:dividerHeight="0.5dp"
tools:context="com.sweetvvck.fakezhihu.NavigationDrawerFragment" />
使用一个ArrayList来存放ListView的数据,定义一个DrawerListItem对象来存放每一个Item的title和icon的资源ID:
<string-array name="item_title">
<item>首页</item>
<item>发现</item>
<item>关注</item>
<item>收藏</item>
<item>草稿</item>
<item>搜索</item>
<item>提问</item>
<item>设置</item>
</string-array>
String[] itemTitle = getResources().getStringArray(R.array.item_title);
int[] itemIconRes = {
R.drawable.ic_drawer_home,
R.drawable.ic_drawer_explore,
R.drawable.ic_drawer_follow,
R.drawable.ic_drawer_collect,
R.drawable.ic_drawer_draft,
R.drawable.ic_drawer_search,
R.drawable.ic_drawer_question,
R.drawable.ic_drawer_setting}; for (int i = 0; i < itemTitle.length; i++) {
DrawerListItem item = new DrawerListItem(getResources().getDrawable(itemIconRes[i]), itemTitle[i]);
mData.add(item); }
准备好数据后为该ListView设置Adapter,我们发现这个ListView是Single Choice模式的,而且每一个Item被选中后会高亮。那么怎样来实现这个功能呢?
实现这种效果有两个步骤:
第一:在ListView中指定android:choiceMode="singleChoice"。
第二:给ListView的Item的布局设置一个特殊的背景drawable,这个drawable包括当状态为activated时的背景和常态下的背景;同一时候这个item布局中的图片src和文字颜色也要坐对应的设置。
item的背景:
<? xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_activated="true" android:drawable="@drawable/activated_background_color" />
<item android:drawable="@android:color/transparent" />
</selector>
图片的src,这里以home为例:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_activated="true" android:drawable="@drawable/ic_drawer_home_pressed" />
<item android:drawable="@drawable/ic_drawer_home_normal" />
</selector>
文字的颜色:
<?xml version="1.0" encoding="utf-8"? >
<!-- Copyright (C) 2011 Google Inc. All Rights Reserved. -->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="false"
android:color="#ff999999"/>
<item android:state_activated="true"
android:color="@android:color/white" />
<item
android:color="#636363" />
</selector>
这样就能实现ListView点击Item高亮的效果了。
考虑到用户在第一次使用app的时候可能不知道有Drawer的存在。我们能够在app第一次被启动时让Drawer处于打开状态。之后再默认隐藏。这是实际项目中经常使用的手段。这里我们用sharedpreference来实现:
// 通过这个flag推断用户是否已经知道drawer了,第一次启动应用显示出drawer(抽屉)。之后启动应用默认将其
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getActivity());
mUserLearnedDrawer = sp.getBoolean(PREF_USER_LEARNED_DRAWER, false);
接下来。要实现Drawer的fragment和宿主activity之间的通讯,须要定义一个回调接口。而且在宿主activity中实现:
/**
* 宿主activity要实现的回调接口
* 用于activity与该fragment之间通讯
*/
public static interface NavigationDrawerCallbacks {
/**
* 当drawer中的某个item被选择是调用该方法
*/
void onNavigationDrawerItemSelected(String title);
}
@Override
public void onNavigationDrawerItemSelected(String title) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction ft = fragmentManager.beginTransaction();
currentFragment = fragmentManager.findFragmentByTag(title);
if(currentFragment == null) {
currentFragment = ContentFragment.newInstance(title);
ft.add(R.id.container, currentFragment, title);
}
if(lastFragment != null) {
ft.hide(lastFragment);
}
if(currentFragment.isDetached()){
ft.attach(currentFragment);
}
ft.show(currentFragment);
lastFragment = currentFragment;
ft.commit();
onSectionAttached(title);
}
详细怎样来创建一个fragment以及怎样实现fragment和activity之间的通讯。能够參考:Android学习路线(二十一)运用Fragment构建动态UI——创建一个Fragment 和 Android学习路线(二十三)运用Fragment构建动态UI——Fragment间通讯 ;完整的NavigationDrawerFragment代码例如以下:
package com.sweetvvck.fakezhihu; import java.util.ArrayList;
import java.util.List; import android.app.Activity;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.app.Fragment;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarActivity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.Toast; /**
* 用于管理交互和展示抽屉导航的Fragment。
* 參考<a href="https://developer.android.com/design/patterns/navigation-drawer.html#Interaction">
* 设计向导</a>
*/
public class NavigationDrawerFragment extends Fragment { /**
* 存放选中item的位置
*/
private static final String STATE_SELECTED_POSITION = "selected_navigation_drawer_position"; /**
* 存放用户是否须要默认开启drawer的key
*/
private static final String PREF_USER_LEARNED_DRAWER = "navigation_drawer_learned"; /**
* 宿主activity实现的回调接口的引用
*/
private NavigationDrawerCallbacks mCallbacks; /**
* 将action bar和drawerlayout绑定的组件
*/
private ActionBarDrawerToggle mDrawerToggle; private DrawerLayout mDrawerLayout;
private ListView mDrawerListView;
private View mFragmentContainerView; private int mCurrentSelectedPosition = 0;
private boolean mFromSavedInstanceState;
private boolean mUserLearnedDrawer;
private List<DrawerListItem> mData = new ArrayList<DrawerListItem>(); public NavigationDrawerFragment() {
} @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); // 通过这个flag推断用户是否已经知道drawer了,第一次启动应用显示出drawer(抽屉),之后启动应用默认将其隐藏
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getActivity());
mUserLearnedDrawer = sp.getBoolean(PREF_USER_LEARNED_DRAWER, false); if (savedInstanceState != null) {
mCurrentSelectedPosition = savedInstanceState.getInt(STATE_SELECTED_POSITION);
mFromSavedInstanceState = true;
} } @Override
public void onActivityCreated (Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// 设置该fragment拥有自己的actionbar action item
setHasOptionsMenu(true);
} @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
mDrawerListView = (ListView) inflater.inflate(R.layout.fragment_navigation_drawer, container, false);
View headerView = inflater.inflate(R.layout.list_header, null);
mDrawerListView.addHeaderView(headerView);
mDrawerListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<? > parent, View view, int position, long id) {
selectItem(position);
}
});
String[] itemTitle = getResources().getStringArray(R.array.item_title);
int[] itemIconRes = {
R.drawable.ic_drawer_home,
R.drawable.ic_drawer_explore,
R.drawable.ic_drawer_follow,
R.drawable.ic_drawer_collect,
R.drawable.ic_drawer_draft,
R.drawable.ic_drawer_search,
R.drawable.ic_drawer_question,
R.drawable.ic_drawer_setting}; for (int i = 0; i < itemTitle.length; i++) {
DrawerListItem item = new DrawerListItem(getResources().getDrawable(itemIconRes[i]), itemTitle[i]);
mData.add(item); }
selectItem(mCurrentSelectedPosition);
DrawerListAdapter adapter = new DrawerListAdapter(this.getActivity(), mData);
mDrawerListView.setAdapter(adapter);
mDrawerListView.setItemChecked(mCurrentSelectedPosition, true);
return mDrawerListView;
} public boolean isDrawerOpen() {
return mDrawerLayout != null && mDrawerLayout.isDrawerOpen(mFragmentContainerView);
} /**
* 设置导航drawer
*
* @param fragmentId fragmentent的id
* @param drawerLayout fragment的容器
*/
public void setUp(int fragmentId, DrawerLayout drawerLayout) {
mFragmentContainerView = getActivity().findViewById(fragmentId);
mDrawerLayout = drawerLayout; mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START); ActionBar actionBar = getActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setHomeButtonEnabled(true);
//隐藏Action bar上的app icon
actionBar.setDisplayShowHomeEnabled(false); mDrawerToggle = new ActionBarDrawerToggle(
getActivity(), /* 宿主 */
mDrawerLayout, /* DrawerLayout 对象 */
R.drawable.ic_drawer, /* 替换actionbar上的'Up'图标 */
R.string.navigation_drawer_open,
R.string.navigation_drawer_close
) {
@Override
public void onDrawerClosed(View drawerView) {
super.onDrawerClosed(drawerView);
if (!isAdded()) {
return;
} getActivity().supportInvalidateOptionsMenu(); // 调用 onPrepareOptionsMenu()
} @Override
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
if (!isAdded()) {
return;
} if (!mUserLearnedDrawer) {
mUserLearnedDrawer = true;
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getActivity());
sp.edit().putBoolean(PREF_USER_LEARNED_DRAWER, true).commit();
} getActivity().supportInvalidateOptionsMenu(); // 调用 onPrepareOptionsMenu()
}
}; // 假设是第一次进入应用,显示抽屉
if (!mUserLearnedDrawer && !mFromSavedInstanceState) {
mDrawerLayout.openDrawer(mFragmentContainerView);
} mDrawerLayout.post(new Runnable() {
@Override
public void run() {
mDrawerToggle.syncState();
}
}); mDrawerLayout.setDrawerListener(mDrawerToggle);
} private void selectItem(int position) {
mCurrentSelectedPosition = position;
if (mDrawerListView != null) {
mDrawerListView.setItemChecked(position, true);
}
if (mDrawerLayout != null) {
mDrawerLayout.closeDrawer(mFragmentContainerView);
}
if (mCallbacks != null) {
if(mCurrentSelectedPosition == 0) {
mCallbacks.onNavigationDrawerItemSelected(getString(R.string.app_name));
return;
}
mCallbacks.onNavigationDrawerItemSelected(mData.get(position - 1).getTitle());
}
} @Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mCallbacks = (NavigationDrawerCallbacks) activity;
} catch (ClassCastException e) {
throw new ClassCastException("Activity must implement NavigationDrawerCallbacks.");
}
} @Override
public void onDetach() {
super.onDetach();
mCallbacks = null;
} @Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(STATE_SELECTED_POSITION, mCurrentSelectedPosition);
} @Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// 当系统配置改变时调用DrawerToggle的改变配置方法(比如横竖屏切换会回调此方法)
mDrawerToggle.onConfigurationChanged(newConfig);
} @Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
//当抽屉打开时显示应用全局的actionbar设置
if (mDrawerLayout != null && isDrawerOpen()) {
inflater.inflate(R.menu.global, menu);
showGlobalContextActionBar();
}
super.onCreateOptionsMenu(menu, inflater);
} @Override
public boolean onOptionsItemSelected(MenuItem item) {
if (mDrawerToggle.onOptionsItemSelected(item)) {
return true;
} if (item.getItemId() == R.id.action_example) {
Toast.makeText(getActivity(), "Example action.", Toast.LENGTH_SHORT).show();
return true;
} return super.onOptionsItemSelected(item);
} /**
* 当抽屉打开时显示应用全局的actionbar设置
*/
private void showGlobalContextActionBar() {
ActionBar actionBar = getActionBar();
actionBar.setDisplayShowTitleEnabled(true);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
actionBar.setTitle(R.string.app_name);
} private ActionBar getActionBar() {
return ((ActionBarActivity) getActivity()).getSupportActionBar();
} /**
* 宿主activity要实现的回调接口
* 用于activity与该fragment之间通讯
*/
public static interface NavigationDrawerCallbacks {
/**
* 当drawer中的某个item被选择是调用该方法
*/
void onNavigationDrawerItemSelected(String title);
} }
这样就完毕模仿“知乎”主界面的demo的开发啦,来看看效果怎样:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc3dlZXR2dmNr/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast">
怎么样,非常像吧,Drawer是不是简直能够以假乱真了,哈哈。
demo地址:http://download.csdn.net/detail/sweetvvck/7794083
事实上demo中还有写知识点没有讲到,比方drawer划开时和关闭时action bar上的action item事实上是不一样的,这时怎样实现的呢?怎么设置action bar不现实logo/icon?选择Drawer中listview的item切换fragment能够每选择一次都replace一次fragment,可是这样每次都得又一次创建一个fragment,假设fragment初始化较复杂就更占资源,此时能够配合使用add,hide,show来实现切换同一时候将以载入过的fragment缓存起来......因为篇幅原因。这些问题都会在之后的博客中具体讲到的~
Android学习路线(二十四)ActionBar Fragment运用最佳实践的更多相关文章
- android 学习随笔二十四(动画:帧动画)
帧动画,一张张图片不断的切换,形成动画效果 * 在drawable目录下定义xml文件,子节点为animation-list,在这里定义要显示的图片和每张图片的显示时长 * FrameAnimatio ...
- Android学习路线(十四)Activity生命周期——停止和重新启动(Stopping and Restarting)一个Activity
正确地停止和重新启动你的activity在activity的生命周期中是一个非常重要的过程.这样可以确保你的用户感觉到你的应用一直都活着而且没有丢失进度.你的activity的停止和重新启动时有几个重 ...
- python3.4学习笔记(二十四) Python pycharm window安装redis MySQL-python相关方法
python3.4学习笔记(二十四) Python pycharm window安装redis MySQL-python相关方法window安装redis,下载Redis的压缩包https://git ...
- 学习笔记:CentOS7学习之二十四:expect-正则表达式-sed-cut的使用
目录 学习笔记:CentOS7学习之二十四:expect-正则表达式-sed-cut的使用 24.1 expect实现无交互登录 24.1.1 安装和使用expect 24.2 正则表达式的使用 24 ...
- 设计模式学习(二十四):Spring 中使用到的设计模式
设计模式学习(二十四):Spring 中使用到的设计模式 作者:Grey 原文地址: 博客园:设计模式学习(二十四):Spring 中使用到的设计模式 CSDN:设计模式学习(二十四):Spring ...
- ActionBar Fragment运用最佳实践
ActionBar Fragment运用最佳实践
- (C/C++学习笔记) 二十四. 知识补充
二十四. 知识补充 ● 子类调用父类构造函数 ※ 为什么子类要调用父类的构造函数? 因为子类继承父类,会继承到父类中的数据,所以子类在进行对象初始化时,先调用父类的构造函数,这就是子类的实例化过程. ...
- Android学习笔记(十四) Handler理论补充
一.如何下载Android源码 在SDK Manager中选中Sources for Android SDK. 二.ThreadLocal初步介绍 1)执行ThreadLocal对象(static f ...
- 【转】Pro Android学习笔记(十四):用户界面和控制(2):Text类控制
目录(?)[-] TextView 例子1在XML中设置autoLink属性 例子2在代码中设置autoLink属性 EditText AutoCompleteTextView MultiAutoCo ...
随机推荐
- ASP.NET MVC 5 学习教程:数据迁移之添加字段
原文 ASP.NET MVC 5 学习教程:数据迁移之添加字段 起飞网 ASP.NET MVC 5 学习教程目录: 添加控制器 添加视图 修改视图和布局页 控制器传递数据给视图 添加模型 创建连接字符 ...
- #AzureChat - 自动伸缩和虚拟机
我们很高兴地推出再一次 #AzureChat,这是 @WindowsAzure 团队为您精心打造的一个在 Twitter 上进行的聊天活动! #AzureChat 专注于云计算的各个方面以及云开发的最 ...
- 再造 “手机QQ” 侧滑菜单(三)——视图联动
代码示例:https://github.com/johnlui/SwiftSideslipLikeQQ 本 文中,我们将一起使用 UINavigationController 来管理主视图,并实现点击 ...
- Qt 无边框窗体改变大小 完美实现
近期,做项目用到无边框窗体,令人蛋疼的是无边框窗体大小的改变要像右边框那样,上下左右四周,而且要流畅. 网上也找了些代码,发现居然还要连接到windows事件,这显然不合常理,后来自己新建了demo, ...
- 清华集训2014 day1 task2 主旋律
题目 这可算是一道非常好的关于容斥原理的题了. 算法 好吧,这题我毫无思路,直接给正解. 首先,问题的正面不容易求,那么就求反面吧: 有多少种添加边的方案,使得这个图是DAG图(这里及以下所说的DAG ...
- hdu4717 The Moving Points(二分做法)
这道题看了大家都是用三分做的,其实这道题也是可以用二分来做的,就是利用一下他们的单调性. 对于N个点,总共要考虑N(N+1)/2个距离,距离可以用二次函数表示,而且开口都是向上的. 下面具体说一下二分 ...
- 《高质量程序设计指南:C++/C语言》面试题整理
本试题仅用于考查C++/C程序员的基本编程技能.内容限于C++/C常用 语法,不涉及 数据结构. 算法以及深奥的语法.考试成绩能反映出考生的编程质量以及对C++/C的理解程度,但不能反映考生的智力和软 ...
- oralce 简单错误汇集。。。。。
1.ora-12560 TNS:协议适配器错误 实例名被错误修改或者oracle 服务没有正常启动.
- 第十一章 认识与学习BASH
系统支持的shell在 /etc/shells里面 Bash Shell 的功能: 1.命令修补能力(histroy) 2.命令与档案补全功能 3.命令别名设定功能 4.工作前景背景控制 5.支持 ...
- const对象默认是static的,而不是extern的
const 和 static 变量,可以放在头文件中 const对象默认是static的,而不是extern的,所以即使放在头文件中声明和定义.多个cpp引用同一个头文件,互相也没有感知,所以不会导致 ...