上一章讲述了Android界面设计时,一些基本控件的使用,本章主要讲述自定义控件,Fragment和Headler线程机制。
1.自定义控件
(1)基本知识
dp、sp和dx
px:像素点
dp:与像素密度密切相关
sp:相当于dp,修饰文字专用
dip:相当于dp
用法:
文字尺寸一律用sp
非文字尺寸一律用dp
偶尔需要用px 例如:在屏幕上画细的分割线 1px
当一个控件不在右侧预览视图里面显示的时候是因为控件没有明确的位置,需要设置一个位置之后才能正常显示
构造器初始化 :
- onMesure() 定大小
- onLayout() 定位置
- onDraw() 绘制
- invalidate() 刷新
自定义控件的三种主要创建形式:
- 继承已有的控件来实现自定义控件,如 Button、 CheckedTextView;
- 通过继承一个布局文件实现自定义控件,如RelativeLayout;
- 通过继承view类来实现自定义控件。
(2)提取布局属性 theme & style
- Theme是针对窗体级别的,改变窗体样式;Style 是针对窗体元素级别的,改变指定控件或者Layout的样式;
- 抽象view的共同属性;
- 可继承
对于定制一个自定义控件,可通过如下步骤:
(1)基本属性定义在一个配置文件中attrs.xml :
<?xml version="1.0" encoding="utf-8"?>
<resources> //类 <declare-styleable name="ViewTest"> //每一个attr都是一个属性,每个属性都有一个format <attr name="backgroundColor" format="color"/> <attr name="textColor" format="color"/> <attr name="textSize" format="dimension"/> </declare-styleable> </
resources>
(2)定义一个控件View类:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 package com.example.chenjinhua.redcircle; 2 3 import android.content.Context; 4 import android.graphics.Canvas; 5 import android.graphics.Color; 6 import android.graphics.Paint; 7 import android.graphics.Rect; 8 import android.util.AttributeSet; 9 import android.view.View; 10 11 public class DrawRedCircleView extends View implements View.OnClickListener{ 12 private Paint mPaint; 13 private Rect mRect; 14 private int mNumber = 20; 15 16 public DrawRedCircleView(Context context) { 17 this(context, null); 18 } 19 20 public DrawRedCircleView(Context context, AttributeSet attrs) { 21 this(context, attrs, 0); 22 } 23 24 public DrawRedCircleView(Context context, AttributeSet attrs, int defStyleAttr) { 25 super(context, attrs, defStyleAttr); 26 init(); 27 } 28 29 private void init() { 30 mPaint = new Paint(); 31 mRect = new Rect(); 32 } 33 34 @Override 35 protected void onDraw(Canvas canvas) { 36 super.onDraw(canvas); 37 mPaint.setColor(Color.RED); 38 canvas.drawCircle(getWidth() / 2, getWidth() / 2, getWidth() / 2, mPaint); 39 40 mPaint.setColor(Color.WHITE); 41 mPaint.setTextSize(100); 42 String textNumber = String.valueOf(mNumber); 43 mPaint.getTextBounds(textNumber,0,textNumber.length(),mRect); 44 int textWidth = mRect.width(); 45 int textHight = mRect.height(); 46 canvas.drawText(textNumber,getWidth()/2 - textWidth/2,getWidth()/2 + textHight/2,mPaint); 47 48 View view = findViewById(R.id.redCircle_view); 49 view.setOnClickListener(this); 50 51 } 52 53 @Override 54 public void onClick(View view) { 55 if ( mNumber > 0 ){ 56 mNumber --; 57 }else{ 58 mNumber = 20; 59 } 60 invalidate(); 61 } 62 }
(3)视图页面引用:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" //添加自定义命名空间 xmlns:jinhua="http://schemas.android.com/apk/res-auto" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <!--引用自定义的控件--> <com.example.chenjinhua.thirdweek.ViewTest android:layout_width="300dp" android:layout_height="300dp" jinhua:backgroundColor="@color/colorAccent" jinhua:textSize="18dp"/> <!--attrs文件中定义的属性-->
</LinearLayout>
(4)Activity类中定义和使用
2.Fragment
(1)什么是Fragment
Fragment是activity界面中的一部分,多个Fragment组合到一个activity中。多个activity中可重用一个Fragment。
Fragment相当于模块化一个activity具有自己的生命周期,接收自己的事件,在activity运行时被添加或删除。
(2)为什么要使用Fragment
支持更动态更灵活的界面设计,在平板上的应用(左边列表,右边新闻)Activity的layout分成Fragment。
(3)Fragmet应用
getSupportFragmentManager().beginTransaction().
setCustomAnimations(R.anim.slide_in_from_right, R.anim.slide_out_to_left).
replace(R.id.fl_content, new ReadCardFragment(), "latest").
commit();
//setCustomAnimations:指定Fragment切换的动画效果
3.Headler多线程与异步
(1)Handler用来做什么?
- 定时执行Message和MessageQueue;
- 在不同线程中执行Runnable。
(2)Handler怎么使用?
- obtainMessage() //取得消息
- sendMessage() //发送消息
- handlerMessage() //处理消息
(3)Handler基本使用方法:
Handler myHandler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case TestHandler.GUIUPDATEIDENTIFIER:
myBounceView.invalidate();
break;
}
super.handleMessage(msg);
}
};
class myThread implements Runnable {
public void run() {
while (!Thread.currentThread().isInterrupted()) {
Message message = new Message();
message.what = TestHandler.GUIUPDATEIDENTIFIER;
TestHandler.this.myHandler.sendMessage(message);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
}
在android中提供了一种异步回调机制Handler,使用它,我们可以在完成一个很长时间的任务后做出相应的通知。
在主线程中,使用handler很简单,new一个Handler对象实现其handleMessage方法,在handleMessage中提供收到消息后相应的处理方法即可。
使用myThreadHandler.sendEmptyMessage(0);发送一个message对象,那么Handler是如何接收该message对象并处理的呢?如下数据结构图:
从这个图中我们很清楚可以看到调用sendEmptyMessage后,会把 Message对象放入一个MessageQueue队列,该队列属于某个Looper对象,每个Looper对象通过 ThreadLocal.set(new Looper())跟一个Thread绑定了,Looper对象所属的线程在Looper.Loop方法中循环执行从MessageQueue队列读取 Message对象,并把Message对象交由Handler处理,调用Handler的dispatchMessage方法。