第三章 关于控件的一些技巧

1.避免EditText输入日期时的验证

当在EditText输入日期时,通常需要对输入的日期进行验证,然而我们可以用Button代替EditText,从而避免验证。

首先,使用Button控件替代EditText控件,但给Button控件设置一个EditText控件的背景,使之看起来像一个EditText控件,如下:

<Button
        android:id="@+id/details_date"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="输入日期"
        android:textColor="@android:color/holo_red_light"
        android:gravity="center"
        android:background="@android:drawable/edit_text" />

这里的@android:drawable/edit_text是系统自带的背景,即EditText的背景。

然后在java代码里实现当用户点击这个控件时弹出一个日期选择对话框,让用户直接选择日期,而不是输入

  private int mYear;
  private int mMonth;
  private int mDay;
  private OnDateSetListener mDateSetListener;
  private Button mDateButton;
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    // get the current date
    final Calendar c = Calendar.getInstance();
    mYear = c.get(Calendar.YEAR);
    mMonth = c.get(Calendar.MONTH);
    mDay = c.get(Calendar.DAY_OF_MONTH);

    mDateSetListener = new DatePickerDialog.OnDateSetListener() {
      @Override
      public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
        mDateButton.setText(getString(R.string.picked_date_format, monthOfYear, dayOfMonth, year));
      }
    };

    mDateButton=(Button)findViewById(R.id.details_date);
    mDateButton.setOnClickListener(new OnClickListener() {
      @Override
      public void onClick(View v) {
        showDatePickerDialog();
      }
    });
  }
  private void showDatePickerDialog(){
    new DatePickerDialog(this,mDateSetListener,mYear, mMonth,mDay).show();
  }

总结:你也许会问,为什么不直接在EditText上设置点击事件,而要用一个Button去替代呢?因为使用Button更加安全,用户也不能修改Button的文字显示。你也可以使用TextWatcher来验证用户的输入,但是这将耗费更多的时间。在app中使用android的系统资源能非常好地利用设备的原有风格。

2.格式化TextView的文字显示

上面这条tweet,由不同的文字风格和颜色组成:黑色、蓝色,还有一部分点击可以打开一个网址。让人觉得这是一个自定义控件来展示这些信息,实际上只用一个TextView控件就能实现。下面将通过一个例子来展示如何给TextView添加不同风格的文字和超链接。

这是xml布局:

<TextView
        android:id="@+id/hello_world"
        android:textSize="18sp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!" />
    <TextView
        android:id="@+id/text_2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="18sp"
        android:layout_below="@+id/hello_world"
        android:layout_marginTop="4dp"
        android:text="我感觉我要喝点水,可你的嘴将我的嘴堵住"
        />

这是java代码:

public class MainActivity extends AppCompatActivity {

    TextView helloWorldText;
    TextView textTwo;
    String textLink="visit <a href=\"http://www.sina.com/\">Sina Home</a>";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //第一个添加超链接
        helloWorldText=(TextView)findViewById(R.id.hello_world);
        helloWorldText.setText(Html.fromHtml(textLink));
        helloWorldText.setMovementMethod(LinkMovementMethod.getInstance());
        //第二个改变前景色和背景色
        textTwo=(TextView)findViewById(R.id.text_2);
        Spannable spannable=new SpannableString(textTwo.getText());
        spannable.setSpan(new BackgroundColorSpan(Color.BLUE),2,5,0);//背景蓝色
        int index=textTwo.getText().toString().indexOf(",");//获取“,”的位置
        spannable.setSpan(new ForegroundColorSpan(Color.YELLOW),index,textTwo.getText().length(),0);//前景黄色
        textTwo.setText(spannable);
    }
}

效果如下:点击Sina Home可以跳转到新浪首页

3.给文字添加发光效果

给文字添加如下图所示的LED效果。

首先新建一个LedTextView继承自TextView,这个类主要用于设置字体效果。

public class LedTextView extends TextView {

  private static final String FONTS_FOLDER = "fonts";
  private static final String FONT_DIGITAL_7 = FONTS_FOLDER
      + File.separator + "digital-7.ttf";

  public LedTextView(Context context) {
    super(context);
    init(context);
  }

  public LedTextView(Context context, AttributeSet attrs) {
    super(context, attrs);
    init(context);
  }

  public LedTextView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    init(context);
  }

  private void init(Context context) {
    AssetManager assets = context.getAssets();
    final Typeface font = Typeface.createFromAsset(assets,FONT_DIGITAL_7);//设置字体
    setTypeface(font);
  }

}

