想寫個日歷選擇的控件,如上圖的效果,我也曾想站在巨人的肩膀上,奈何巨人也是坑哎..
起初,在codeKK上找了個第三方的庫,用起來很爽,然后我Demo了之后就網(wǎng)項目里面依賴了,結(jié)果和原項目的一個庫中的字段有沖突,想著那就該字段吧,轉(zhuǎn)念一想,字段改了豈不是項目中所有用到的這個字段都得改呢.我嫌麻煩,真的嫌麻煩
再說項目依賴的庫真的也有點多,所以我準備自己擼出來一個空間,已知原項目中,已有如下的一個庫.是WheelView
compile 'com.bigkoo:pickerview:2.0.8'
那么好,既然有了個WheelView的庫,那就在這個基礎(chǔ)上開始寫就好了.于是呢,我就真的開始寫了..
我計劃用一個dialogFragment 來彈出來選則框.dialogFragment和dialog的區(qū)別呢,就不多說了.
然后我就開始了
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<TextView
android:id="@+id/cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="10dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:paddingTop="5dp"
android:text="取消"
android:textColor="#99999999"
android:textSize="16sp"
/>
<View
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
/>
<TextView
android:id="@+id/confrim"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="10dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:paddingTop="5dp"
android:text="確定"
android:textColor="#342564"
android:textSize="16sp"
/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<com.bigkoo.pickerview.lib.WheelView
android:id="@+id/year"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
>
</com.bigkoo.pickerview.lib.WheelView>
<com.bigkoo.pickerview.lib.WheelView
android:id="@+id/month"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1">
</com.bigkoo.pickerview.lib.WheelView>
<com.bigkoo.pickerview.lib.WheelView
android:id="@+id/day"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
>
</com.bigkoo.pickerview.lib.WheelView>
</LinearLayout>
</LinearLayout>
以上是布局文件,其中com.bigkoo.pickerview.lib.WheelView為原項目所依賴的庫,就是滾輪類似的控件.
布局寫完,我開始著手寫dialogFragment了
public class SccDateDialog extends DialogFragment {
private static final String TAG = "SccDateDialog";
private TextView confrim, cancel;
private WheelView year, month, day;
private List<String> years;
private List<String> months;
private List<String> days;
private String mStringYear;
private String mStringMonth;
private String mStringDay;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.sccdatedialog, null);
return view;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
initViews();
initDatas();
initWheelViews();
getSelected();
}
/**
* 彈出選擇的時間
*/
private void getSelected() {
confrim.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(getActivity(), mStringYear + "-" + mStringMonth + "-" + mStringDay, Toast.LENGTH_SHORT).show();
dismiss();
}
});
cancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
dismiss();
}
});
}
/**
* 給WheelView添加數(shù)據(jù)
*/
private void initWheelViews() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String date = sdf.format(new Date(System.currentTimeMillis()));
String[] strings = date.split("-");
year.setCurrentItem(years.indexOf(strings[0]));
Log.e(TAG, "initWheelViews: setCurrentItem(3)--->"+3 );
mStringYear = years.get(years.indexOf(strings[0]));
Log.e(TAG, "initWheelViews: getCurrentItem()--->"+year.getCurrentItem() );
year.setCyclic(false);
year.setAdapter(new WheelAdapter() {
@Override
public int getItemsCount() {
return years.size();
}
@Override
public Object getItem(int index) {
return years.get(index);
}
@Override
public int indexOf(Object o) {
return years.indexOf(o);
}
});
year.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(int index) {
mStringYear = years.get(year.getCurrentItem());
}
});
month.setCurrentItem(months.indexOf(strings[1]));
mStringMonth = months.get(months.indexOf(strings[1]));
month.setCyclic(false);
month.setAdapter(new WheelAdapter() {
@Override
public int getItemsCount() {
return months.size();
}
@Override
public Object getItem(int index) {
return months.get(index);
}
@Override
public int indexOf(Object o) {
return months.indexOf(o);
}
});
month.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(int index) {
mStringMonth = months.get(month.getCurrentItem());
}
});
day.setCurrentItem(days.indexOf(strings[2]));
mStringDay = days.get(days.indexOf(strings[2]));
day.setCyclic(false);
day.setAdapter(new WheelAdapter() {
@Override
public int getItemsCount() {
return days.size();
}
@Override
public Object getItem(int index) {
return days.get(index);
}
@Override
public int indexOf(Object o) {
return days.indexOf(o);
}
});
day.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(int index) {
mStringDay = days.get(day.getCurrentItem());
}
});
}
/**
* 初始化數(shù)據(jù)
*/
private void initDatas() {
years = new ArrayList<>();
months = new ArrayList<>();
days = new ArrayList<>();
for (int i = 2014; i < 2021; i++) {
years.add(i + "");
}
for (int i = 1; i <= 12; i++) {
if (i < 10) {
months.add("0" + i);
} else {
months.add(i + "");
}
}
for (int i = 1; i <= 31; i++) {
if (i < 10) {
days.add("0" + i);
} else {
days.add(i + "");
}
}
}
/**
* 初始化控件
*/
private void initViews() {
confrim = (TextView) getView().findViewById(R.id.confrim);
cancel = (TextView) getView().findViewById(R.id.cancel);
year = (WheelView) getView().findViewById(R.id.year);
month = (WheelView) getView().findViewById(R.id.month);
day = (WheelView) getView().findViewById(R.id.day);
}
}
此時,這個庫的坑給出來了.
year.setCurrentItem(years.indexOf(strings[0]));
Log.e(TAG, "initWheelViews: setCurrentItem(3)--->"+3 );
mStringYear = years.get(years.indexOf(strings[0]));
Log.e(TAG, "initWheelViews: getCurrentItem()--->"+year.getCurrentItem() );
year.setCyclic(false);
year是顯示年的WheelView,setCurrentItem我起初設(shè)置為3,然后打印一下,因為set和get的設(shè)置值和返回值不一致.所以打印主要是想和getCurrentItem做一個對比. 結(jié)果真的對比做出來了..
log打印如下, 我當時就起了怪了,set和get得到的值為啥不一樣啊,,.這讓我怎么搞呢, 出去抽根煙吧.
調(diào)整一下情緒和思路,開始看源碼.看作者到底是咋搞的..于是,打開了源碼
這是源碼中的get方法:
public final int getCurrentItem() {
return selectedItem;
}
返回了一個selectedItem這個字段.那搜一下這個字段吧.共兩處,第一處是聲明,哈哈
private int selectedItem;
第二處是:
if (translateY >= firstLineY && maxTextHeight + translateY <= secondLineY) {
// 中間條目
canvas.clipRect(0, 0, measuredWidth, (int) (itemHeight));
canvas.drawText(contentText, drawCenterContentStart, maxTextHeight - CENTERCONTENTOFFSET, paintCenterText);
int preSelectedItem = adapter.indexOf(visibles[counter]);
if(preSelectedItem != -1){
selectedItem = preSelectedItem;
}
那再看看preSelectedItem字段唄
int preSelectedItem = adapter.indexOf(visibles[counter]);
那就在看看這個visibles[counter],數(shù)組就不看了,看一下索引值吧
counter = 0;
while (counter < itemsVisible) {
canvas.save();
// L(弧長)=α(弧度)* r(半徑) (弧度制)
// 求弧度--> (L * π ) / (π * r) (弧長X派/半圓周長)
float itemHeight = maxTextHeight * lineSpacingMultiplier;
double radian = ((itemHeight * counter - itemHeightOffset) * Math.PI) / halfCircumference;
// 弧度轉(zhuǎn)換成角度(把半圓以Y軸為軸心向右轉(zhuǎn)90度拘领,使其處于第一象限及第四象限
float angle = (float) (90D - (radian / Math.PI) * 180D);
// 九十度以上的不繪制
if (angle >= 90F || angle <= -90F) {
canvas.restore();
} else {
String contentText = getContentText(visibles[counter]);
//計算開始繪制的位置
measuredCenterContentStart(contentText);
measuredOutContentStart(contentText);
float translateY = (float) (radius - Math.cos(radian) * radius - (Math.sin(radian) * maxTextHeight) / 2D);
//根據(jù)Math.sin(radian)來更改canvas坐標系原點挽霉,然后縮放畫布,使得文字高度進行縮放判没,形成弧形3d視覺差
canvas.translate(0.0F, translateY);
canvas.scale(1.0F, (float) Math.sin(radian));
if (translateY <= firstLineY && maxTextHeight + translateY >= firstLineY) {
// 條目經(jīng)過第一條線
canvas.save();
canvas.clipRect(0, 0, measuredWidth, firstLineY - translateY);
canvas.scale(1.0F, (float) Math.sin(radian) * SCALECONTENT);
canvas.drawText(contentText, drawOutContentStart, maxTextHeight, paintOuterText);
canvas.restore();
canvas.save();
canvas.clipRect(0, firstLineY - translateY, measuredWidth, (int) (itemHeight));
canvas.scale(1.0F, (float) Math.sin(radian) * 1F);
canvas.drawText(contentText, drawCenterContentStart, maxTextHeight - CENTERCONTENTOFFSET, paintCenterText);
canvas.restore();
} else if (translateY <= secondLineY && maxTextHeight + translateY >= secondLineY) {
// 條目經(jīng)過第二條線
canvas.save();
canvas.clipRect(0, 0, measuredWidth, secondLineY - translateY);
canvas.scale(1.0F, (float) Math.sin(radian) * 1.0F);
canvas.drawText(contentText, drawCenterContentStart, maxTextHeight - CENTERCONTENTOFFSET, paintCenterText);
canvas.restore();
canvas.save();
canvas.clipRect(0, secondLineY - translateY, measuredWidth, (int) (itemHeight));
canvas.scale(1.0F, (float) Math.sin(radian) * SCALECONTENT);
canvas.drawText(contentText, drawOutContentStart, maxTextHeight, paintOuterText);
canvas.restore();
} else if (translateY >= firstLineY && maxTextHeight + translateY <= secondLineY) {
// 中間條目
canvas.clipRect(0, 0, measuredWidth, (int) (itemHeight));
canvas.drawText(contentText, drawCenterContentStart, maxTextHeight - CENTERCONTENTOFFSET, paintCenterText);
int preSelectedItem = adapter.indexOf(visibles[counter]);
if(preSelectedItem != -1){
selectedItem = preSelectedItem;
}
} else {
// 其他條目
canvas.save();
canvas.clipRect(0, 0, measuredWidth, (int) (itemHeight));
canvas.scale(1.0F, (float) Math.sin(radian) * SCALECONTENT);
canvas.drawText(contentText, drawOutContentStart, maxTextHeight, paintOuterText);
canvas.restore();
}
canvas.restore();
}
counter++;
}
初始化為0,然后在監(jiān)聽中有++
所以日歷控件顯示的初始值為今天的話,點擊之后獲得的值是為0的item下標.哎,不說了,自己去改吧..改完后的代碼就是SccDateDialog的代碼,其實就是把初始化的值自己獲取一下..
其實原作者很厲害,只是差那么一點點就完美了..