Android--View自定义-折叠

Posted time_iter

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android--View自定义-折叠相关的知识,希望对你有一定的参考价值。

一:效果描述:
1-:点击title部分,展开布局;
2-:点击title部分,隐藏布局;
3-:布局的隐藏与展示都是一个渐变,title右边的图片切换方向;


二:需求分析:
1-:控制由左边的数字,左边的文字,右边的图片以及隐藏布局中的组件组成;
2-:点击标题,控制布局,进一步隐藏布局里面的控件显示或者隐藏;
3-:布局的显示隐藏伴随右边图片箭头方向

三:功能实现思路:
1-:提供六个控件:左边的数字,左边的文字,右边的图案,title总布局,隐藏的布局;
2-:提供设置隐藏布局的方法, 并对布局宽高进行设置,需要测量;
3-:布局隐藏显示动画应与右边图片箭头方向保持一致<时间一致>;

四:自定义view的布局:
1-:main_view.xml:

<?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="wrap_content"
    android:background="#ffffff"
    android:orientation="vertical">


    <RelativeLayout
        android:id="@+id/title_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:id="@+id/layout_number"
            android:layout_width="70px"
            android:layout_height="70px"
            android:gravity="center"
            android:layout_centerVertical="true"
            android:background="@drawable/tv_color"
            android:clickable="false"
            android:text="1"
            android:textStyle="bold"
            android:textColor="#EBEFEC"
            android:textSize="35px" />

        <TextView
            android:id="@+id/layout_title"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_toRightOf="@id/layout_number"
            android:layout_marginLeft="30px"
            android:clickable="false"
            android:textColor="#1d953f"
            android:textSize="46px" />


        <ImageView
            android:src="@mipmap/arrow_up"
            android:id="@+id/layout_image"
            android:layout_width="48px"
            android:layout_height="27px"
            android:layout_alignParentRight="true"
            android:layout_centerVertical="true"
            android:clickable="false"
            android:scaleType="fitCenter" />
    </RelativeLayout>

    <View
        android:layout_width="match_parent"
        android:layout_height="2px"
        android:layout_below="@id/title_layout"
        android:background="#E7E7EF"
        android:clickable="false"
        />

    <RelativeLayout
        android:id="@+id/content_layout"
        android:visibility="gone"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
    </RelativeLayout>

</LinearLayout>

五:自定义View,获取属性,自定义一些方法:
1-:布局的显示与隐藏是通过控制Visibility,右上角角图片,是通过控制动画进行旋转实现:
2-:代码具体实现:

public class CollapseView extends LinearLayout
     Context mcontext;
     TextView  numberTv,titleTv;
     ImageView titleImg;
     Drawable titleBmp;

     RelativeLayout titleLayout,contentLayout;

    long duration=300l;

    int parentWidthMeasureSpec;
    int parentHeightMeasureSpec;
    float titlenumberSize,titlenameSize;

    public CollapseView(Context context) 
        super(context);
    

    public CollapseView(Context context, AttributeSet attrs) 
        super(context, attrs);
        mcontext=context;
        LayoutInflater.from(mcontext).inflate(R.layout.view_layout,this);
        initType(mcontext,attrs);
        initView();
    


    public void initType(Context context, AttributeSet attrs)
        TypedArray typedArray=context.obtainStyledAttributes(attrs,R.styleable.CollapseView,0,0);
        titleBmp=typedArray.getDrawable(R.styleable.CollapseView_titleimg);
        titlenumberSize=typedArray.getDimensionPixelSize(R.styleable.CollapseView_titlenumberSize, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,16,getResources().getDisplayMetrics()));
        titlenameSize=typedArray.getDimensionPixelSize(R.styleable.CollapseView_titlenameSize, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,16,getResources().getDisplayMetrics()));
        typedArray.recycle();

    


    public void initView()
        numberTv=(TextView) findViewById(R.id.layout_number);
        titleTv=(TextView) findViewById(R.id.layout_title);
        titleImg=(ImageView) findViewById(R.id.layout_image);
        titleLayout=(RelativeLayout) findViewById(R.id.title_layout);
        contentLayout=(RelativeLayout) findViewById(R.id.content_layout);
        if (titlenameSize!=0)
            titleTv.setTextSize(titlenumberSize);
        

        if (titlenumberSize!=0)
            numberTv.setTextSize(titlenumberSize);
        

        if (titleBmp!=null)
            titleImg.setImageDrawable(titleBmp);
        


        titleLayout.setOnClickListener(new OnClickListener() 
            @Override
            public void onClick(View v) 
                rotateArrow();
            
        );

        collapse(contentLayout);
    


    /**
     * 设置数字
     *
     */
    public void setNumber(String number)
        if(!TextUtils.isEmpty(number))
            titleTv.setText(number);
        
    

    /**
     * 设置标题
     *
     */
    public void setTitle(String title)
        if(!TextUtils.isEmpty(title))
            titleTv.setText(title);
        
    


    /**
     * 实际上在使用因此布局的时候仅需要传入布局的ID
     */
    public void setContent(int resID)
        View view=LayoutInflater.from(mcontext).inflate(resID,null);
        RelativeLayout.LayoutParams layoutParams=
                new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
        view.setLayoutParams(layoutParams);
        contentLayout.addView(view);
    


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) 
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        parentWidthMeasureSpec=widthMeasureSpec;
        parentHeightMeasureSpec=heightMeasureSpec;
    


     //右上角图标旋转
    public void rotateArrow()
        int degree=0;
        if (titleImg.getTag()==null||titleImg.getTag().equals(true))
            titleImg.setTag(false);
            degree=-180;
            expand(contentLayout);
        else 
            degree=0;
            titleImg.setTag(true);
            collapse(contentLayout);
        
        titleImg.animate().setDuration(duration).rotation(degree).start();
    


    //展开
    private void expand(final View view)
        WindowManager  wm=(WindowManager)mcontext.getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics displayMetrics=new DisplayMetrics();
        wm.getDefaultDisplay().getMetrics(displayMetrics);
        view.measure(parentWidthMeasureSpec,parentHeightMeasureSpec);
        final int measuredHeight = view.getMeasuredHeight();
        view.setVisibility(View.VISIBLE);

        Animation animation=new Animation() 
            @Override
            protected void applyTransformation(float interpolatedTime, Transformation t) 
                if (interpolatedTime==1)
                    view.getLayoutParams().height=measuredHeight;
                else 
                    view.getLayoutParams().height=(int) (measuredHeight*interpolatedTime);
                
                view.requestLayout();
            


            @Override
            public boolean willChangeBounds() 
                return true;
            
        ;
        animation.setDuration(duration);
        startAnimation(animation);
    


   //折叠
    public void collapse(final View view)
       final   int measuredHeight=view.getMeasuredHeight();

        Animation animation=new Animation() 
            @Override
            protected void applyTransformation(float interpolatedTime, Transformation t) 

                if (interpolatedTime==1)
                    view.setVisibility(View.GONE);
                else 
                    view.getLayoutParams().height = measuredHeight - (int) (measuredHeight * interpolatedTime);
                    view.requestLayout();
                
            
        ;
        animation.setDuration(duration);
        startAnimation(animation);
    