然后在布局中设置两个LedTextView,一个用来显示88:88:88的背景,一个用来显示当前的时间,如下:

<merge xmlns:android="http://schemas.android.com/apk/res/android" >

    <com.manning.androidhacks.hack011.view.LedTextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="88:88:88"
        android:textColor="#3300ff00"
        android:textSize="80sp" />

    <com.manning.androidhacks.hack011.view.LedTextView
        android:id="@+id/main_clock_time"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:textColor="#00ff00"
        android:textSize="80sp" />

</merge>

在activity中设置

public class MainActivity extends Activity {

  private static final String DATE_FORMAT = "%02d:%02d:%02d";
  private static final int REFRESH_DELAY = 500;

  private final Handler mHandler = new Handler();
  private final Runnable mTimeRefresher = new Runnable() {
    @Override
    public void run() {
      final Date d = new Date();
      mTextView.setText(String.format(DATE_FORMAT, d.getHours(),
          d.getMinutes(), d.getSeconds()));
      mHandler.postDelayed(this, REFRESH_DELAY);
    }
  };

  private TextView mTextView;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    mTextView = (TextView) findViewById(R.id.main_clock_time);
  }

  @Override
  protected void onResume() {
    super.onResume();
    mHandler.post(mTimeRefresher);
  }

  @Override
  protected void onStop() {
    super.onStop();
    mHandler.removeCallbacks(mTimeRefresher);
  }
}

其中%02d是用来限制数字格式的,2是代表宽度,如果整数不够2列就补上0,比如printf("%02d"
,3);结果就是03,

如果数字大于2则没有影响,比如printf("%02d",1234);结果是1234

4.为控件添加圆角背景

直接给控件添加一个drawable背景就行了,没什么好说的

<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <solid android:color="#AAAAAA"/>
    <corners android:radius="15dp"/>
</shape>

5.在onCreate()方法中获取控件的高度和宽度

如果在onCreate()方法中直接调用view的getHeight()和getWidth()方法,都只会返回0,也就是获取不到控件的高和宽。因为布局的绘制过程分为两个步骤,measure和layout,首先测量布局和其中每一个控件的宽和高,然后确定每一个控件在布局中的摆放位置。控件在第二个步骤才能获得宽度和高度,而layout发生在onCreate()方法调用之后,因此在onCreate()方法中无法获得控件的宽高。

为了解决这一问题,可以使用view的post()方法,这个方法接收一个Runnable参数并把它添加到消息队列中。这个Runnable方法在ui线程中执行。

java代码如下:

  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    mTextView = (TextView) findViewById(R.id.main_clock_time);
    Log.d("crx","before post:textView.width="+mTextView.getWidth()+",textView.height="+mTextView.getHeight());
    mTextView.post(new Runnable() {
      @Override
      public void run() {
        Log.d("crx","after post:textView.width="+mTextView.getWidth()+",textView.height="+mTextView.getHeight());
      }
    });
  }

下面输出的结果:

6.VideoViews和横竖屏切换

这一节主要展示如何让视频在手机旋转的时候自动转换横竖屏

首先布局的时候可以让VidioViews占据整个屏幕,但不可见。然后设置一个view控件,放在当手机竖着时视频的位置。

然后在Manifest文件中为当前activity设置android:configChanges="orientation"属性,这样当手机旋转时就会自动调用onConfigurationChanged()方法。

因此就可以在onConfigurationChanged()方法中添加如下代码:

switch (getResources().getConfiguration().orientation) {//判断横竖屏
    case Configuration.ORIENTATION_LANDSCAPE: {//如果是横屏
      mPortraitContent.setVisibility(View.GONE);//隐藏竖屏控件
      //设置VideoViews的高和宽等属性
      RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
      params.addRule(RelativeLayout.CENTER_IN_PARENT);
      mVideoView.setLayoutParams(params);
      break;
    }

    case Configuration.ORIENTATION_SQUARE:
    case Configuration.ORIENTATION_UNDEFINED:
    case Configuration.ORIENTATION_PORTRAIT:
    default: {//竖屏

      mPortraitContent.setVisibility(View.VISIBLE);//隐藏横屏控件
      int[] locationArray = new int[2];
      mPortraitPosition.getLocationOnScreen(locationArray);//获取控件高和宽
      //设置视频空间高和宽
      RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(mPortraitPosition.getWidth(), mPortraitPosition.getHeight());
      params.leftMargin = locationArray[0];
      params.topMargin = locationArray[1];
      mVideoView.setLayoutParams(params);

      break;
    }
 }

