Android开发笔记0
记录一些好用的开发技巧
0. 自定义一个View
现在的音乐播放器,比如天天动听或网易云音乐中都会将推荐页面中的内容进行分块,比如热门推荐、个性化推荐、最新音乐等等。每个区块前面都会有一个标题,如下图:
可能很多人还在重用布局文件(layout文件)来做这些功能,但是如果你现在又需要在另一个(或多个)页面中使用这个标题,那么你就必须把标题的布局文件include进来,然后在代码里面findViewById
来获取标题,还要设置标题TextView
和标题前面小圆圈的主题什么的。这样你需要在每个使用这个标题的页面中都重复写这些代码
这样太麻烦了,你可以直接把它写成一个View,然后在布局文件中直接使用这个View
/**
*
* @author bxbxbai
* @version 1.0.0
*/
public class IndicatorView extends LinearLayout {
TextView mTitle;
public IndicatorView(Context context) {
super(context);
init();
}
public IndicatorView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public IndicatorView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
View view = View.inflate(getContext(), R.layout.find_song_title_bar, this);
mTitle = (TextView) view.findViewById(R.id.id_text_title);
}
public void setTitle(String title) {
mTitle.setText(title);
}
}
1. 正方形的Layout
有很多情况会出现正方形的View,如下图:
这样的布局一般会是最外面一个LinearLayout
,包含一个RelativeLayout
和一个TextView
,这个RelativeLayout
中包含了一个ImageView
和两个TextView
。如果把ImageView
的layout_height
设置成wrap_content
,这样肯定会有问题,有的时候图片不是正方形的,就会有各种奇形怪状。
你也可以在加载图片的时候将Bitmap的高剪成和宽一致,但是这样太麻烦了。你也可以写一个SqaureImageView
,但是我觉得这样的重用性不好。
其实,最好的方式还是将这个RelativeLayout
换成SquareLayout
,这是一个正方形的RelativeLayout
。然后将ImageView
的layout_height
和layout_width
设置成match_parent
就可以了,图片自动设置为正方形,再按照需求设置ImageView
的scaleType
代码很少,如下:
/**
* Created by baia on 14/10/27.
* @author bxbxbai
* @version 1.0.0
*/
public class SquareLayout extends RelativeLayout {
public SquareLayout(Context context) {
super(context);
}
public SquareLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SquareLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(getDefaultSize(0, widthMeasureSpec), getDefaultSize(0, heightMeasureSpec));
//children are just made to fill our space
int childWithSize = getMeasuredWidth();
//height is set to be same as width
heightMeasureSpec = widthMeasureSpec =
MeasureSpec.makeMeasureSpec(childWithSize, MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
2. LinearLayout 的divider
先来看一张图:
如果要写上面图片中的布局,整体的布局肯定是两个LinearLayout
,然后设置margin值让各个子View之间留出空隙。如果你设置了button_2隐藏了,然后你就看到了:
图片中button_1右边留出了一个margin值
如果你使用LinearLayout
的android:divider
属性就会极大的方便你的代码。android:divider
的值是一个drawable
,你可以定义一个如下drawable文件
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/
android:shape="rectangle">
<size
android:width="10dp"
android:height="10dp" />
<solid android:color="@android:color/transparent" />
</shape>
其中,下面3个按钮的布局文件为:
<LinearLayout
android:id="@+id/buttons_container"
android:layout_width="match_parent"
android:divider="@drawable/drawable_divider"
android:showDividers="middle"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/btn_0"
style="@style/ButtonStyle"
android:background="@android:color/holo_purple"
android:text="button_0" />
<Button
android:id="@+id/btn_1"
style="@style/ButtonStyle"
android:background="@android:color/darker_gray"
android:text="button_1" />
<Button
android:id="@+id/btn_3"
style="@style/ButtonStyle"
android:background="@android:color/holo_blue_dark"
android:text="button_2" />
</LinearLayout>
比较重要的两句代码就是:
android:divider="@drawable/drawable_divider"
android:showDividers="middle"
这个@drawable/drawable_divider
就是上面写的drawable文件,showDividers
的值可以选择beginning
, middle
, end
, none
,什么意思一看就明白。
LinearLayout
的android:divider
是一个非常好用而且强大的功能噢~
3. 更加方便的启动Fragment或Activity
启动Activity的一个非常普遍的方法就是
Intent intent = new Intent(MainActivity.this, AlbumActivity.class);
intent.putExtra(ALBUM_ID, 100L);
startActivity(intent);
如果app中有很多地方会启动AlbumActivity
,那么这样的话你就需要在很多地方重复上面的代码,这不是在Repeat Yourself了吗。不光如此,如果一个Activity需要很多值,那么你就需要一个一个的设置,非常麻烦。
换个思路,你可以这样写:
public class AlbumActivity extends Activity {
//....
/**
* launch activity
* @param context Context
* @param albumId id
*/
public static void launch(Context context, long albumId) {
Intent intent = new Intent(context, AlbumActivity.class);
intent.putExtra(ALBUM_ID, albumId);
context.startActivity(intent);
}
//...
}
然后你就可以直接这样启动AlbumActivity
:
AlbumActivity.launch(MainActivity.this, 100L);
其实启动Fragment也可以使用这样的方法,超级方便。
我一直觉得,我写一个Fragment或Activity是希望别人以更加方便的方式去调用,而不是别人要用我的组件的时候先要看半天代码,这样很浪费时间
4. ListView的layout_height属性
ListView的layout_height
属性一般情况下不允许设置为wrap_content
,这样会在ListView滚动的时候非常浪费性能(getView方法会多次调用)
5. Singleton模板
在看Android源码的时候发现这么一个类:
package android.util;
/**
* Singleton helper class for lazily initialization.
*
* Modeled after frameworks/base/include/utils/Singleton.h
*
* @hide
*/
public abstract class Singleton<T> {
private T mInstance;
protected abstract T create();
public final T get() {
synchronized (this) {
if (mInstance == null) {
mInstance = create();
}
return mInstance;
}
}
}
突然发现这个代码写的真好啊啊…如果你想创建一个单例的话只要继承这个Singleton<T>
模板就可以了
但是!因为Android系统源码上加了@hide
标注,我们不能直接继承这个android.util.Singleton<T>
类。
我们可以在工程的utils包中写一份一模一样的代码嘛~