Android自定义View(RollWeekView-炫酷的星期日期选择控件)
转载请标明出处:
http://blog.csdn.net/xmxkf/article/details/53420889
本文出自:【openXu的博客】
目录:
最近收到一个自定义控件的需求,需要做一个日期选择控件,实现图如下:
一次展示一个星期的5天,中间放大的为当前选中的;如果点击了其中一个日期,比如星期五,那么整体向左滑动,并将星期五慢慢放大,星期三慢慢缩小,星期六和星期天就展示出来了;如果继续点击星期六,那么照样是整体向左滑动一个单位,星期日右边就需要塞进一个星期一。就是一个无限循环的过程,中间选中的需要展示当天的日期。
1、分析
最开始,我想到在LinearLayout
中依次排开7个子控件(星期几),当点击之后,把所有的子控件通过动画移动相应的偏移量,但是,如果移动后就会出现空位的情况(周一的左边和周日的右边没有了),所以这种方式可是可以,但是要解决无限循环空位的情况。
于是就想到能不能多添加几个子控件作为空位替补?这个方法肯定能实现,但是究竟需要多少个替补呢?这些替补应该放在什么位置呢?
当前展示的5个子控件中,如果点击最左边或者最右边,这样的偏移量是最大的,需要便宜两个子控件单位,所以左边和右边最多个需要2个替补就行了,算起来也不多,一共才9个(当前展示5个,左边隐藏替补2个,右边隐藏替补2个)。在点击之前,先将替补位置设置好,当点击之后,所有子控件执行偏移动画(不可能出现空位,最多偏移2位),动画结束之后,再重新为隐藏的4个替补分配位置并绑定数据,绑定什么数据那就看当前中间显示的是星期几了。
分析图如下:
但是新的问题又来了,动画执行完毕之后,怎么判断哪些子控件是当前正在显示的呢(中间五个)?由于正在显示的子控件的位置是可以确定的,因为要重写onMeasure()
,在onMeasure()
方法中可以得到单个子控件的宽度(item_width=getMeasureWidth()/5
),动画结束之后,遍历这些子控件,如果x==0
的那肯定就是当前正在展示的第一个子控件,x==item_width
则是第二个….,剩余的4个就不用判断了,直接将两个移动到左边,两个移动到右边,然后重新为这四个替补设置数据。
2、定义控件布局
组合控件的布局如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:gravity="center_vertical">
<LinearLayout
android:id="@+id/ll_1"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center">
<LinearLayout
android:layout_width="@dimen/week_item_sise"
android:layout_height="@dimen/week_item_sise"
android:background="@drawable/week_one_bg"
android:orientation="vertical"
android:gravity="center">
<TextView
android:id="@+id/tv_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="周" />
<TextView
android:id="@+id/tv_date1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="周" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/ll_2"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center">
<LinearLayout
android:layout_width="@dimen/week_item_sise"
android:layout_height="@dimen/week_item_sise"
android:background="@drawable/week_one_bg"
android:orientation="vertical"
android:gravity="center">
<TextView
android:id="@+id/tv_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="周" />
<TextView
android:id="@+id/tv_date2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="周" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/ll_3"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center">
<LinearLayout
android:layout_width="@dimen/week_item_sise"
android:layout_height="@dimen/week_item_sise"
android:background="@drawable/week_one_bg"
android:orientation="vertical"
android:gravity="center">
<TextView
android:id="@+id/tv_3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="周" />
<TextView
android:id="@+id/tv_date3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="周" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/ll_4"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center">
<LinearLayout
android:layout_width="@dimen/week_item_sise"
android:layout_height="@dimen/week_item_sise"
android:background="@drawable/week_one_bg"
android:orientation="vertical"
android:gravity="center">
<TextView
android:id="@+id/tv_4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="周" />
<TextView
android:id="@+id/tv_date4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="周" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/ll_5"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center">
<LinearLayout
android:layout_width="@dimen/week_item_sise"
android:layout_height="@dimen/week_item_sise"
android:background="@drawable/week_one_bg"
android:orientation="vertical"
android:gravity="center">
<TextView
android:id="@+id/tv_5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="周" />
<TextView
android:id="@+id/tv_date5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="周" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/ll_6"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center">
<LinearLayout
android:layout_width="@dimen/week_item_sise"
android:layout_height="@dimen/week_item_sise"
android:background="@drawable/week_one_bg"
android:orientation="vertical"
android:gravity="center">
<TextView
android:id="@+id/tv_6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="周" />
<TextView
android:id="@+id/tv_date6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="周" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/ll_7"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center">
<LinearLayout
android:layout_width="@dimen/week_item_sise"
android:layout_height="@dimen/week_item_sise"
android:background="@drawable/week_one_bg"
android:orientation="vertical"
android:gravity="center">
<TextView
android:id="@+id/tv_7"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="周" />
<TextView
android:id="@+id/tv_date7"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="周" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/ll_8"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center">
<LinearLayout
android:layout_width="@dimen/week_item_sise"
android:layout_height="@dimen/week_item_sise"
android:background="@drawable/week_one_bg"
android:orientation="vertical"
android:gravity="center">
<TextView
android:id="@+id/tv_8"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="周" />
<TextView
android:id="@+id/tv_date8"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="周" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/ll_9"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center">
<LinearLayout
android:layout_width="@dimen/week_item_sise"
android:layout_height="@dimen/week_item_sise"
android:background="@drawable/week_one_bg"
android:orientation="vertical"
android:gravity="center">
<TextView
android:id="@+id/tv_9"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="周" />
<TextView
android:id="@+id/tv_date9"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="周" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
3、定义CustomWeekView
布局写完后,接下来应该找一个容器接纳他们,这个容器就是我们定义的CustomWeekView
,让其继承LinearLayout
,然后重写构造方法,并初始化子控件;此处自定义属性就不再赘述,之前的所有自定义控件案例中都讲解过,如果不熟悉请参考 Android自定义View(二、深入解析自定义属性):
public class CustomWeekView extends LinearLayout{
public CustomWeekView(Context context) {
this(context, null);
}
public CustomWeekView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomWeekView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
LayoutInflater.from(context).inflate(R.layout.custom_week_layout, this, true);
ll_1 = (LinearLayout) findViewById(R.id.ll_1);
ll_2 = (LinearLayout) findViewById(R.id.ll_2);
...
tv_1 = (TextView) findViewById(R.id.tv_1);
tv_2 = (TextView) findViewById(R.id.tv_2);
...
tv_date1 = (TextView) findViewById(R.id.tv_date1);
tv_date2 = (TextView) findViewById(R.id.tv_date2);
...
if (attrs != null) {
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.LimitScroller);
limit = 5;
background = ta.getColor(R.styleable.LimitScroller_android_background, Color.TRANSPARENT);
textSize = ta.getDimension(R.styleable.LimitScroller_android_textSize, 15f);
final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
textSize = textSize / fontScale + 0.5f;
dateTextSize = ta.getInteger(R.styleable.LimitScroller_dateTextSize, 12);
textColor = ta.getColor(R.styleable.LimitScroller_android_textColor, Color.BLACK);
dateTextColor = ta.getColor(R.styleable.LimitScroller_dateTextColor, Color.RED);
durationTime = ta.getInt(R.styleable.LimitScroller_durationTime, 1000);
scaleSize = ta.getFloat(R.styleable.LimitScroller_scaleSize, 0);
ta.recycle(); //注意回收
}
}
}
4、重写onMeasure
由于本控件宽度是填充父窗体,高度是包裹内容,这里不需要我们手动写代码测量,直接调用super.onMeasure()
好了。(onMeasure()详解请移步:Android自定义View(三、深入解析控件测量onMeasure))。但是我们需要在测量完毕后,计算子控件的宽度并初次安置每个子控件的位置,这个宽度就是后面移动的单位,也作为位置判断的依据。由于onMeasure()
方法会被调用多次(后面设置位置、显示隐藏等等操作都会导致onMeasure()
触发),所以需要判断一下如果ITEM_WIDTH<=0
才需要计算;然后还要为子控件设置初始日期:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// Log.w(TAG, "测量完成,宽度*高度="+getMeasuredWidth()+"*"+getMeasuredHeight());
if(ITEM_WIDTH<=0) {
ITEM_WIDTH = getMeasuredWidth()/limit;
// Log.w(TAG, "每小项尺寸:"+ITEM_WIDTH+"*"+getMeasuredHeight());
measureInit();
}
if(ll_2.getX()>0 && !isFirstSeted) {
//设置今天的日期在中间
animalFinish = false;
Calendar cal = Calendar.getInstance();
int todayNum = cal.get(Calendar.DAY_OF_WEEK)-1;
Log.d(TAG, "今天是星期"+WEEK_STR[todayNum]);
setCenter(getEnumByNum(todayNum));
animalFinish = true;
isFirstSeted = true;
}
}
/**根据屏幕的宽度和显示的个数,设置item的宽度*/
private void measureInit(){
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)ll_1.getLayoutParams();
lp.width = ITEM_WIDTH;
ll_1.setLayoutParams(lp);
lp = (LinearLayout.LayoutParams)ll_2.getLayoutParams();
lp.width = ITEM_WIDTH;
ll_2.setLayoutParams(lp);
lp = (LinearLayout.LayoutParams)ll_3.getLayoutParams();
lp.width = ITEM_WIDTH;
ll_3.setLayoutParams(lp);
lp = (LinearLayout.LayoutParams)ll_4.getLayoutParams();
lp.width = ITEM_WIDTH;
ll_4.setLayoutParams(lp);
lp = (LinearLayout.LayoutParams)ll_5.getLayoutParams();
lp.width = ITEM_WIDTH;
ll_5.setLayoutParams(lp);
lp = (LinearLayout.LayoutParams)ll_6.getLayoutParams();
lp.width = ITEM_WIDTH;
ll_6.setLayoutParams(lp);
lp = (LinearLayout.LayoutParams)ll_7.getLayoutParams();
lp.width = ITEM_WIDTH;
ll_7.setLayoutParams(lp);
lp = (LinearLayout.LayoutParams)ll_8.getLayoutParams();
lp.width = ITEM_WIDTH;
ll_8.setLayoutParams(lp);
lp = (LinearLayout.LayoutParams)ll_9.getLayoutParams();
lp.width = ITEM_WIDTH;
ll_9.setLayoutParams(lp);
}
5、点击后执行动画
上面的步骤完成之后,基本上已经完成的控件的初始设置,接下来就是点击子控件后执行动画了。这里一共需要执行两套动画,一套是缩放动画、一套是移动动画。添加点击事件的代码就不贴出来了,下面是执行动画的方法:
private void startAnimation(final WEEKDAY centerWitch, final LinearLayout llClickView) {
if(centerWitch==centerNow)
return;
animalFinish = false;
LinearLayout innerLL = (LinearLayout)ll3.getChildAt(0);
TextView tvDate = (TextView)innerLL.getChildAt(1);
tvDate.setVisibility(View.GONE);
innerLL = (LinearLayout)llClickView.getChildAt(0);
tvDate = (TextView)innerLL.getChildAt(1);
tvDate.setVisibility(View.VISIBLE);
//根据当前中间位置显示的 和 被点击的日期,获取需要偏移的增量
int offset = getXOffset(centerWitch);
Log.d(TAG, "当前中间为"+centerNow+",点击的是"+centerWitch+ " 偏移量:"+offset);
//当前中间位置的需要缩放到原尺寸
// Log.v(TAG, "中间item缩放量scaleX="+ll3.getChildAt(0).getScaleX()+" scaleY="+ll3.getChildAt(0).getScaleY());
ObjectAnimator anim100 = ObjectAnimator.ofFloat(ll3.getChildAt(0), "scaleX", ll3.getChildAt(0).getScaleX(), 1.0f);
ObjectAnimator anim101 = ObjectAnimator.ofFloat(ll3.getChildAt(0), "scaleY", ll3.getChildAt(0).getScaleY(), 1.0f);
//被点击的需要放大
ObjectAnimator anim102 = ObjectAnimator.ofFloat(llClickView.getChildAt(0), "scaleX", 1, scaleSize);
ObjectAnimator anim103 = ObjectAnimator.ofFloat(llClickView.getChildAt(0), "scaleY", 1, scaleSize);
//透明度动画
ObjectAnimator anim104 = ObjectAnimator.ofFloat(llClickView.getChildAt(0), "scaleY", 1, scaleSize);
//位移动画
ObjectAnimator anim1 = ObjectAnimator.ofFloat(ll_1, "X", ll_1.getX(), ll_1.getX() + offset);
ObjectAnimator anim2 = ObjectAnimator.ofFloat(ll_2, "X", ll_2.getX(), ll_2.getX() + offset);
ObjectAnimator anim3 = ObjectAnimator.ofFloat(ll_3, "X", ll_3.getX(), ll_3.getX() + offset);
ObjectAnimator anim4 = ObjectAnimator.ofFloat(ll_4, "X", ll_4.getX(), ll_4.getX() + offset);
ObjectAnimator anim5 = ObjectAnimator.ofFloat(ll_5, "X", ll_5.getX(), ll_5.getX() + offset);
ObjectAnimator anim6 = ObjectAnimator.ofFloat(ll_6, "X", ll_6.getX(), ll_6.getX() + offset);
ObjectAnimator anim7 = ObjectAnimator.ofFloat(ll_7, "X", ll_7.getX(), ll_7.getX() + offset);
ObjectAnimator anim8 = ObjectAnimator.ofFloat(ll_8, "X", ll_8.getX(), ll_8.getX() + offset);
ObjectAnimator anim9 = ObjectAnimator.ofFloat(ll_9, "X", ll_9.getX(), ll_9.getX() + offset);
AnimatorSet animSet = new AnimatorSet();
animSet.setDuration(durationTime);
animSet.playTogether(anim100, anim101, anim102, anim103, anim1, anim2, anim3, anim4, anim5, anim6, anim7, anim8, anim9);
animSet.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
Log.w(TAG, "动画结束后位置:"+ll_1.getX()+" "+ll_2.getX()+" "+ll_3.getX()+" "
+ll_4.getX()+" "+ll_5.getX()+" "+ll_6.getX()
+" "+ll_7.getX()+" "+ll_8.getX()+" "+ll_9.getX());
setCenter(centerWitch);
animalFinish = true;
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
animSet.start();
}
7、重置预备控件
动画执行完毕之后,要做两个操作。第一个就是将当前不在显示范围的4个子控件左右各放2个,第二步就是为预备控件绑定新的星期日期。下面的方法是根据各个子控件的坐标来判断是隐藏还是展示,然后为隐藏的控件重新安排位置;然后绑定数据:
/*这些引用代表当前正在显示的5个条目 和 四个预备条目,
*由于ll_x系列条目是不断移动的,所以此处需要根据ll_x的位置重新为llx赋值
* 其中ll1-ll5为当前正在显示的条目, ll6、ll7为右边隐藏的预备条目, ll8、ll9为左边的隐藏预备条目
*/
private LinearLayout ll1, ll2, ll3, ll4, ll5, ll6, ll7, ll8, ll9;
/**1、找到正在展示的五个item,并将预备item复位*/
private void setCenter(WEEKDAY weekDay){
//记录当前显示在中间的星期X
centerNow = weekDay;
//1、找到当前显示的5个条目的位置
List<LinearLayout> list = new ArrayList<>(llList);
for(int i = 0; i<5; i++){
for(int j = 0; j<list.size(); j++){
LinearLayout ll = list.get(j);
if(ll.getX()==ITEM_WIDTH*i){
list.remove(ll); //找到之后就remove可以减少后面遍历的次数
// Log.d(TAG, "找到"+i+"了"+ll);
switch (i) {
case 0:
ll1 = ll;
break;
case 1:
ll2 = ll;
break;
case 2:
ll3 = ll;
//当前中间位置item放大
ll3.getChildAt(0).setScaleX(scaleSize);
ll3.getChildAt(0).setScaleY(scaleSize);
break;
case 3:
ll4 = ll;
break;
case 4:
ll5 = ll;
break;
}
}
}
}
Log.i(TAG, "找完后还剩"+list.size()+" 总:"+llList.size());
//2、剩余的四个作为预备,归位,左边隐藏两个,右边隐藏两个
for(int i = 0; i<list.size(); i++){
LinearLayout ll = list.get(i);
switch (i){
case 0: //左1
ll.setX(-ITEM_WIDTH*2);
ll8=ll;
break;
case 1: //左2
ll.setX(-ITEM_WIDTH*1);
ll9=ll;
break;
case 2: //右1
ll.setX(ITEM_WIDTH*5);
ll6=ll;
break;
case 3: //右2
ll.setX(ITEM_WIDTH*6);
ll7=ll;
break;
}
}
//绑定数据
reBoundDataByCenter(weekDay);
}
/**2、重新绑定数据*/
private void reBoundDataByCenter(WEEKDAY weekDay){
if(weekDay == WEEKDAY.wk1){
/*星期1在中间,依次为4、5、6、7、1、2、3、4、5*/
setLLText(ll8, 4, false);
setLLText(ll9, 5, false);
setLLText(ll1, 6, false);
setLLText(ll2, 7, false);
setLLText(ll3, 1, true);
setLLText(ll4, 2, false);
setLLText(ll5, 3, false);
setLLText(ll6, 4, false);
setLLText(ll7, 5, false);
}else if(weekDay == WEEKDAY.wk2){
/*星期2在中间,依次为5、6、7、1、2、3、4、5、6*/
setLLText(ll8, 5, false);
setLLText(ll9, 6, false);
setLLText(ll1, 7, false);
setLLText(ll2, 1, false);
setLLText(ll3, 2, true);
setLLText(ll4, 3, false);
setLLText(ll5, 4, false);
setLLText(ll6, 5, false);
setLLText(ll7, 6, false);
}else if(weekDay == WEEKDAY.wk3){
/*星期3在中间,依次为6、7、1、2、3、4、5、6、7*/
setLLText(ll8, 6, false);
setLLText(ll9, 7, false);
setLLText(ll1, 1, false);
setLLText(ll2, 2, false);
setLLText(ll3, 3, true);
setLLText(ll4, 4, false);
setLLText(ll5, 5, false);
setLLText(ll6, 6, false);
setLLText(ll7, 7, false);
}else if(weekDay == WEEKDAY.wk4){
/*星期4在中间,依次为7、1、2、3、4、5、6、7、1*/
setLLText(ll8, 7, false);
setLLText(ll9, 1, false);
setLLText(ll1, 2, false);
setLLText(ll2, 3, false);
setLLText(ll3, 4, true);
setLLText(ll4, 5, false);
setLLText(ll5, 6, false);
setLLText(ll6, 7, false);
setLLText(ll7, 1, false);
}else if(weekDay == WEEKDAY.wk5){
/*星期5在中间,依次为1、2、3、4、5、6、7、1、2*/
setLLText(ll8, 1, false);
setLLText(ll9, 2, false);
setLLText(ll1, 3, false);
setLLText(ll2, 4, false);
setLLText(ll3, 5, true);
setLLText(ll4, 6, false);
setLLText(ll5, 7, false);
setLLText(ll6, 1, false);
setLLText(ll7, 2, false);
}else if(weekDay == WEEKDAY.wk6){
/*星期6在中间,依次为2、3、4、5、6、7、1、2、3*/
setLLText(ll8, 2, false);
setLLText(ll9, 3, false);
setLLText(ll1, 4, false);
setLLText(ll2, 5, false);
setLLText(ll3, 6, true);
setLLText(ll4, 7, false);
setLLText(ll5, 1, false);
setLLText(ll6, 2, false);
setLLText(ll7, 3, false);
}else if(weekDay == WEEKDAY.wk7){
/*星期7在中间,依次为3、4、5、6、7、1、2、3、4*/
setLLText(ll8, 3, false);
setLLText(ll9, 4, false);
setLLText(ll1, 5, false);
setLLText(ll2, 6, false);
setLLText(ll3, 7, true);
setLLText(ll4, 1, false);
setLLText(ll5, 2, false);
setLLText(ll6, 3, false);
setLLText(ll7, 4, false);
}
}
private void setLLText(LinearLayout ll, int witchDay, boolean showDate){
ll.setTag(witchDay); //便于区分点击事件
LinearLayout innerLL = (LinearLayout)ll.getChildAt(0);
TextView tv = (TextView)innerLL.getChildAt(0);
String text = "星期" + WEEK_STR[witchDay];
tv.setText(text);
TextView tvDate = (TextView)innerLL.getChildAt(1);
text = DATE_STR.get(witchDay);
tvDate.setText(text);
if(showDate){
tvDate.setVisibility(View.VISIBLE);
}else{
tvDate.setVisibility(View.GONE);
}
}
当执行完上面的方法后,控件的状态又回到了初始状态,下次点击又会重复上面的步骤。因为动画执行完后,只有被隐藏的子控件需要重新安排位置,所以,不会出现闪跳的现象。
最终效果图如下:
喜欢请点赞,no爱请勿喷~O(∩_∩)O谢谢
源码下载:
注:没有积分的童鞋 请留言索要代码喔
Android自定义View(RollWeekView-炫酷的星期日期选择控件)的更多相关文章
- Android自定义View,高仿QQ音乐歌词滚动控件!
最近在以QQ音乐为样板做一个手机音乐播放器,源码下篇博文放出.今天我想聊的是这个QQ音乐播放器中歌词显示控件的问题,和小伙伴们一起来探讨怎么实现这个歌词滚动的效果.OK,废话不多说,先来看看效果图: ...
- Photoshop和WPF双剑配合,打造炫酷个性的进度条控件
现在如果想打造一款专业的App,UI的设计和操作的简便性相当重要.UI设计可以借助Photoshop或者AI等设计工具,之前了解到WPF设计工具Expression Blend可以直接导入PSD文件或 ...
- 用c/c++混合编程方式为ios/android实现一个自绘日期选择控件(一)
本文为原创,如有转载,请注明出处:http://www.cnblogs.com/jackybu 前言 章节: 1.需求描述以及c/c++实现日期和月历的基本操作 2.ios实现自绘日期选择控件 3.a ...
- [Ext JS 4] 实战之 带week(星期)的日期选择控件(三)
前言 在 [Ext JS 4] 实战之 带week(星期)的日期选择控件(二) 的最后,有提到一个解决方案. 不过这方案有一个条件 ==> “2. 每年的周数从(1-52), 如果超过52 周 ...
- 【C#】wpf自定义calendar日期选择控件的样式
原文:[C#]wpf自定义calendar日期选择控件的样式 首先上图看下样式 原理 总览 ItemsControl内容的生成 实现 界面的实现 后台ViewModel的实现 首先上图,看下样式 原理 ...
- 【朝花夕拾】Android自定义View篇之(八)多点触控(上)MotionEvent简介
前言 在前面的文章中,介绍了不少触摸相关的知识,但都是基于单点触控的,即一次只用一根手指.但是在实际使用App中,常常是多根手指同时操作,这就需要用到多点触控相关的知识了.多点触控是在Android2 ...
- 【朝花夕拾】Android自定义View篇之(九)多点触控(下)实践出真知
前言 在上一篇文章中,已经总结了MotionEvent以及多点触控相关的基础理论知识和常用的函数.本篇将通过实现单指拖动图片,多指拖动图片的实际案例来进行练习并实现一些效果,来理解前面的理论知识.要理 ...
- 自定义View的学习(一) 自绘制控件
一.自绘控件 就是自己绘制的控件,通过onDraw()方法将控件绘制出来 自定义一个可点击的View 这个View可以记住用户点击的次数 public class CounterView exte ...
- Android 自定义控件之 日期选择控件
效果如下: 调用的代码: @OnClick(R.id.btn0) public void btn0() { final AlertDialog dialog = new AlertDialog.Bui ...
随机推荐
- hdu1045 Fire Net---二进制枚举子集
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1045 题目大意: 给你一幅n*n的图,再给你一些点,这些点的上下左右不能再放其他点,除非有墙('X') ...
- 编码注释coding: utf-8
# -*- coding: utf-8 -*- PY文件当中是不支持中文的,即使你输入的注释是中文也不行,为了解决这个问题,就需要把文件编码类型改为UTF-8的类型,输入这个代码就可以让PY源文件里面 ...
- Java高级篇(二)——网络通信
网络编程是每个开发人员工具相中的核心部分,我们在学习了诸多Java的知识后,也将步入几个大的方向,Java网络编程就是其中之一. 如今强调网络的程序不比涉及网络的更多.除了经典的应用程序,如电子邮件. ...
- ReactNative Android之原生UI组件动态addView不显示问题解决
ReactNative Android之原生UI组件动态addView不显示问题解决 版权声明:本文为博主原创文章,未经博主允许不得转载. 转载请表明出处:http://www.cnblogs.com ...
- java制作验证码(java验证码小程序)
手动制作java的验证码 Web应用验证码的组成: (1)输入框 (2)显示验证码的图片 验证码的制作流程: 生成验证码的容器使用 j2ee的servlet 生成图片需要的类: (1) Buffere ...
- [BZOJ]4405: [wc2016]挑战NPC(带花树)
带花树模板 #include<cstdio> #include<cstring> #include<algorithm> using namespace std; ...
- POJ2135:Farm Tour
题意:给定一个无向图,从1走到n再从n走回1,每个边只能走一遍,求最短路 题解:可以定义一个源点s,和一个汇点t s和1相连容量为2,费用为0, t和n相连容量为2,费用为0 然后所用的边的容量都定为 ...
- ●BZOJ 2209 [Jsoi2011]括号序列
题链: http://www.lydsy.com/JudgeOnline/problem.php?id=2209 题解: Splay 很好的题,但是把智障的我给恶心到了... 首先不难发现,最后没 ...
- bzoj3262陌上花开 cdq分治
3262: 陌上花开 Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 2794 Solved: 1250[Submit][Status][Discus ...
- python中模块,包,库的概念
模块:就是.py文件,里面定义了一些函数和变量,需要的时候就可以导入这些模块. 包:在模块之上的概念,为了方便管理而将文件进行打包.包目录下第一个文件便是 __init__.py,然后是一些模块文件和 ...