7.移除背景,提高Activity启动速度

在Android ADK中,有一个叫做Hierarchy Viewer的工具,使用这个工具能够清楚地看出布局的层级和复杂程度。(注:真机调试下可能无法查看,如果要使用Hierarchy Viewer最好使用模拟器) 如果我们创建一个默认的android项目,布局代码如下:

<merge xmlns:android="http://schemas.android.com/apk/res/android" >

    <com.manning.androidhacks.hack011.view.LedTextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="88:88:88"
        android:textColor="#3300ff00"
        android:textSize="80sp" />

    <com.manning.androidhacks.hack011.view.LedTextView
        android:id="@+id/main_clock_time"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:textColor="#00ff00"
        android:textSize="80sp" />

</merge>

在Hierarchy Viewer中查看此布局的层级关系图如下:

这个布局中actionbar占了很大部分,实际上我们的布局代码中并没有,是项目的主题自带的,如果去掉actionbar,将会极大地简化布局的层级关系

我们可以在res/values文件夹下添加一个my_theme.xml,在里面自定义主题

<resources>
    <style name="Theme.NoBackground" parent="android:Theme">
        <item name="android:windowNoTitle">true</item>
    </style>
</resources>

把title去掉之后,布局层级关系如下图:

可见层级树深度也降低了一层,分支也少了。在真机上启动app速度也快了一些。

我们已经知道布局里有LinearLayout和LedTextView,这里的DectorView和FrameLayout如何解释呢?FrameLayout是在执行setContentView()方法时创建的,DectorView是层级树的根节点。默认情况下,FrameLayout将会填充整个屏幕,并且拥有默认的背景颜色。DectorView则持有整个屏幕背景。如果我们的UI背景是自定义的,默认情况下设备仍然会花费时间去绘制默认背景。因此如果我们确认不会使用默认背景,就可以把默认背景移除掉,这样可以加快activity的创建速度。

去除默认背景的方法也很简单,只要在刚才的style属性中添加一项属性如下:

<resources>
    <style name="Theme.NoBackground" parent="android:Theme">
        <item name="android:windowNoTitle">true</item>
        <item name="android:windowBackground">@null</item>
    </style>
</resources>

8.自定义Toast

Toast的位置默认在屏幕底部正中间,但是我们也能让Toast显示在其它位置。使用Toast.setGravity(int gravity, int xOffset, int yOffset)方法。

比如:

toast.setGravity(Gravity.TOP|Gravity.LEFT, 0, 0);

让toast显示在屏幕的左上角

自定义一个Toast

先在xml中写好toast的布局,如下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:id="@+id/toast_layout_root"
              android:orientation="horizontal"
              android:layout_width="fill_parent"
              android:layout_height="fill_parent"
              android:padding="8dp"
              android:background="#DAAA"
              >
    <ImageView android:src="@drawable/droid"
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:layout_marginRight="8dp"
               />
    <TextView android:id="@+id/text"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:textColor="#FFF"
              />
</LinearLayout>

然后在java代码中把布局添加到toast中并显示出来:

LayoutInflater inflater = getLayoutInflater();
View layout = inflater.inflate(R.layout.custom_toast,(ViewGroup)findViewById(R.id.toast_layout_root));

TextView text = (TextView) layout.findViewById(R.id.text);
text.setText("This is a custom toast");

Toast toast = new Toast(getApplicationContext());
toast.setGravity(Gravity.CENTER_VERTICAL, 0, 0);
toast.setDuration(Toast.LENGTH_LONG);
toast.setView(layout);
toast.show();
时间: 2024-10-28 20:39:17

第三章 关于控件的一些技巧的相关文章

第三章 按钮控件的创建

一.前言 不知不觉一晃两个月过去,说来惭愧,在此期间alterto一直没有再研究DuiEngine.主要是因为DuiEngine的作者现在构建一个新的界面库soui,而笔者也一直处于观望状态,因为DuiEngine的作者说了以后可能就不维护DuiEngine了,要把主要的经历放在SOUI上.alterto顿时犹豫了,既然这样我还为DuiEngine做什么教程啊.于是这两个月的时间里一直都很犹豫,也没有再出DuiEngine相关的教程.现在看来这种焦躁对于一个优秀的程序猿来说着实不应该,这也正暴露

深入浅出ExtJS 第三章 表格控件(未完)

