Android学习——UI高级组件三
PopupWindow(弹出式窗口)
Android的对话框有两种:PopupWindow和AlertDialog。它们的不同点在于:AlertDialog位置固定,PopupWindow位置随意。
PopupWindow几个方法
showAsDropDown(View anchor)
相对某个控件的位置(正左下方),无偏移
showAsDropDown(View anchor,int xoff,int yoff)
相对某个控件位置,有偏移
showAtLocation(View parent , int gravity,int x,int y)
相对父控件的位置可以设置偏移和无偏移
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/show"
android:text="显示弹出窗口"
android:onClick="showWindow"/>
弹出窗口的布局
<?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">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="修改"
android:layout_weight="1"
android:id="@+id/button_edit"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="删除"
android:layout_weight="1"
android:id="@+id/button_delete"/>
</LinearLayout>
package com.example.myapplication3;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.PopupWindow;
/*
* PopupWindow组件
* */
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
//按钮事件方法
public void showWindow(View v){
View view=getLayoutInflater().inflate(R.layout.window_layout,null);
//实例化创建对象popupwindow(窗体宽高)
PopupWindow popupWindow=new PopupWindow(view,
ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT);
popupWindow.setBackgroundDrawable(getResources().getDrawable(android.R.drawable.btn_default));
popupWindow.setAnimationStyle(android.R.style.Animation_Translucent);
popupWindow.setOutsideTouchable(true);
popupWindow.getBackground().setAlpha(100);
popupWindow.setFocusable(true);
popupWindow.setTouchable(true);
popupWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
//显示
popupWindow.showAtLocation(v, Gravity.BOTTOM,0,0);
}
}
获取屏幕尺寸大小
//获取屏幕尺寸方法
DisplayMetrics md=new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(md);
int width=md.widthPixels;
int height=md.heightPixels;
Notification
应用常规界面外展示的消息
Notification普通通知(Notification drawer标准显示方式)
新建一个button按钮
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="发送一个普通通知"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:onClick="sendNotification1"/>
设置信息
package com.example.myapplication3;
import android.annotation.SuppressLint;
import android.app.Notification;
import android.app.NotificationManager;
import android.content.Context;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.NotificationManagerCompat;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
/*
*Notification
* */
public class Main2Activity extends AppCompatActivity {
private static final int NID_1=0x1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
}
//发送一个普通的通知
public void sendNotification1(View v){
// Notification n=new Notification();//老版本 API 11 之前创建通知的方法
// Notification.Builder builder=new Notification.Builder(this);//API 11 之后使用
//v4支持包
NotificationCompat.Builder builder=new NotificationCompat.Builder(this);
//设置相关属性
builder.setSmallIcon(R.mipmap.ic_launcher);//设置小图标
builder.setContentTitle("你有一条新消息");//设置标题
builder.setContentText("天道酬勤,宁静致远");//设置通知内容
//创建通知对象
Notification n=builder.build();
//获取系统的通知管理器,发送通知
NotificationManager nm= (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
nm.notify(NID_1,n);
}
}
其他属性及事件
builder.setAutoCancel(true);//自动取消
builder.setDefaults(Notification.DEFAULT_ALL);//设置呼吸灯、响铃、震动
builder.setNumber(10);//数据条数
builder.setTicker("新消息");
builder.setOngoing(true);//设置为常驻通知
//定义一个意图,当点击通知时,要打开一个界面(Activity)
Intent intent=new Intent(this,Main3Activity.class);
//参数:上下文,请求编码(没有),意图,创建PendingIntent的方式
// PendingIntent.FLAG_NO_CREATE;//如果有就是用,没有创建
// PendingIntent.FLAG_CANCEL_CURRENT;//取消当前的PI,创建新的
// PendingIntent.FLAG_ONE_SHOT;//只是用一次
// PendingIntent.FLAG_UPDATE_CURRENT;//如果有,更新Intent,没有就创建
PendingIntent pi=PendingIntent.getActivity(this,0,intent,PendingIntent.FLAG_UPDATE_CURRENT);
在Main3Activity关闭通知
//取消指定ID通知
NotificationManager nm= (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
nm.cancel(Main2Activity.NID_1);
若要发送一条短消息给另一个界面
使用方法
//发送一条短消息
Intent.putExtra("msg","天道酬勤,宁静致远");
在另一个Activity界面接收
String msg=getIntent().getStringExtra("msg");
TextView tv=findViewById(R.id.msg);
Notification大视图通知
设置按钮
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="发送一个大视图通知"
android:layout_below="@id/button"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:onClick="sendNotification2"/>
方法
private static final int NID_2=0x2;
//大视图
public void sendNotification2(View v){
NotificationCompat.Builder builder=new NotificationCompat.Builder(this);
//设置相关属性
builder.setSmallIcon(R.mipmap.ic_launcher);//设置小图标
builder.setContentTitle("消息");//设置标题
builder.setContentText("消息");//设置通知内容
//设置大视图样式
NotificationCompat.InboxStyle style=new NotificationCompat.InboxStyle();
style.setBigContentTitle("静夜思");//大视图内容
style.addLine("床前明月光,");
style.addLine("疑是地上霜。");
style.addLine("举头望明月,");
style.addLine("低头思故乡。");
builder.setStyle(style);
style.setSummaryText("作者:李白");//提示文本
builder.setNumber(5);
Notification n=builder.build();
NotificationManager nm= (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
nm.notify(NID_2,n);
}
Notifications进度条通知 (显示一个已知长度的进度条指示器)
button
<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="发送一个进度条通知"
android:layout_below="@id/button2"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:onClick="sendNotification3"/>
方法
private static final int NID_3=0x3;
//进度条通知
public void sendNotification3(View v){
final NotificationCompat.Builder builder=new NotificationCompat.Builder(this);
//设置相关属性
builder.setSmallIcon(R.mipmap.ic_launcher);//设置小图标
builder.setContentTitle("更新中...");//设置标题
builder.setContentText("正在由装逼模式更新至牛逼模式...");//设置通知内容
builder.setProgress(100,5,false);
final NotificationManager nm= (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
nm.notify(NID_3,builder.build());
//模拟更新的线程
new Thread(new Runnable() {
@Override
public void run() {
// int progress=0;
for (int progress=0;progress<=100;progress+=5){
builder.setProgress(100,progress,false);
nm.notify(NID_3,builder.build());
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
builder.setProgress(0,0,true);//设置不确定进度
builder.setContentText("更新完成,由于机主逼格不够,正在返回菜鸟模式");
nm.notify(NID_3,builder.build());
}
}).start();
}
自定义通知
自定义布局custom_layout.xml 支持的布局方式(FrameLayout、LinearLayout、RelatuveLayout)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center">
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxHeight="64dp"
android:maxWidth="64dp"
android:adjustViewBounds="true"
tools:srcCompat="@tools:sample/avatars" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="歌曲名称" />
<Button
android:id="@+id/button5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="播放" />
<Button
android:id="@+id/button6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="下一首" />
</LinearLayout>
//自定义视图通知
public void sendNotification4(View v){
final NotificationCompat.Builder builder=new NotificationCompat.Builder(this);
//设置相关属性
builder.setSmallIcon(R.mipmap.ic_launcher);//设置小图标
builder.setOngoing(true);
// builder.setContentTitle("更新中...");//设置标题
// builder.setContentText("正在由装逼模式更新至牛逼模式...");//设置通知内容
//创建一个远程的视图
RemoteViews views=new RemoteViews(getPackageName(),R.layout.custom_layout);
views.setTextViewText(R.id.textView_song,"陷阱");//设置textview文本
// views.setImageViewResource();//设置imageview图片
views.setTextViewText(R.id.button_play,"暂停");
// views.setOnClickPendingIntent();//设置按钮单击事件
builder.setContent(views);
builder.setTicker("Android播放器");
NotificationManager nm= (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
nm.notify(NID_4,builder.build());
}
样式和主题
样式Style:是给view和window指定外观和格式的属性集合。样式能够指定如宽高、边距、字体颜色大小、背景等属性。样式被定义在一个与布局xml文件分开的xml资源文件中。应用在一个组件上。
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/textView"
android:text="@string/hello_world"
android:textColor="@android:color/holo_blue_dark"
android:textSize="35sp"
android:background="#00ff00"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world"
android:textColor="@android:color/holo_blue_dark"
android:textSize="35sp"
android:background="#00ff00"/>
在value下的style文件中可以这样定义
<style name="Textview_Style">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:textColor">@android:color/holo_blue_dark</item>
<item name="android:textSize">35sp</item>
<item name="android:background">#00ff00</item>
</style>
调用时
<TextView
style="@style/Textview_Style"
android:text="@string/hello_world"
//可继续添加属性,将会覆盖原来style中的属性值/>
ps:parent属性,继承一个系统样式或用xx.yy(xx为继承样式)
主题Theme:应用在整个Activity或应用程序的样式,而不是一个独立的View对象。当一个样式被用作主题时,Activity或应用程序中的每一个view对象都会使用它所支持的美国样式属性。
在清单文件中进行配置
<style name="MyAppTheme">
<item name="android:textColor">#000000</item>
<item name="android:textSize">60sp</item>
</style>
<activity
android:name=".Main4Activity"
android:label="@string/title_activity_main4"
android:theme="@style/MyAppTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
同时Activity类中继承类修改为Activity
自定义组件
三种方式:1.组合现有Android默认提供的组件:继承ViewGroup或其子layout类等布局类进行组合;2.调整现有Android默认提供的组件:继承子类具体类;3.完全自定义:继承view基类,里面界面及事件完全由自己控制。
1.自定义组件实现步骤
配置xml属性资源文件values目录下attr.xml,在其中定义样式。
<resources>
<declare-styleable name="MyView">
<attr name="textColor" format="color"></attr>
<attr name="textSize" format="dimension"></attr>
<attr name="text" format="string"></attr>
</declare-styleable>
</resources>
在自定义类中引用
package com.example.myapplication3;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
public class MyView extends View {
private int textColor;
private int textSize;
private String text;
private Paint paint;//画笔
public MyView(Context context) {
super(context);
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
paint=new Paint();
//获取配置文件中的属性值
TypedArray array=context.obtainStyledAttributes(attrs,R.styleable.MyView);
textColor = array.getColor(R.styleable.MyView_textColor,0xffffff);
textSize= (int) array.getDimension(R.styleable.MyView_textSize,24);
text=array.getString(R.styleable.MyView_text);
}
public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
//视图的绘制事件方法
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
paint.setColor(textColor);
paint.setTextSize(textSize);
//画布
canvas.drawText(text,10,10,paint);
}
}
使用自定义组件
<com.example.myapplication3.MyView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/textView"
app:textColor="#ff0000"
app:textSize="16sp"
app:text="威哥新浪微博:http://weibo.com/jianweima"/>
2.自定义组件Scrollview嵌套Listview的冲突
现在strings下定义一列数组,用于显示在ListView上
<string-array name="names">
<item>路人甲</item>
<item>炮灰乙</item>
<item>流氓丙</item>
<item>土匪丁</item>
<item>火柴人</item>
<item>貂蝉</item>
<item>吕布</item>
<item>服部半藏</item>
<item>魏忠贤</item>
<item>东方不败</item>
<item>曾小贤</item>
<item>胡一菲</item>
<item>陈美嘉</item>
<item>吕子乔</item>
<item>关谷神奇</item>
<item>唐悠悠</item>
<item>陆展博</item>
<item>张伟</item>
</string-array>
然后在布局文件中
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Main6Activity">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:entries="@array/names"></ListView>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/button"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/button1"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/button2"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/button3"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/button4"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/button5" />
</LinearLayout>
</ScrollView>
</LinearLayout>
若直接在滚动条组件Scrollview下加上Listview,会出现Listview显示不全的问题,只会显示列表中第一个内容,所以需要另外自定义一个ListView类
package com.example.myapplication3;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.ListView;
public class MyListView extends ListView {
public MyListView(Context context) {
super(context);
}
public MyListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyListView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
//绘制组件时,重新测量宽度空间和高度空间
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
heightMeasureSpec=MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE>>2,MeasureSpec.AT_MOST);//内容多大就有多大
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
然后调用自定义的listView
<com.example.myapplication3.MyListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:entries="@array/names"></com.example.myapplication3.MyListView>