3-:部门代码解析:
-1:initType()获取自定义的属性,进行初始化,可以对自定义View的组件属性进行控制;
-2:initView()获取自定义View使用到组件,进行初始化;
-3:setNumber()可以对左边的TextView数字进行,默认为1;
-4: setTitle()可以对中间的TextView设置文字;
-5: setContent()设置显示隐藏的布局,只关注布局id,不关注布局包含哪些组件;
-6: expand()实现隐藏布局的展示,其中,需要知道,当一个view的Visibility状态为GONE时,系统在measure阶段不会去进行测量,所以,当显示布局的时候无法得知到布局的宽和高,但是,可以得知,在view的measure阶段,系统会测量宽高,而此时,可以通过getMeasuredWidth()getMeasuredHeight()
就可以获取到测量的宽高。
-7:通过传入隐藏布局的id,把布局转化为view,使用addview()可以把布局添加到其他组件上。
-8:可以通过手动测绘的方式对布局设置宽高:

则:

WindowManager  wm=(WindowManager)mcontext.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics displayMetrics=new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(displayMetrics);
view.measure(parentWidthMeasureSpec,parentHeightMeasureSpec);

-9:布局展开,借助动画实现:

applyTransformation(float interpolatedTime, Transformation t)

animation的interpolatedTime值在一定的时间内可以从0变化到1,所以,可以使用它进行布局高度的渐次展开扩大:

view.getLayoutParams().height=(int) (measuredHeight*interpolatedTime);
measuredHeight * interpolatedTime

表示了content的高从0到measuredHeight的逐次变化,在这个变化的过程中不断调用

view.requestLayout();

不断刷新页面,就可以达到效果;

-10:

requestLayout 

View重新调用一次layout过程;

总结:技术关键点:手动测量view 的方式来获取view的宽高。

另附:
左上角TextView的背景色的xml:
1-:tv_color:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval"
    android:useLevel="false">

    <solid android:color="@color/colorAccent"/>
    <padding
        android:left="2dp"
        android:top="1dp"
        android:right="2dp"
        android:bottom="1dp"
        />

    <solid android:color="@color/colorAccent"/>
    <stroke android:width="1dp" android:color="@color/colorAccent"/>
    <size android:width="15dp"
        android:height="15dp"/>

</shape>

2-:自定义属性xml:

<resources>
    <declare-styleable name="CollapseView">

        <attr name="titlenumberSize" format="dimension"/>
        <attr name="titlenameSize" format="dimension"/>
        <attr name="titleimg"  format="reference"/>
    </declare-styleable>
</resources>

3-:使用:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="vertical"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    tools:context="com.example.erhu.view01.MainActivity">

    <com.example.erhu.view01.CollapseView
    android:id="@+id/mian"
        app:titlenameSize="20sp"
        app:titlenumberSize="20sp"
    android:orientation="vertical"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">

</com.example.erhu.view01.CollapseView>

</LinearLayout>

4-:使用时,需要使用setcontent设置content布局id:

collapseView=(CollapseView)findViewById(R.id.mian);
collapseView.setContent(R.layout.mian_view);

以上是关于Android--View自定义-折叠的主要内容,如果未能解决你的问题,请参考以下文章

Android view的测量及绘制

Android View measure流程详解

Android View知识

Android - View 绘制流程

Android——View的工作原理

图解Android View的scrollTo(),scrollBy(),getScrollX(), getScrollY()