2015年4月14日即将实习结束,在过去的五六个月里,对于Android开发还是学到了很多,临走前将以前做的笔记整理一下,自己也再回顾一次。零散是必然的,也可能只是一小段代码片段,但都是曾经我在学Android是觉得挺有用的知识点。
第一部分:学习SDK下的实例代码时的笔记
1.menu菜单
onCreateOptionMenu(Menu menu){
.....
//代码生成MenuItem,使用一个自动生成的ID从resources(ids.xml)去避免所有的menu ids冲突
MenuItem locationItem = menu.add(0,R.id.menu_location,0,"Location");
locationItem.setIcon(R.drawable.ic_action_location);
MenuItemCompat.setShowAsAction(locationItem,MenuItem.SHOW_AS_ACTION_IF_ROOM);
........
}
resources/ids.xml:
<resources>
<!--会自动生成一个id-->
<item name="menu_location" type="id"/>
</resources>
2.通过strings.xml返回字符串并修改格式
代码中:
mHeaderTitle.setText(getString(R.string.image_header,mItem.getName(),mItem.getAuthor()));
strings.xml文件配置中:
<string name="image_header"> %1$s by %2$s </string>
3.通过ActivityOptionsCompat实现Activity过渡是的控件传输
ActivityOptionsCompat activityOptions=ActivityOptionsCompat.makeSceneTransitionAnimation(this,
new Pair<View,String>(view.findViewById(R.id.imageview_item),DetailActivity.VIEW_NAME_HEADER_IMAGE),
new Pair<View,String>(view.findViewById(R.id.textview_name),DetailActivity.VIEW_NAME_HEADER_TITLE)
);
ActivityCompat.startActivity(this,intent,activityOptions.toBundle());
获得随Activity启动附加的数据:
ViewCompat.setTransitionName(mHeaderImageView,VIEW_NAME_HEADER_IMAGE);
ViewCompat.setTransitionName(mHeaderTitle,VIEW_NAME_HEADER_TITLE);
//实现添加Transition.TransitionListener监听方法,对转移情况的监听
private boolean addTransitionListener(){
final Transition transition = getWindow().getSharedElementEnterTransition();
if(transition != null){
transition.addListener(new Transition.TransitionListener(){
public void onTransitionEnd(Transition transition){
loadFullSizeImage();
transition.removeListener(this);
}
public void onTransitionStart(Transition transition){}
public void onTransitionCancel(Transition transition){
transition.removeListener(this);
}
public void onTransitionPause(Transition transition){}
public void onTransitionResume(Transition transition){}
});
return true;
}
return false;
}
4.加载图片
Picasso.with( context ).load( url ).into( imageView );
5.使用Android L新特性,解决手机重启是带来的数据灾难
//需要在启动Activity的manifest文件中添加属性:
android:persistableMode="persistAcrossReboots"
//恢复持久化数据
public void onPostCreate(Bundle savedInstanceState,PersistableBundle persistentState){
super.onPostCreate(savedInstanceState,persistentState);
if(persistentState != null){
mDocumentCounter = persistentState.getInt(KEY_EXTRA_NEW_DOCUMENT_COUNTER);
}
}
//存储持久化数据
public void onSaveInstanceState(Bundle outState,PersistableBundle outPersistentState){
outPersistentState.putInt(KEY_EXTRA_NEW_DOCUMENT_COUNTER,mDocumentCounter);
super.onSaveInstanceState(outState,outPersistentState);
}
5.动画视图ViewAnimator
//可以实现ViewAnimator下定义的子视图的动画切换
ViewAnimator output=(ViewAnimator)this.findViewById(R.id.smaple_output);
if(mLogShown){
output.setDisplayedChild(1);
}else{
output.setDisplayedChild(0);
}
//重新更新菜单视图
//这个方法会重新执行onCreateOptionsMenu and onPrepareOptionsMenu
supportInvalidateOptionsMenu();
在xml文件中配置此视图
<ViewAnimator
android:id="@+id/sample_output"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<ScrollView
style="@style/Widget.SampleMessageTile"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
style="@style/Widget.SampleMessage"
..................../>
</ScrollView>
<fragment
android:name="....."
........./>
</ViewAnimator>
6.view.setTag(Object obj)的使用
//对View使用Tag可以缓存对象,从而提高了效率
在Adapter中使用inflate填充布局是可以使用setTag(...):
public View getView(int position,View convertView,ViewGroup parent){
final View view;
final ViewHolder holder;
if(convertView==null){
view=mLayoutInflater.inflate(mResourceId,parent,false);
holder=new ViewHolder();
assert view != null;
holder.image=(ImageView)view.findViewById(R.id.meat_image);
holder.title=(TextView)view.findViewById(R.id.meat_title);
view.setTag(holder);
}else{
view=convertView;
holder=(ViewHolder)view.getTag();
}
Meat meat=getItem(position);
holder.image.setImageResource(meat.resourceId);
holder.title.setText(meat.title);
return view;
}
定义static class ViewHolder:
private static class ViewHolder{
public ImageView image;
public TextView title;
}
7.在FramLayout中动画切换布局
private void toggle(){
mCover.setVisibility(View.VISIBLE);
FrameLayout before=copyVisibleViews();
FrameLayout.LayoutParams params=new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,FrameLayout.LayoutParams.MATCH_PARENT);
mCover.addView(befor,params);
swapAbsListView();
//在菜单中交换图标
ActivityCompat.invailidateOptionsMenu(getActivity());
//开始切换动画
mAbsListView.post(new Runnable(){
public void run(){
Scene scene=new Scene(mCover,copyVisibleViews());
Transition transition = new AutoTransition();
transition.addListener(AdapterTransitionFragment.this);
TransitionManager.go(scene,transition);
}
});
}
/**
* Swap ListView with GridView, or GridView with ListView.
*/
private void swapAbsListView() {
// We save the current scrolling position before removing the current list.
int first = mAbsListView.getFirstVisiblePosition();
// If the current list is a GridView, we replace it with a ListView. If it is a ListView,
// a GridView.
LayoutInflater inflater = LayoutInflater.from(getActivity());
inflateAbsList(inflater, (ViewGroup) mAbsListView.getParent(),
mAbsListView instanceof GridView);
mAbsListView.setAdapter(mAdapter);
// We restore the scrolling position here.
mAbsListView.setSelection(first);
// The new list is ready, and we replace the existing one with it.
mContent.removeAllViews();
mContent.addView(mAbsListView);
}
/**
* Copy all the visible views in the mAbsListView into a new FrameLayout and return it.
*
* @return a FrameLayout with all the visible views inside.
*/
private FrameLayout copyVisibleViews() {
// This is the FrameLayout we return afterwards.
FrameLayout layout = new FrameLayout(getActivity());
// The transition framework requires to set ID for all views to be animated.
layout.setId(ROOT_ID);
// We only copy visible views.
int first = mAbsListView.getFirstVisiblePosition();
int index = 0;
while (true) {
// This is one of the views that we copy. Note that the argument for getChildAt is a
// zero-oriented index, and it doesn‘t usually match with its position in the list.
View source = mAbsListView.getChildAt(index);
if (null == source) {
break;
}
// This is the copy of the original view.
View destination = mAdapter.getView(first + index, null, layout);
assert destination != null;
destination.setId(ROOT_ID + first + index);
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
source.getWidth(), source.getHeight());
params.leftMargin = (int) source.getX();
params.topMargin = (int) source.getY();
layout.addView(destination, params);
++index;
}
return layout;
}
8.设置ImmersiveMode(沉浸感模式)
//可以隐藏导航栏、全屏、沉浸感粘连等等特性
public void toggleHideyBar(){
int uiOptions = getActivity().getWindow().getDecorView().getSystemUiVisibility();
int newUiOptins = uiOptions;
boolean isImmersiverModeEnabled =((uiOptions|View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY)==uiOptions);
if(isImmersiveModeEnabled){
Log.i(TAG,"immersive mode turn off");
}else{
Log.i(TAG,"immersive mode turn on");
}
newUiOptions ^= View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
newUiOptions ^= View.SYSTEM_UI_FLAG_FULLSCREEN;
newUiOptions ^= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
getActivity().getWindow().getDecorView().setSystemUiVisibility(newUiOptions);
}
9.BasicTransition动态变换屏幕Scene
//创建一个屏幕的容器根结点
ViewGroup mSceneRoot =(ViewGroup)view.findViewById(R.id.scene_root);
//创建转换的屏幕
Scene mScene1 = new Scene(mSceneRoot,(ViewGroup)mSceneRoot.findViewById(R.id.container));
Scene mScene2 = Scene.getSceneForLayout(mSceneRoot,R.layout.scene2,getActivity());
//为屏幕创建一个转移管理器
TransitionManager mTransitionManagerForScene3 = TransitionInflater.from(getActivity())
.inflateTransitionManager(R.transition.scene3_transition_manager,mSceneRoot);
//启动屏幕转换
TransitionManager.go(mScene1);
//通过转换管理器实现转换
mTransitionManagerForScene3.transitionTo(mScene3);
//也可以通过转换管理器实现对一个屏幕中的某个控件的属性进行转换
TransitionManager.beginDelayedTransition(mSceneRoot);
View square = mSceneRoot.findViewById(R.id.transition_square);
ViewGroup.LayoutParams params = square.getLayoutParams();
int newSize = getResources().getDimensionPixelSize(R.dimen.square_size_expanded);
params.width = newSize;
params.height = newSize();
square.setLayoutParams(params);
//每个屏幕的Layout.xml文件的根节点的id需要一样,这样才能实现屏幕的切换
//配置转换器管理的配置文件
<transitionManager xmlns:an.....>
<transition
android:toScene="@layout/scene3"
android:transition="@transition/changebounds_fadein_together"/>
</transitionManager>
在changebounds_fadein_together.xml中:
//对id为transition_title的控件进行淡入动画
<transitionSet xmls:android=....>
<changeBounds/>
<fade android:fadingMode="fade_in">
<targets>
<target android:targetId="@id/transition_title"/>
</targets>
</fade>
</transitionSet>
10.按钮的风格
//When using the Holo theme (setting your activity or app theme to Theme.Holo or one of its descendants)
//a LinearLayout with the ?android:buttonBarStyle will draw dividers (with padding) between buttons.
<LinearLayout
style="?android:buttonBarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
//同时要确保每个子Button都应用的?android:buttonBarStyle的风格
<Button
style="?android:buttonBarButtonStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"/>
<Button
style="?android:buttonBarButtonStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"/>
</LinearLayout>
//通过设置divider的属性,可以出现分割条的效果
<LinearLayout xmlns:an...........
android:minHeight="?android:listPreferredItemHeight"
android:divider="?android:dividerVertical"
android:dividerPadding="8dp"
android:showDividers="middle"/>
//When using the Holo theme,setting a Button or ImageButton to ?android:borderlessButtonStyle removes its border
//and sets the background to ?android:selectableItemBackground,as described above.
<ImageButton
android:id="@+id/secondary_action"
style="?android:borderlessButtonStyle"
android:layout_width="48dp"
android:layout_height="match_parent"
android:src="@drawable/ic_action_delete"
android:contentDescription="@string/Delete"/>
//对于ListView可以设置scrollbarStyle属性,修改滚动条的风格
<ListView
.........
android:paddingLeft="48dp"
android:paddingRight="48dp"
android:scrollbarStyle="outsideOverlay"/>
11.布局下的子控件的选中状态设置为与父容器一致
<com.example.CheckableLinearLayout>
<TextView
android:duplicateParentState="true" //复制父容器的选中状态
android:textColor="@color/hideable_text_color"/>
<ImageView
android:duplicateParentState="true"
android:src="@drawable/ic_hideable_item"/>
</com.example.CheckableLinearLayout>
//在com.example.CheckableLinearLayout类下:
public class CheckableLinearLayout extends LinearLayout implements Checkable{
private static final int[] CHECKED_STATE_SET={android.R.attr.state_checked};
private boolean mChecked = false;
public CheckableLinearLayout(Context context,AttributeSet attrs){
super(context,attrs);
}
public boolean isChecked(){
return mChecked;
}
public void setChecked(boolean b){
if(b!=mChecked){
mChecked = b;
refreshDrawableState();
}
}
public void toggle(){
setChecked(!mChecked);
}
public int[] onCreateDrawableState(int extraSpace){
final int[] drawableState = super.onCreateDrawableState(extraSpace+1);
if(isChecked()){
mergeDrawableState(drawableState,CHECKED_STATE_SET);
}
return drawableState;
}
}
在ic_hideable_item.xml文件中:
<selector xmlns:android="...">
<item android:state_checked="false" android:drawable="@drawable/ic_hideable_item_unchecked"/>
<item android:drawable="@drawable/ic_hideable_item_checked"/>
</selector>
12.自定义的Transition
TransitionManager.go(mScenes[mCurrentScene],mTransition);
//创造改变颜色属性的差值动画转换器
public class ChangeColor extends Transition{
private static final String PROPNAME_BACKGROUND="customtransition:change_color:background";
private void captureValues(TransitionValues values){
values.values.put(PROPNAME_BACKGROUND,values.view.getBackground());
}
public void captureStartValues(TransitionValues transitionValues){
captureValues(transitionValues);
}
public void captureEndValues(TransitionValues transitionValues){
captureValues(transitionValues);
}
public Animator createAnimator(ViewGroup sceneRoot,TransitionValues startValues,TransitionValues endValues){
if(null==startValues||null==endValues){
return null;
}
final View view = endValues.view;
Drawable startBackground =(Drawable)startValues.values.get(PROPNAME_BACKGROUND);
Drawable endBackground = (Drawable)endValues.values.get(PROPNAME_BACKGROUND);
if(startBackground instanceof ColorDrawable && endBackground instanceof ColorDrawable){
ColorDrawable startColor =(ColorDrawable)startBackground;
ColorDrawable endColor =(ColorDrawable)endBackground;
if(startColor.getColor() !=endColor.getColor()){
ValueAnimator animator = ValueAnimator.ofObject(new ArgbEvaluator(),startColor.getColor(),endColor.getColor());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener(){
public void onAnimatorUpdate(ValueAnimator animation){
Object value =animation.getAnimatedValue();
if(value!=null){
view.setBackgroundColor((Integer)value);
}
}
});
return animator;
}
}
return null;
}
}
?
13.获得ActionBar的高度
TypedValue tv =new TypedValue();
if(context.getTheme().resolveAttribute(android.R.attr.actionBarSize,tv,true)){
mActionBarHeight =TypedValue.complexToDimensionPixelSize(tv.data,context.getResources().getDisplayMetrics());
}
?
14.CardView的使用
<android.support.v7.widget.CardView
style="@style/card">
</android.support.v7.widget.CardView>
<style name="card">
<item name="cardCornerRadius">4dp</item> //设置卡片的圆角半径
<item name="cardElevation">5dp</item> //设置卡片抬高的高度,可以形成阴影效果
<item name="contentPadding">20dp</item>
</style>
//通过fontFamily属性设置文本的字体
<item name="android:fontFamily">sans-serif</item>
//通过textAppearance属性设置文本的外观
<item name="android:textAppearance">?android:textAppearanceLarge</item>
?
15.自定义ActionBar的布局
public class DonwBarActivity extends Activity{
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
final LayoutInflater inflater =(LayoutInflater)getActionBar().getThemedContext().getSystemService(LAYOUT_INFLATER_SERVICE);
//加载ActionBar的填充布局文件
final View customActionBarView =inflater.inflate(R.layout.actionbar_custom_view_donw_cancel,null);
customActionBarView.findViewById(R.id.actionbar_donw).setOnClickListener(new View.OnClickListener(){
public void onClick(View v){
finish();
}
});
final ActionBar actionBar =getActionBar();
actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM,ActionBar.DISPLAY_SHOW_CUSTOM|ActionBar.DISPLAY_SHOW_HOME|ActionBar.DISPLAY_SHOW_TITLE);
//为ActionBar填充布局文件
actionBar.setCustomView(customActionBarView,new ActionBar.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT));
setContentView(R.layout.activity_done_bar);
}
}
//ActionBar的布局文件actionbar_custom_view_done_cancel.xml
<LinearLayout
android:orientation="horizontal"
android:divider="?android:attr/dividerVertical"
android:showDividers="middle"
android:dividerPadding="12dp">
<include layout="@layout/include_cancel_button"/>
<include layout="@layout/include_done_button"/>
</LinearLayout>
//include_cancel_button布局文件
<FrameLayout
style="?android:actionButtonStyle"
android:id="@+id/actionbar_cancel"
.....>
<TextView
style="?android:actionBarTabTextStyle"
.......
android:drawableLeft="@drawable/ic_action_cancel"
android:drawablePadding="8dp"
android:gravity="center_vertical"
android:text="@string/cancel"/>
</FrameLayout>
?