美文网首页
《打造高质量Android应用》读书笔记

《打造高质量Android应用》读书笔记

作者: crossroads | 来源:发表于2019-11-17 16:42 被阅读0次

    前言

    最近看到一本书,是开发安卓的一些小技巧和基础知识,大家一起查漏补缺吧!只有一部分,其他的有点老了,还有一些不感兴趣,没继续看了,所以只有9个知识点哦

    1. 使用weight和weightsum属性实现视图居中
    <LinearLayout 
      ......
        android:gravity="center"
        android:orientation="horizontal"
        android:weightSum="1" > //
    
        <Button
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="0.5" //确保按钮占据50%空间
            ......
     />
    </LinearLayout>
    
    2. 在include里使用android:layout_*属性,重写include布局属性,实现复用

    footer布局:

    <TextView xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:gravity="center"
        android:text="@string/footer_text" />
    

    include footer:

    <RelativeLayout
        <include
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_marginBottom="30dp"
            layout="@layout/footer" />
     ......
    /RelativeLayout>
    
    3. ViewStub实现view的延迟加载

    场景:让用户自己决定是否显示地图信息
    地图view

    <com.google.android.maps.MapView xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:clickable="true" 
       ......
    />
    

    使用ViewStub

     <ViewStub
          android:id="@+id/map_stub"
          android:layout_width="fill_parent"
          android:layout_height="fill_parent"
          android:inflatedId="@+id/map_view" 
          android:layout="@layout/map" />
    

    在Activity中调用

      private View mViewStub;
      @Override
      public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        mViewStub = findViewById(R.id.map_stub);
      }
      public void onShowMap(View v) {
        mViewStub.setVisibility(View.VISIBLE);
      }
      ......
    

    inflatedId是调用ViewStub的inflate()方法或setVisibility()方法是返回的ID,这个ID便是被填充的View的ID,避免了使用findViewById()方法

    4.定制ViewGroup

    绘制布局由两个遍历过程组成:测量过程和布局过程。测量过程由measure(int, int)方法完成,该方法从上到下遍历视图树。在递归遍历过程中,每个视图都会向下层传递尺寸和规格。当measure方法遍历结束,每个视图都保存了各自的尺寸信息。第二个过程由layout(int,int,int,int)方法完成,该方法也是由上而下遍历视图树,在遍历过程中,每个父视图通过测量过程的结果定位所有子视图的位置信息。
    为了理解这个概念,下面分析ViewGroup的绘制过程,第一步是测量ViewGroup的宽度和高度,在onMeasure方法中完成这个步骤。在该方法中,ViewGroup通过遍历所有子视图计算它的大小。最后一步操作,在onLayout()方法中完成,利用上一步计算出的测量信息,布局所有子视图。

    作者实现了如下布局:


    1>在values下创建attrs.xml,自定义属性

    <resources>
        <declare-styleable name="CascadeLayout">
            <attr name="horizontal_spacing" format="dimension" />
            <attr name="vertical_spacing" format="dimension" />
        </declare-styleable>
    
        <declare-styleable name="CascadeLayout_LayoutParams">
            <attr name="layout_vertical_spacing" format="dimension" />//属性名前缀是layout_,因此该属性会被添加到LayoutParams的属性表中
        </declare-styleable>
    </resources>
    

    2>布局

    <FrameLayout
      xmlns:anyname="http://schemas.android.com/apk/res-auto"
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" >
    
        <com.XX.view.CascadeLayout
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            anyname:horizontal_spacing="30dp"
           anyname:vertical_spacing="20dp" >
    
            <View
                android:layout_width="100dp"
                android:layout_height="150dp"
               anyname:layout_vertical_spacing="90dp"
                android:background="#FF0000" />
    
            <View
                android:layout_width="100dp"
                android:layout_height="150dp"
                android:background="#00FF00" />
    
            <View
                android:layout_width="100dp"
                android:layout_height="150dp"
                android:background="#0000FF" />
        </com.XX.view.CascadeLayout>
    
    </FrameLayout>
    

    3>自定义CascadeLayout

    public class CascadeLayout extends ViewGroup {
    
      private int mHorizontalSpacing;
      private int mVerticalSpacing;
    
      public CascadeLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    
        TypedArray a = context.obtainStyledAttributes(attrs,
            R.styleable.CascadeLayout);
    
        try {
          mHorizontalSpacing = a.getDimensionPixelSize(
              R.styleable.CascadeLayout_horizontal_spacing,
              getResources().getDimensionPixelSize(
                  R.dimen.cascade_horizontal_spacing));
    
          mVerticalSpacing = a.getDimensionPixelSize(
              R.styleable.CascadeLayout_vertical_spacing, getResources()
                  .getDimensionPixelSize(R.dimen.cascade_vertical_spacing));
        } finally {
          a.recycle();
        }
    
      }
    
      @Override
      protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    // 使用宽和高计算布局的最终大小以及子视图的x和y轴位置
        int width = getPaddingLeft();
        int height = getPaddingTop();
        int verticalSpacing;
    
        final int count = getChildCount();
        for (int i = 0; i < count; i++) {
          verticalSpacing = mVerticalSpacing;
    
          View child = getChildAt(i);
          measureChild(child, widthMeasureSpec, heightMeasureSpec); //令每个子视图测量自身
    
          LayoutParams lp = (LayoutParams) child.getLayoutParams();
          width = getPaddingLeft() + mHorizontalSpacing * i;
    
    // 在LayoutParams中保存每个子视图的x、y坐标
          lp.x = width; 
          lp.y = height;
    
          if (lp.verticalSpacing >= 0) {
            verticalSpacing = lp.verticalSpacing;
          }
    
          width += child.getMeasuredWidth();
          height += verticalSpacing;
        }
    
        width += getPaddingRight();
        height += getChildAt(getChildCount() - 1).getMeasuredHeight()
            + getPaddingBottom();
    
        setMeasuredDimension(resolveSize(width, widthMeasureSpec),
            resolveSize(height, heightMeasureSpec)); // 用计算所得宽高设置整个布局的测量尺寸
      }
    
      @Override
      protected void onLayout(boolean changed, int l, int t, int r, int b) {
    
        final int count = getChildCount();
        for (int i = 0; i < count; i++) {
          View child = getChildAt(i);
          LayoutParams lp = (LayoutParams) child.getLayoutParams();
    
          child.layout(lp.x, lp.y, lp.x + child.getMeasuredWidth(), lp.y
              + child.getMeasuredHeight());
        }
      }
    
      @Override
      protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
        return p instanceof LayoutParams;
      }
    
      @Override
      protected LayoutParams generateDefaultLayoutParams() {
        return new LayoutParams(LayoutParams.WRAP_CONTENT,
            LayoutParams.WRAP_CONTENT);
      }
    
      @Override
      public LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new LayoutParams(getContext(), attrs);
      }
    
      @Override
      protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
        return new LayoutParams(p.width, p.height);
      }
    
      public static class LayoutParams extends ViewGroup.LayoutParams {
        int x;
        int y;
        public int verticalSpacing;
    
        public LayoutParams(Context context, AttributeSet attrs) {
          super(context, attrs);
    
          TypedArray a = context.obtainStyledAttributes(attrs,
              R.styleable.CascadeLayout_LayoutParams);
          try {
            verticalSpacing = a
                .getDimensionPixelSize(
                    R.styleable.CascadeLayout_LayoutParams_layout_vertical_spacing,
                    -1);
          } finally {
            a.recycle();
          }
        }
    
        public LayoutParams(int w, int h) {
          super(w, h);
        }
    
      }
    }
    
    5. TextSwitcher和ImageSwitcher实现平滑过渡

    TextSwitcher: 为文本标签添加动画效果
    ImageSwitcher : 为图片切换添加动画效果

        mTextSwitcher.setFactory(new ViewFactory() {
          @Override
          public View makeView() {
            TextView t = new TextView(MainActivity.this);
            t.setGravity(Gravity.CENTER);
            return t;
          }
        });
        mTextSwitcher.setInAnimation(this, android.R.anim.fade_in);
        mTextSwitcher.setOutAnimation(this, android.R.anim.fade_out);
         mTextSwitcher.setText("hello");
    
    6. 避免在Edittext中验证日期

    在应用程序中使用Android内置资源是一个借用设备样式的好方法,如

      <Button
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:background="@android:drawable/edit_text"
            />
    
    7. 格式化TextView的文本,如链接、不同样式文本等

    链接:

    textView1.setText(Html.fromHtml("<![CDATA[Visit <a href=\"http://manning.com/\">Manning home page</a>]]>"));
    textView1.setMovementMethod(LinkMovementMethod.getInstance());
    

    不同样式

    
        final Spannable text2 = new SpannableString(
            getString(R.string.text2));
        text2.setSpan(new BackgroundColorSpan(Color.RED), 1, 4, 0);
        text2.setSpan(new ForegroundColorSpan(Color.BLUE), 5, 9, 0);
    XX.setText(text2);
    
    8. 横竖屏

    设置android:configChanges="orientation"就不会重启Activity,而是调用onConfigurationChanged()方法

    9. 移除窗口默认背景提高应用程序启动速度
    <resources>
        <style name="Theme.NoBackground" parent="android:Theme">
            <item name="android:windowBackground">@null</item>
            <item name="android:windowNoTitle">true</item>
        </style>
    </resources>
    
    9.更改toast显示位置
     Toast toast = Toast.makeText(this, "Upper Left!",
            Toast.LENGTH_SHORT);
        toast.setGravity(Gravity.TOP | Gravity.LEFT, 0, 0);
        toast.show();
    

    相关文章

      网友评论

          本文标题:《打造高质量Android应用》读书笔记

          本文链接:https://www.haomeiwen.com/subject/sbbeictx.html