1 3.1 表格的特性简介 2 >.Ext中的表格功能:包括排序/缓存/拖动/隐藏某一列/自动显示行号/列汇总/单元格编辑等实用功能; 3 >.表格由类Ext.grid.GridPanel定义,继承自Ext.Panel,其xtype为grid; 4 >.表格控件必须包含列(columns)定义信息,并指定表格的数据存储器(Ext.data.Store); 1 3.2 制作一个简单的表格 2 >1.列的定义是一个JSON数组,它是整个表格的列模型,应该首先创建; 3 var colu

android快速上手(三)常用控件使用

完成了android的第一个程序HelloWorld,下面就开始控件的学习,下面是一些常见的控件. (一)TextView 简单的文本描述 (二)EditText 编辑框,输入文字信息 (三)Button 按钮,点击后会触发点击事件,可以对事件进行处理 (四)ImageView 图片控件,可以加载图片显示 (五)ListView 列表,需要跟适配器Adapter结合,适配器提供数据 (六)Toast 闪现提示语,常用于普通的提示文本,只显示一小段时间自动消失 (七)ScrollView 一般用于

WP8.1学习系列(第十二章)——全景控件Panorama开发指南

2014/6/18 适用于:Windows Phone 8 和 Windows Phone Silverlight 8.1 | Windows Phone OS 7.1 全景体验是本机 Windows Phone 外观的一部分.与旨在适合手机屏幕边界的标准应用不同,全景应用通过使用超出屏幕边界的长水平画布提供了一个查看控件.数据和服务的独特方式.这些固有的动态视图使用分层动画和内容,以便各层以不同的速度流畅地平移,类似于视差效果. 本主题包括以下部分. 全景控件概述 导航支持 全景应用功能 相关

《Programming WPF》翻译 第5章 7.控件模板

原文:<Programming WPF>翻译 第5章 7.控件模板 如果仔细的看我们当前的TTT游戏,会发现Button对象并没有完全为我们工作.哪些TTT面板有内圆角? 图5-14 这里,我们真正需要的是能够保持按钮的行为,如支持内容和点击事件,但是我们想要接管这些按钮的外观.WPF允许这种方式,因为内在的控件创建的时候是缺少外观性的,例如,他们提供行为,但是外观可以被完全包装在客户端控件的外面. 还记得我们是如何使用数据模板,来为非可视化对象提供外观的么?我们能够使用控件模板对控件做同样的

Silverlight学习笔记(三):控件布局管理

简介: 学习Silverlight控件在页面上是如何进行布局,实现多种复杂布局 一.常见的三种布局方式 1. Silverlight学习笔记(三):控件布局管理,码迷,mamicode.com

深入Windows窗体原理及控件重绘技巧

之前有学MFC的同学告诉我觉得Windows的控件重绘难以理解,就算重绘成功了还是有些地方不明白,我觉得可能很多人都有这样的问题,在这里我从Windows窗体的最基本原理来讲解,如果你有类似的疑惑希望这篇文章可以帮你解惑. 1.Windows窗体原理 首先,如果看过Win32 SDK编程的都知道Windows的三大核心系统:负责窗口对象产生和消息分发的USER模块,负责图像显示绘制的GDI模块,负责内存.进程.IO管理的KERNEL模块.试想象一下如何在一个像素阵列上产生窗口对象,其实就是使用G

【WPF学习】第五十九章 理解控件模板

最近工作比较忙,未能及时更新内容,敬请了解!!! 对于可视化树的分析引出了几个有趣问题.例如,控件如何从逻辑树表示扩张成可视化树表示? 每个控件都有一个内置的方法,用于确定如何渲染控件(作为一组更基础的元素).该方法称为控件模板(control template),是用XAML标记块定义的. 下面是普通Button类的模板的简化版本.该版本省略了XML明朝空间声明.为嵌套的元素设置属性的特性,以及当按钮被禁用.取得焦点或单击时确定按钮行为的触发器: <ControlTemplate ...>

webform(三)Repeater控件

Repeater 控件用于显示重复的项目列表,这些项目被限制在该控件.Repeater 控件可被绑定到数据库表.XML 文件或者其他项目列表. 一.建实体类和数据访问类 建立的方法和winform一样,建立时会提示类文件应该放在App_Code文件里,是否放入,选择是,会自动创建该文件夹并将类放进去. webform没有命名空间. 实体类: public class Users { public int Ids { get; set; } public string Ucode { get; s