(创建页面,内容为“<nowiki>分类:编程</nowiki>”) |
无编辑摘要 |
||
第1行: | 第1行: | ||
< | [[分类:编程]] | ||
==项目中引用MPChartLib== | |||
1、 将MPChartLib文件夹拷贝到项目根目录 | |||
2、在根目录里的settings.gradle里增加include ':app', ':MPChartLib' | |||
3、将文件MPChartLib.aar拷贝到libs文件夹里 | |||
4、在build.grade(app)中增加 | |||
dependencies { | |||
implementation project(':MPChartLib') | |||
} | |||
==设置app自动启动== | |||
增加权限 | |||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/> | |||
注册消息接收 | |||
<receiver android:name=".BootBroadcastReceiver"> | |||
<intent-filter> | |||
<action android:name="android.intent.action.BOOT_COMPLETED" /> | |||
</intent-filter> | |||
</receiver> | |||
消息接收函数 | |||
class BootBroadcastReceiver: BroadcastReceiver() { | |||
override public fun onReceive(context: Context, intent: Intent) { | |||
val mBootIntent = Intent(context, MainActivity::class.java) | |||
mBootIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) | |||
context.startActivity(mBootIntent) | |||
} | |||
} | |||
==获取位置信息(kotlin)== | |||
val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager | |||
val location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER) | |||
if (location != null) { | |||
val sb = StringBuffer() | |||
sb.append('实时的位置信息:经度:') | |||
sb.append(location.longitude) | |||
sb.append('纬度:') | |||
sb.append(location.latitude) | |||
sb.append('高度:') | |||
sb.append(location.altitude) | |||
sb.append('速度:') | |||
sb.append(location.speed) | |||
sb.append('方向:') | |||
sb.append(location.bearing) | |||
sb.append('精度:') | |||
sb.append(location.accuracy) | |||
Toast.makeText(applicationContext, sb.toString(), Toast.LENGTH_LONG).show() | |||
} | |||
添加权限 | |||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> | |||
==发送Notification消息(kotlin)== | |||
fun sendNotification(channel_id:String ,channle_name:String,nTitle:String,nContentText:String,id:Int){ | |||
var notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager | |||
var notification: Notification? = null | |||
//val intent = Intent(Intent.ACTION_VIEW, Uri.parse('http://www.baidu.com/')) | |||
//val pendingIntent = PendingIntent.getActivity(this, 0, intent, 0) | |||
//如需链接到网站使用注释代码 | |||
val intent = Intent() | |||
intent.setClass(this@MainActivity, MainActivity::class. | |||
val pendingIntent = PendingIntent.getActivity(this, 0, intent, 0) | |||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { | |||
val mChannel = NotificationChannel(channel_id, channle_name, NotificationManager.IMPORTANCE_LOW) | |||
notificationManager.createNotificationChannel(mChannel) | |||
notification = Notification.Builder(this) | |||
.setChannelId(channel_id) | |||
.setContentTitle(nTitle) | |||
.setContentText(nContentText) | |||
.setContentIntent(pendingIntent) | |||
.setSmallIcon(R.drawable.house).build() | |||
} else { | |||
val notificationBuilder = NotificationCompat.Builder(this) | |||
.setContentTitle(nTitle) | |||
.setContentText(nContentText) | |||
.setSmallIcon(R.drawable.house) | |||
.setOngoing(true) | |||
//.setChannel(id)//无效 | |||
notification = notificationBuilder.build() | |||
} | |||
notificationManager.notify(id, notification) | |||
} | |||
==禁止使用http链接解决方法== | |||
访问网络时报异常 | |||
Cleartext HTTP traffic to not permitted | |||
在<application标签里增加android:usesCleartextTraffic="true"即可 | |||
==bitmap缩小显示== | |||
var matrix = Matrix() | |||
matrix.postScale(0.3f,0.3f)//长和宽放大缩小的比例 | |||
val resizeBmp = Bitmap.createBitmap(bitmap,0,0,bitmap.getWidth(),bitmap.getHeight(),matrix,true) | |||
==textview 连续左移== | |||
设置一下参数,自动连续左移动 | |||
android:ellipsize="marquee" | |||
android:focusable="auto" | |||
android:focusableInTouchMode="true" | |||
android:marqueeRepeatLimit="marquee_forever" | |||
android:scrollHorizontally="true" | |||
android:singleLine="true" | |||
==useAndroidx Error== | |||
编译报错 This project uses AndroidX dependencies, but the 'android.useAndroidX' property is not enabled. | |||
在gradle.propeties文件里增加如下语句,允许AnsiroidX | |||
android.useAndroidX=true | |||
==post获取数据(kotlin)== | |||
Thread(Runnable { | |||
val toMain1 = mAppMesHandler.obtainMessage() | |||
toMain1.arg1 = 1 | |||
var conn: HttpURLConnection? = null | |||
var urlString = "http://server/new.php" | |||
try { | |||
conn = URL(urlString).openConnection() as HttpURLConnection | |||
conn.requestMethod = "POST" // 指定POST请求 | |||
conn.doOutput = true // 设置请求过程可以传递参数给服务器 | |||
// post请求参数 | |||
val param = String.format("name=%s&age=%s&action=%s", "fengxueyan", "23", "query") | |||
DataOutputStream(conn.outputStream).use { os -> | |||
os.writeBytes(param) | |||
} | |||
conn.connect() | |||
conn.inputStream.use { input -> | |||
val data = input.bufferedReader().readText() | |||
toMain1.obj = data.toString() | |||
} | |||
} catch (e: Exception) { | |||
toMain1.obj = e.toString() | |||
} finally { | |||
conn?.disconnect() | |||
} | |||
mAppMesHandler.sendMessage(toMain1) | |||
}).start() | |||
//访问网络必须使用线程,而且线程不允许更新UI | |||
val mAppMesHandler = object : Handler() { | |||
override fun handleMessage(msg: Message) { | |||
if(msg.arg1 == 1){ | |||
var hList0 = msg.obj as String | |||
textView.setText(hList0) | |||
// Toast.makeText(applicationContext,hList0,Toast.LENGTH_LONG).show() | |||
} | |||
} | |||
} | |||
==时间日期选择== | |||
<TimePicker | |||
android:id="@+id/ptime" | |||
android:layout_width="310dp" | |||
android:layout_height="347dp" | |||
app:layout_constraintEnd_toEndOf="parent" | |||
app:layout_constraintStart_toStartOf="parent" | |||
app:layout_constraintTop_toBottomOf="@+id/button2" /> | |||
textView.setText(ptime.hour.toString()+":"+ptime.minute.toString()) | |||
<DatePicker | |||
android:id="@+id/pdate" | |||
android:layout_width="358dp" | |||
android:layout_height="428dp" | |||
android:layout_marginTop="20dp" | |||
app:layout_constraintEnd_toEndOf="parent" | |||
app:layout_constraintHorizontal_bias="0.566" | |||
app:layout_constraintStart_toStartOf="parent" | |||
app:layout_constraintTop_toBottomOf="@+id/button2" /> | |||
textView.setText(pdate.year.toString()+"-"+(pdate.month+1).toString()+"-"+pdate.dayOfMonth.toString()) | |||
==多个Fragment和Activity的简易数据交换方法(kotlin)== | |||
动态创建多个Fragment后,和Activity数据交换有很多种方式,消息方式简单快捷,代码量少 | |||
在Activity中定义消息处理 | |||
val mMainHandler = object : Handler() { | |||
override fun handleMessage(msg: Message) { | |||
if (msg.arg1 == 1) { | |||
val sVerRes = msg.obj as String | |||
Toast.makeText(applicationContext, sVerRes, Toast.LENGTH_LONG).show() | |||
} | |||
} | |||
在Fragment里定义消息handle | |||
private var aHandle:Handler? = null | |||
建立初始化函数,将Activity的消息handle传入 | |||
fun setHandler(AHandler: Handler?) { | |||
try { | |||
aHandle = AHandler | |||
} catch (e: Exception) { | |||
throw ClassCastException(context.toString() | |||
} | |||
} | |||
Activity向Fragment传递数据直接定义函数 | |||
Fragment向Activity传递数据发送消息 | |||
val toMain1 = aHandle!!.obtainMessage() | |||
toMain1.obj = “message or data” | |||
toMain1.arg1 = 1 | |||
aHandle!!.sendMessage(toMain1) | |||
==实现扫码二维码(kotlin)== | |||
dependencies增加引用 | |||
implementation 'com.hongyelinggu:scancode:1.0.0' | |||
申请相机权限 | |||
<uses-permission android:name="android.permission.CAMERA"/> | |||
val REQUEST_EXTERNAL_STORAGE = 1234 | |||
if (ActivityCompat.checkSelfPermission(this, | |||
"android.permission.CAMERA") != PackageManager.PERMISSION_GRANTED ) { | |||
ActivityCompat.requestPermissions(this, | |||
arrayOf(Manifest.permission.CAMERA), REQUEST_EXTERNAL_STORAGE) | |||
} | |||
else{ | |||
} | |||
执行扫描 | |||
startActivityForResult(Intent(this@MainActivity, CommonScanActivity::class.java), 1) | |||
返回结果字符串 | |||
override fun onActivityResult(requestCode:Int, resultCode:Int, data:Intent?){ | |||
super.onActivityResult(requestCode, resultCode, data) | |||
val rCode = data!!.extras!!.getString(Constant.REQUEST_SCAN_MODE) //得到新Activity关闭后返回的数据 | |||
Toast.makeText(applicationContext, rCode, Toast.LENGTH_LONG).show() | |||
} | |||
==读取写入文本文件(kotlin)== | |||
写入文件 | |||
val fn = filesDir.toString() + "文件名.txt" | |||
var fff = "文本内容" | |||
try { | |||
val tfw = FileWriter(fn) | |||
tfw.write(fff) | |||
tfw.close() | |||
Toast.makeText(applicationContext, "保存成功", Toast.LENGTH_LONG).show() | |||
} catch (e: Exception) { | |||
Toast.makeText(applicationContext, e.toString(), Toast.LENGTH_LONG).show() | |||
} | |||
读取文件 | |||
val fn = filesDir.toString() + "文件名.txt" | |||
try { | |||
val fb = FileReader(fn) | |||
val tv2:TextView = findViewById(R.id.textView2) | |||
tv2.setText(fb.readText()) //显示到TextView | |||
fb.close() | |||
} | |||
catch(e:Exception){ | |||
Toast.makeText(applicationContext, e.toString(), Toast.LENGTH_LONG).show() | |||
} | |||
如果路径访问需要权限 | |||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission> | |||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"></uses-permission> | |||
//获取sd卡读写权限 | |||
//val REQUEST_EXTERNAL_STORAGE = 1234 | |||
if (ActivityCompat.checkSelfPermission(this, | |||
"android.permission.WRITE_EXTERNAL_STORAGE") != PackageManager.PERMISSION_GRANTED ) { | |||
ActivityCompat.requestPermissions(this, | |||
arrayOf(WRITE_EXTERNAL_STORAGE, READ_EXTERNAL_STORAGE), REQUEST_EXTERNAL_STORAGE) | |||
} | |||
else{ | |||
} | |||
==多项选择对话框 kotlin== | |||
val builder = AlertDialog.Builder(this) | |||
builder.setTitle("请选择") | |||
builder.setIcon(R.drawable.ic_launcher_foreground) | |||
builder.setCancelable(true) | |||
val items = arrayOf("第一项", "第二项", "第三项") | |||
var selected = booleanArrayOf(true, false, true) | |||
builder.setMultiChoiceItems(items, selected) { dialog, which, isChecked -> // dialog.dismiss(); | |||
// Toast.makeText(this@MainActivity, items[which] + isChecked, Toast.LENGTH_SHORT).show() | |||
} | |||
//此代码实现输入文本对话框 | |||
//val filename :EditText = EditText(this) | |||
//builder.setView(filename) | |||
builder.setPositiveButton(" 确定发送 ") { dialogInterface, i -> | |||
val tw: TextView = findViewById(R.id.textView1) | |||
var sd = "" | |||
for (i in 0 until items.count()) { | |||
if (selected[i]) | |||
sd += items[i] | |||
} | |||
tw.setText(sd) | |||
Toast.makeText(this@MainActivity, sd, Toast.LENGTH_SHORT).show() | |||
//tw.setText(filename.text.toString()) | |||
} | |||
builder.setNegativeButton("取消发送") { dialogInterface, i -> | |||
// finish() | |||
} | |||
builder.show() | |||
==OptionsMenu kotlin== | |||
app 右键 new=》android resouce file | |||
resouce type 选择Menu | |||
创建菜单项目,编辑ID和title | |||
//显示菜单 | |||
override fun onCreateOptionsMenu(menu: Menu?): Boolean { | |||
menuInflater.inflate(R.menu.mainmanu,menu) | |||
return true | |||
// return super.onCreateOptionsMenu(menu) | |||
} | |||
//处理菜单点击响应 | |||
override fun onOptionsItemSelected(item: MenuItem): Boolean { | |||
if(item?.itemId == R.id.menu_exit){ | |||
finish() | |||
} | |||
if(item?.itemId == R.id.menu_upate){ | |||
Toast.makeText(this,"system update",Toast.LENGTH_LONG).show() | |||
} | |||
return super.onOptionsItemSelected(item) | |||
} | |||
==ContextMenu kotlin == | |||
app 右键 new=》android resouce file | |||
resouce type 选择Menu | |||
创建菜单项目,编辑ID和title | |||
override fun onCreateContextMenu(menu: ContextMenu?, v: View?, menuInfo: ContextMenu.ContextMenuInfo?) { | |||
super.onCreateContextMenu(menu, v, menuInfo) | |||
menuInflater.inflate(R.menu.menupop,menu) | |||
menu!!.setHeaderTitle("请选择") | |||
} | |||
重载函数 | |||
override fun onContextItemSelected(item: MenuItem): Boolean { | |||
if(item.itemId == R.id.media_route_menu_item1){ | |||
Toast.makeText(this,"11111111",Toast.LENGTH_LONG).show() | |||
} | |||
return super.onContextItemSelected(item) | |||
} | |||
onCreate | |||
val bt_menu: Button = findViewById(R.id.button_menu) | |||
registerForContextMenu(bt_menu) | |||
bt_menu.setOnClickListener { | |||
openContextMenu(it) | |||
} | |||
如果在list view item弹出菜单,直接 | |||
val tv_houseList = findViewById(R.id.listview_house_list) as ListView | |||
registerForContextMenu(tv_houseList) | |||
这样长按item自动会弹出菜单 | |||
==androidstudio使用WebView显示网页(kotlin)== | |||
val wset = wview1.settings | |||
wset.javaScriptEnabled = true | |||
wview1.setWebViewClient(object : WebViewClient() { | |||
override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean { | |||
view.loadUrl(url) | |||
return true | |||
} | |||
}) | |||
wview1.loadUrl(“http://www.baidu.com”) | |||
在AndroidManifest.xml增加 | |||
android:usesCleartextTraffic="true" | |||
需要添加网络权限 | |||
如果需要支持网页弹出alert: | |||
wview1.setWebChromeClient (object : WebChromeClient() | |||
override fun onJsAlert(view: WebView,url: String,message: String,result: JsResult):Boolean{ | |||
return super.onJsAlert(view, url, message, result) | |||
} | |||
}) | |||
==androidstudio使用viewPager显示多张图片并关联tabLayout(kotlin)== | |||
val mImgId = intArrayOf(R.drawable.h1, R.drawable.h2, R.drawable.h3) | |||
val mList = ArrayList() | |||
var tabName : Array = Array(3,{""}) | |||
tabName[0] = "TAB1" | |||
tabName[1] = "TAB2" | |||
tabName[2] = "TAB3" | |||
vpage.setAdapter(object : PagerAdapter() { | |||
override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) { | |||
container.removeView(mList.get(position)) | |||
} | |||
override fun instantiateItem(container: ViewGroup, position: Int): Any { | |||
val imageView = ImageView(this@MainActivity) | |||
imageView.setImageResource(mImgId[position]) | |||
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP) | |||
container.addView(imageView) | |||
mList.add(imageView) | |||
return imageView | |||
} | |||
override fun getCount(): Int { | |||
return mImgId.size | |||
} | |||
override fun isViewFromObject(view: View, `object`: Any): Boolean { | |||
return view === `object` | |||
} | |||
override fun getPageTitle(position:Int):CharSequence{ | |||
return tabName[position] | |||
} | |||
}) | |||
tabcus.setupWithViewPager(vpage) | |||
==使用ViewPager2和TabLayout实现多frgment切换== | |||
private fun initTab(){ | |||
val viewpage = findViewById(R.id.viewpage2) as ViewPager2 | |||
viewpage.adapter = object : FragmentStateAdapter(this){ | |||
override fun getItemCount(): Int { | |||
return 3 | |||
} | |||
override fun createFragment(position: Int): Fragment { | |||
return when(position){ | |||
0 -> myFragment() | |||
1 -> hlistFragment() | |||
else -> hlistFragment() | |||
} | |||
} | |||
} | |||
val tabmain = findViewById(R.id.tabLayout) as TabLayout | |||
TabLayoutMediator( | |||
tabmain, | |||
viewpage, | |||
object : TabLayoutMediator.TabConfigurationStrategy{ | |||
override fun onConfigureTab(tab: TabLayout.Tab, position: Int) { | |||
when(position){ | |||
0 -> tab.text = "资源汇总" | |||
1 -> tab.text = "我的房源" | |||
else -> tab.text = "房源资源库" | |||
} | |||
} | |||
}).attach() | |||
xml文件 | |||
<com.google.android.material.tabs.TabLayout | |||
<androidx.viewpager2.widget.ViewPager2 | |||
建立Fragement list 用于访问每个动态创建的Fragment | |||
var list_frm:ArrayList<Fragment> = ArrayList() | |||
override fun createFragment(position: Int): Fragment { | |||
when(position){ | |||
0 -> { | |||
val fg = myFragment() | |||
list_frm.add(fg ) | |||
return fg | |||
} | |||
1 -> { | |||
val fg = hlistFragment() | |||
list_frm.add(fg) | |||
return fg | |||
} | |||
else -> { | |||
val fg = hlistFragment() | |||
list_frm.add(fg) | |||
return fg | |||
} | |||
} | |||
} | |||
==使用BaseAdapter为listview装入数据== | |||
class myAdapter (context: Activity,listValue:String): BaseAdapter(){ | |||
private var ct:Activity | |||
private var lv:String | |||
init { | |||
ct = context | |||
lv = listValue | |||
} | |||
override fun getCount():Int{ | |||
val hma_list = lv.split("^") | |||
return hma_list.count() | |||
} | |||
override fun getItem(position: Int):String{ | |||
val hma_list = lv.split("^") | |||
return hma_list[position].toString() | |||
} | |||
override fun getItemId(position: Int):Long{ | |||
return position.toLong() | |||
} | |||
override fun getView(position: Int, view: View?, parent: ViewGroup): View { | |||
val rowView = ct.layoutInflater.inflate(R.layout.layout_house_info_item, null, true) | |||
val hm_name = rowView.findViewById(R.id.tv_item_name) as TextView | |||
val hm_price = rowView.findViewById(R.id.tv_item_price) as TextView | |||
val hm_size = rowView.findViewById(R.id.tv_item_size) as TextView | |||
val hm_room = rowView.findViewById(R.id.tv_item_room) as TextView | |||
val hm_time = rowView.findViewById(R.id.tv_item_time) as TextView | |||
val hm_status = rowView.findViewById(R.id.tv_item_status) as TextView | |||
val hma_list = lv.split("^") | |||
var hma_value = hma_list[position].split("~") | |||
hm_name.text = hma_value[0] | |||
if(hma_value[12] == "2" ) | |||
hm_price.text = hma_value[4]+"/月" | |||
else | |||
hm_price.text = hma_value[2]+"万" | |||
hm_size.text = hma_value[9] +" "+ hma_value[1]+"平米" | |||
hm_room.text = hma_value[6]+"室"+hma_value[7]+"厅"+hma_value[8]+"卫 "+hma_value[5]+"层" | |||
hm_time.text = "最后跟进"+hma_value[11] | |||
return rowView | |||
} | |||
} | |||
listview 操作 | |||
val adapter = myAdapter(this,listStr) | |||
tv_houseList.setAdapter(adapter) | |||
==让EditText不能编辑,只读== | |||
et_tel.keyListener = null | |||
==让WebView支持手机定位== | |||
静态申请权限 | |||
<uses-permission android:name="android.permission.INTERNET"/> | |||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> | |||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> | |||
<uses-permission android:name="android.permission.ACCESS_GPS" /> | |||
<uses-permission android:name="android.permission.ACCESS_ASSISTED_GPS" /> | |||
<uses-permission android:name="android.permission.ACCESS_LOCATION" /> | |||
动态申请权限 | |||
if (ActivityCompat.checkSelfPermission(this, | |||
"android.permission.WRITE_EXTERNAL_STORAGE") != PackageManager.PERMISSION_GRANTED ) { | |||
ActivityCompat.requestPermissions(this, | |||
arrayOf(ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION), 1234) | |||
} | |||
设置WebView参数 | |||
val wview1 = findViewById(R.id.vview1) as WebView | |||
val wset = wview1.settings | |||
wset.javaScriptEnabled = true | |||
wset.setGeolocationEnabled(true) //允许定位 | |||
wview1.setWebViewClient(object : WebViewClient() { | |||
override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean { | |||
view.loadUrl(url) | |||
return true | |||
} | |||
}) | |||
wview1.setWebChromeClient (object : WebChromeClient() { | |||
override fun onJsAlert(view: WebView, url: String, message: String, result: JsResult):Boolean{ | |||
return super.onJsAlert(view, url, message, result) | |||
} | |||
override fun onGeolocationPermissionsShowPrompt( | |||
origin: String?, | |||
callback: GeolocationPermissions.Callback? | |||
) { | |||
val remember = true | |||
val builder: AlertDialog.Builder = AlertDialog.Builder(this@MainActivity) | |||
builder.setTitle("位置信息") | |||
builder.setMessage(origin + "允许获取您的地理位置信息吗?").setCancelable(true) | |||
.setPositiveButton("允许", | |||
DialogInterface.OnClickListener { dialog, id -> | |||
callback?.invoke( | |||
origin, | |||
true, | |||
remember | |||
) | |||
}) | |||
.setNegativeButton("不允许", | |||
DialogInterface.OnClickListener { dialog, id -> | |||
callback?.invoke( | |||
origin, | |||
false, | |||
remember | |||
) | |||
}) | |||
val alert: AlertDialog = builder.create() | |||
alert.show() | |||
} | |||
}) |
2024年3月14日 (四) 12:44的版本
项目中引用MPChartLib
1、 将MPChartLib文件夹拷贝到项目根目录 2、在根目录里的settings.gradle里增加include ':app', ':MPChartLib' 3、将文件MPChartLib.aar拷贝到libs文件夹里 4、在build.grade(app)中增加 dependencies { implementation project(':MPChartLib') }
设置app自动启动
增加权限 <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/> 注册消息接收 <receiver android:name=".BootBroadcastReceiver"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> </intent-filter> </receiver>
消息接收函数 class BootBroadcastReceiver: BroadcastReceiver() { override public fun onReceive(context: Context, intent: Intent) { val mBootIntent = Intent(context, MainActivity::class.java) mBootIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) context.startActivity(mBootIntent) } }
获取位置信息(kotlin)
val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager val location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER) if (location != null) { val sb = StringBuffer() sb.append('实时的位置信息:经度:') sb.append(location.longitude) sb.append('纬度:') sb.append(location.latitude) sb.append('高度:') sb.append(location.altitude) sb.append('速度:') sb.append(location.speed) sb.append('方向:') sb.append(location.bearing) sb.append('精度:') sb.append(location.accuracy) Toast.makeText(applicationContext, sb.toString(), Toast.LENGTH_LONG).show() } 添加权限 <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
发送Notification消息(kotlin)
fun sendNotification(channel_id:String ,channle_name:String,nTitle:String,nContentText:String,id:Int){ var notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager var notification: Notification? = null //val intent = Intent(Intent.ACTION_VIEW, Uri.parse('http://www.baidu.com/')) //val pendingIntent = PendingIntent.getActivity(this, 0, intent, 0) //如需链接到网站使用注释代码 val intent = Intent() intent.setClass(this@MainActivity, MainActivity::class. val pendingIntent = PendingIntent.getActivity(this, 0, intent, 0) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val mChannel = NotificationChannel(channel_id, channle_name, NotificationManager.IMPORTANCE_LOW) notificationManager.createNotificationChannel(mChannel) notification = Notification.Builder(this) .setChannelId(channel_id) .setContentTitle(nTitle) .setContentText(nContentText) .setContentIntent(pendingIntent) .setSmallIcon(R.drawable.house).build() } else { val notificationBuilder = NotificationCompat.Builder(this) .setContentTitle(nTitle) .setContentText(nContentText) .setSmallIcon(R.drawable.house) .setOngoing(true) //.setChannel(id)//无效 notification = notificationBuilder.build() } notificationManager.notify(id, notification) }
禁止使用http链接解决方法
访问网络时报异常 Cleartext HTTP traffic to not permitted 在<application标签里增加android:usesCleartextTraffic="true"即可
bitmap缩小显示
var matrix = Matrix() matrix.postScale(0.3f,0.3f)//长和宽放大缩小的比例 val resizeBmp = Bitmap.createBitmap(bitmap,0,0,bitmap.getWidth(),bitmap.getHeight(),matrix,true)
textview 连续左移
设置一下参数,自动连续左移动 android:ellipsize="marquee" android:focusable="auto" android:focusableInTouchMode="true" android:marqueeRepeatLimit="marquee_forever" android:scrollHorizontally="true" android:singleLine="true"
useAndroidx Error
编译报错 This project uses AndroidX dependencies, but the 'android.useAndroidX' property is not enabled.
在gradle.propeties文件里增加如下语句,允许AnsiroidX android.useAndroidX=true
post获取数据(kotlin)
Thread(Runnable { val toMain1 = mAppMesHandler.obtainMessage() toMain1.arg1 = 1
var conn: HttpURLConnection? = null var urlString = "http://server/new.php" try { conn = URL(urlString).openConnection() as HttpURLConnection conn.requestMethod = "POST" // 指定POST请求 conn.doOutput = true // 设置请求过程可以传递参数给服务器
// post请求参数 val param = String.format("name=%s&age=%s&action=%s", "fengxueyan", "23", "query") DataOutputStream(conn.outputStream).use { os -> os.writeBytes(param) } conn.connect() conn.inputStream.use { input -> val data = input.bufferedReader().readText() toMain1.obj = data.toString() } } catch (e: Exception) { toMain1.obj = e.toString() } finally { conn?.disconnect() }
mAppMesHandler.sendMessage(toMain1) }).start()
//访问网络必须使用线程,而且线程不允许更新UI
val mAppMesHandler = object : Handler() {
override fun handleMessage(msg: Message) {
if(msg.arg1 == 1){
var hList0 = msg.obj as String
textView.setText(hList0)
// Toast.makeText(applicationContext,hList0,Toast.LENGTH_LONG).show()
}
}
}
时间日期选择
<TimePicker android:id="@+id/ptime" android:layout_width="310dp" android:layout_height="347dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/button2" />
textView.setText(ptime.hour.toString()+":"+ptime.minute.toString())
<DatePicker android:id="@+id/pdate" android:layout_width="358dp" android:layout_height="428dp" android:layout_marginTop="20dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.566" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/button2" />
textView.setText(pdate.year.toString()+"-"+(pdate.month+1).toString()+"-"+pdate.dayOfMonth.toString())
多个Fragment和Activity的简易数据交换方法(kotlin)
动态创建多个Fragment后,和Activity数据交换有很多种方式,消息方式简单快捷,代码量少
在Activity中定义消息处理 val mMainHandler = object : Handler() {
override fun handleMessage(msg: Message) { if (msg.arg1 == 1) { val sVerRes = msg.obj as String Toast.makeText(applicationContext, sVerRes, Toast.LENGTH_LONG).show() }
}
在Fragment里定义消息handle
private var aHandle:Handler? = null
建立初始化函数,将Activity的消息handle传入
fun setHandler(AHandler: Handler?) {
try { aHandle = AHandler } catch (e: Exception) { throw ClassCastException(context.toString() }
}
Activity向Fragment传递数据直接定义函数 Fragment向Activity传递数据发送消息 val toMain1 = aHandle!!.obtainMessage() toMain1.obj = “message or data” toMain1.arg1 = 1
aHandle!!.sendMessage(toMain1)
实现扫码二维码(kotlin)
dependencies增加引用 implementation 'com.hongyelinggu:scancode:1.0.0'
申请相机权限 <uses-permission android:name="android.permission.CAMERA"/> val REQUEST_EXTERNAL_STORAGE = 1234 if (ActivityCompat.checkSelfPermission(this, "android.permission.CAMERA") != PackageManager.PERMISSION_GRANTED ) { ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.CAMERA), REQUEST_EXTERNAL_STORAGE) } else{
}
执行扫描 startActivityForResult(Intent(this@MainActivity, CommonScanActivity::class.java), 1)
返回结果字符串 override fun onActivityResult(requestCode:Int, resultCode:Int, data:Intent?){ super.onActivityResult(requestCode, resultCode, data) val rCode = data!!.extras!!.getString(Constant.REQUEST_SCAN_MODE) //得到新Activity关闭后返回的数据 Toast.makeText(applicationContext, rCode, Toast.LENGTH_LONG).show() }
读取写入文本文件(kotlin)
写入文件
val fn = filesDir.toString() + "文件名.txt" var fff = "文本内容" try { val tfw = FileWriter(fn) tfw.write(fff) tfw.close()
Toast.makeText(applicationContext, "保存成功", Toast.LENGTH_LONG).show() } catch (e: Exception) { Toast.makeText(applicationContext, e.toString(), Toast.LENGTH_LONG).show() }
读取文件 val fn = filesDir.toString() + "文件名.txt" try { val fb = FileReader(fn) val tv2:TextView = findViewById(R.id.textView2) tv2.setText(fb.readText()) //显示到TextView fb.close() } catch(e:Exception){ Toast.makeText(applicationContext, e.toString(), Toast.LENGTH_LONG).show() }
如果路径访问需要权限 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"></uses-permission>
//获取sd卡读写权限 //val REQUEST_EXTERNAL_STORAGE = 1234 if (ActivityCompat.checkSelfPermission(this, "android.permission.WRITE_EXTERNAL_STORAGE") != PackageManager.PERMISSION_GRANTED ) { ActivityCompat.requestPermissions(this, arrayOf(WRITE_EXTERNAL_STORAGE, READ_EXTERNAL_STORAGE), REQUEST_EXTERNAL_STORAGE) } else{
}
多项选择对话框 kotlin
val builder = AlertDialog.Builder(this) builder.setTitle("请选择") builder.setIcon(R.drawable.ic_launcher_foreground) builder.setCancelable(true)
val items = arrayOf("第一项", "第二项", "第三项") var selected = booleanArrayOf(true, false, true)
builder.setMultiChoiceItems(items, selected) { dialog, which, isChecked -> // dialog.dismiss();
// Toast.makeText(this@MainActivity, items[which] + isChecked, Toast.LENGTH_SHORT).show()
}
//此代码实现输入文本对话框 //val filename :EditText = EditText(this) //builder.setView(filename)
builder.setPositiveButton(" 确定发送 ") { dialogInterface, i -> val tw: TextView = findViewById(R.id.textView1) var sd = "" for (i in 0 until items.count()) { if (selected[i]) sd += items[i] } tw.setText(sd) Toast.makeText(this@MainActivity, sd, Toast.LENGTH_SHORT).show()
//tw.setText(filename.text.toString()) } builder.setNegativeButton("取消发送") { dialogInterface, i -> // finish()
}
builder.show()
OptionsMenu kotlin
app 右键 new=》android resouce file resouce type 选择Menu 创建菜单项目,编辑ID和title //显示菜单 override fun onCreateOptionsMenu(menu: Menu?): Boolean { menuInflater.inflate(R.menu.mainmanu,menu) return true // return super.onCreateOptionsMenu(menu) } //处理菜单点击响应 override fun onOptionsItemSelected(item: MenuItem): Boolean {
if(item?.itemId == R.id.menu_exit){ finish() } if(item?.itemId == R.id.menu_upate){ Toast.makeText(this,"system update",Toast.LENGTH_LONG).show() }
return super.onOptionsItemSelected(item)
}
ContextMenu kotlin
app 右键 new=》android resouce file resouce type 选择Menu 创建菜单项目,编辑ID和title
override fun onCreateContextMenu(menu: ContextMenu?, v: View?, menuInfo: ContextMenu.ContextMenuInfo?) { super.onCreateContextMenu(menu, v, menuInfo) menuInflater.inflate(R.menu.menupop,menu) menu!!.setHeaderTitle("请选择") }
重载函数
override fun onContextItemSelected(item: MenuItem): Boolean { if(item.itemId == R.id.media_route_menu_item1){ Toast.makeText(this,"11111111",Toast.LENGTH_LONG).show() } return super.onContextItemSelected(item) }
onCreate
val bt_menu: Button = findViewById(R.id.button_menu) registerForContextMenu(bt_menu) bt_menu.setOnClickListener { openContextMenu(it) }
如果在list view item弹出菜单,直接
val tv_houseList = findViewById(R.id.listview_house_list) as ListView registerForContextMenu(tv_houseList)
这样长按item自动会弹出菜单
androidstudio使用WebView显示网页(kotlin)
val wset = wview1.settings wset.javaScriptEnabled = true wview1.setWebViewClient(object : WebViewClient() { override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean { view.loadUrl(url) return true } }) wview1.loadUrl(“http://www.baidu.com”)
在AndroidManifest.xml增加
android:usesCleartextTraffic="true"
需要添加网络权限
如果需要支持网页弹出alert:
wview1.setWebChromeClient (object : WebChromeClient() override fun onJsAlert(view: WebView,url: String,message: String,result: JsResult):Boolean{ return super.onJsAlert(view, url, message, result) } })
androidstudio使用viewPager显示多张图片并关联tabLayout(kotlin)
val mImgId = intArrayOf(R.drawable.h1, R.drawable.h2, R.drawable.h3)
val mList = ArrayList() var tabName : Array = Array(3,{""})
tabName[0] = "TAB1" tabName[1] = "TAB2" tabName[2] = "TAB3"
vpage.setAdapter(object : PagerAdapter() { override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) { container.removeView(mList.get(position)) } override fun instantiateItem(container: ViewGroup, position: Int): Any { val imageView = ImageView(this@MainActivity) imageView.setImageResource(mImgId[position]) imageView.setScaleType(ImageView.ScaleType.CENTER_CROP) container.addView(imageView) mList.add(imageView) return imageView } override fun getCount(): Int { return mImgId.size } override fun isViewFromObject(view: View, `object`: Any): Boolean { return view === `object` } override fun getPageTitle(position:Int):CharSequence{ return tabName[position] }
}) tabcus.setupWithViewPager(vpage)
使用ViewPager2和TabLayout实现多frgment切换
private fun initTab(){ val viewpage = findViewById(R.id.viewpage2) as ViewPager2 viewpage.adapter = object : FragmentStateAdapter(this){ override fun getItemCount(): Int { return 3 } override fun createFragment(position: Int): Fragment { return when(position){ 0 -> myFragment() 1 -> hlistFragment() else -> hlistFragment() } } } val tabmain = findViewById(R.id.tabLayout) as TabLayout
TabLayoutMediator( tabmain, viewpage, object : TabLayoutMediator.TabConfigurationStrategy{ override fun onConfigureTab(tab: TabLayout.Tab, position: Int) { when(position){ 0 -> tab.text = "资源汇总" 1 -> tab.text = "我的房源" else -> tab.text = "房源资源库" } } }).attach()
xml文件
<com.google.android.material.tabs.TabLayout <androidx.viewpager2.widget.ViewPager2
建立Fragement list 用于访问每个动态创建的Fragment
var list_frm:ArrayList<Fragment> = ArrayList()
override fun createFragment(position: Int): Fragment { when(position){ 0 -> { val fg = myFragment() list_frm.add(fg ) return fg } 1 -> { val fg = hlistFragment() list_frm.add(fg) return fg } else -> { val fg = hlistFragment() list_frm.add(fg) return fg } } }
使用BaseAdapter为listview装入数据
class myAdapter (context: Activity,listValue:String): BaseAdapter(){ private var ct:Activity private var lv:String init { ct = context lv = listValue
} override fun getCount():Int{ val hma_list = lv.split("^") return hma_list.count() } override fun getItem(position: Int):String{ val hma_list = lv.split("^") return hma_list[position].toString() } override fun getItemId(position: Int):Long{ return position.toLong() }
override fun getView(position: Int, view: View?, parent: ViewGroup): View { val rowView = ct.layoutInflater.inflate(R.layout.layout_house_info_item, null, true) val hm_name = rowView.findViewById(R.id.tv_item_name) as TextView val hm_price = rowView.findViewById(R.id.tv_item_price) as TextView val hm_size = rowView.findViewById(R.id.tv_item_size) as TextView val hm_room = rowView.findViewById(R.id.tv_item_room) as TextView val hm_time = rowView.findViewById(R.id.tv_item_time) as TextView val hm_status = rowView.findViewById(R.id.tv_item_status) as TextView val hma_list = lv.split("^") var hma_value = hma_list[position].split("~") hm_name.text = hma_value[0] if(hma_value[12] == "2" ) hm_price.text = hma_value[4]+"/月" else hm_price.text = hma_value[2]+"万" hm_size.text = hma_value[9] +" "+ hma_value[1]+"平米" hm_room.text = hma_value[6]+"室"+hma_value[7]+"厅"+hma_value[8]+"卫 "+hma_value[5]+"层" hm_time.text = "最后跟进"+hma_value[11] return rowView } }
listview 操作
val adapter = myAdapter(this,listStr) tv_houseList.setAdapter(adapter)
让EditText不能编辑,只读
et_tel.keyListener = null
让WebView支持手机定位
静态申请权限
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_GPS" /> <uses-permission android:name="android.permission.ACCESS_ASSISTED_GPS" /> <uses-permission android:name="android.permission.ACCESS_LOCATION" />
动态申请权限
if (ActivityCompat.checkSelfPermission(this, "android.permission.WRITE_EXTERNAL_STORAGE") != PackageManager.PERMISSION_GRANTED ) { ActivityCompat.requestPermissions(this, arrayOf(ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION), 1234) }
设置WebView参数
val wview1 = findViewById(R.id.vview1) as WebView val wset = wview1.settings wset.javaScriptEnabled = true wset.setGeolocationEnabled(true) //允许定位 wview1.setWebViewClient(object : WebViewClient() { override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean { view.loadUrl(url) return true } })
wview1.setWebChromeClient (object : WebChromeClient() { override fun onJsAlert(view: WebView, url: String, message: String, result: JsResult):Boolean{ return super.onJsAlert(view, url, message, result) } override fun onGeolocationPermissionsShowPrompt( origin: String?, callback: GeolocationPermissions.Callback? ) { val remember = true val builder: AlertDialog.Builder = AlertDialog.Builder(this@MainActivity) builder.setTitle("位置信息") builder.setMessage(origin + "允许获取您的地理位置信息吗?").setCancelable(true) .setPositiveButton("允许", DialogInterface.OnClickListener { dialog, id -> callback?.invoke( origin, true, remember ) }) .setNegativeButton("不允许", DialogInterface.OnClickListener { dialog, id -> callback?.invoke( origin, false, remember ) }) val alert: AlertDialog = builder.create() alert.show() } })