Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/xuexiangjys/uithemesample
Android的UI主题使用案例
https://github.com/xuexiangjys/uithemesample
android samples ui-design x-samples
Last synced: about 1 month ago
JSON representation
Android的UI主题使用案例
- Host: GitHub
- URL: https://github.com/xuexiangjys/uithemesample
- Owner: xuexiangjys
- License: apache-2.0
- Created: 2022-07-10T02:58:04.000Z (over 2 years ago)
- Default Branch: master
- Last Pushed: 2023-12-15T05:47:11.000Z (about 1 year ago)
- Last Synced: 2024-02-29T16:31:57.655Z (10 months ago)
- Topics: android, samples, ui-design, x-samples
- Language: Kotlin
- Homepage:
- Size: 212 KB
- Stars: 7
- Watchers: 3
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Funding: .github/FUNDING.yml
- License: LICENSE
Awesome Lists containing this project
README
# UIThemeSample
Android的UI主题使用案例
## 关于我
| 公众号 | 掘金 | 知乎 | CSDN | 简书 | 思否 | 哔哩哔哩 | 今日头条
|---------|---------|--------- |---------|---------|---------|---------|---------|
| [我的Android开源之旅](https://t.1yb.co/Irse) | [点我](https://juejin.im/user/598feef55188257d592e56ed/posts) | [点我](https://www.zhihu.com/people/xuexiangjys/posts) | [点我](https://xuexiangjys.blog.csdn.net/) | [点我](https://www.jianshu.com/u/6bf605575337) | [点我](https://segmentfault.com/u/xuexiangjys) | [点我](https://space.bilibili.com/483850585) | [点我](https://img.rruu.net/image/5ff34ff7b02dd)## 自定义View
### 完全自定义View实现自定义控件
自定义View、ViewGroup或者SurfaceView:
* 自定义View:主要重写onDraw(绘制)方法。
* 自定义ViewGroup:主要重写:onMeasure(测量)、onLayout(布局)这两个方法。
* 自定义SurfaceView:创建RenderThread,然后调用`SurfaceHolder的.lockCanvas`方法获取画布,再调用`SurfaceHolder的.unlockCanvasAndPost`方法将绘制的画布投射到屏幕上。
```kotlin
class CustomSurfaceView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
) : SurfaceView(context, attrs), SurfaceHolder.Callback {private var mSurfaceHolder: SurfaceHolder = holder
private lateinit var mRenderThread: RenderThread
private var mIsDrawing = false
override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {}
override fun surfaceCreated(holder: SurfaceHolder) {
// 开启RenderThread
mIsDrawing = true
mRenderThread = RenderThread()
mRenderThread.start()
}override fun surfaceDestroyed(holder: SurfaceHolder) {
// 销毁RenderThread
mIsDrawing = false
mRenderThread.interrupt()
}/**
* 绘制界面的线程
*/
private inner class RenderThread : Thread() {override fun run() {
// 不停绘制界面
while (mIsDrawing) {
drawUI()
try {
sleep(...) // 刷新间隔
} catch (_: InterruptedException) {
}
}
}
}/**
* 界面绘制
*/
private fun drawUI() {
val canvas = mSurfaceHolder.lockCanvas()
try {
drawCanvas(canvas)
} catch (e: Exception) {
e.printStackTrace()
} finally {
mSurfaceHolder.unlockCanvasAndPost(canvas)
}
}
}
```### 继承组件的方式实现自定义控件
最简单的自定义组件的方式,直接继承需要拓展/修改的控件,重写对应的方法即可。
一般是希望在原有系统控件基础上做一些修饰性的修改(功能增强),而不会做大幅度的改动。
### 组合的方式实现自定义控件
> 组合控件就是将多个控件组合成一个新的控件,可以重复使用。
实现组合控件的一般步骤如下:
* 编写布局文件
* 实现构造方法
* 初始化UI,加载布局
* 对外提供修改的接口api可以看到,组合的方式和我们平时写一个Fragment的流程是很类似的。
## Theme主题
应用于窗体级别,是一整套样式的组合,采取就近原则:Application > Activity > ViewGroup > View。 一般而言,Theme主要应用于Application和Activity这样的窗体,主要放在`/res/values/themes.xml`。
```xml
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
```
### Application中的Theme
Application的主题一般在`Manifest`中,它只对在`Manifest`中未设置Theme的Activity生效。
```xml
```
### Activity中的Theme
Activity的主题可以在`Manifest`和代码中调用`setTheme`设置。一般在Activity的onCreate()中,`setContentView`方法之前设置。
1.在`Manifest`中设置。
```xml
```
2.代码中调用`setTheme`设置,注意一定要在调用`setContentView(View)`和`inflate(int, ViewGroup)`方法前。
```kotlin
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setTheme(R.style.AppTheme)
setContentView(R.layout.layout_main)
}
```### ViewGroup和View中的Theme
ViewGroup和View的主题一般在布局xml中设置,使用`android:theme`设置。
```xml
```
## Style样式
> 仅应用于单个View这种窗体元素级别的外观,主要放在`/res/values/styles.xml`。
### Style的声明
样式的声明,一般放在`/res/values/...`目录下带`styles`的文件中,使用` `进行设置。
```xml
<item name="attr-name1">value1</item>
<item name="attr-name2">value2</item>
<item name="attr-name3">value3</item>```
### Style的使用
样式一般在布局xml中设置,使用`android:style`设置,不同于主题,样式只能应用于单个View,对于其子View并不会生效。
```xml
```
### Style的优先级顺序
如果我们在多个地方给控件指定了style的属性,那么最终是由谁生效呢?这里我们就以TextView为例,介绍一下Style的生效规则:
* 1.通过文本span将字符设置的样式应用到TextView派生的类。
* 2.以代码方式动态设置的属性。
* 3.将单独的属性直接应用到View。
* 4.将样式应用到View。
* 5.控件的默认样式,在View构造方法中定义的。
* 6.控件所处应用、Activity、父布局所应用的主题。
* 7.应用某些特定于View的样式,例如为TextView设置TextAppearance。## Attribute属性
> Attribute属性是组成Style的基本单位。如果说主题是各种样式的组合,那么样式就是各种属性的组合,主要放在`/res/values/attrs.xml`。
### Attribute的声明
1.单个属性的定义
```xml
```
2.一组属性的定义
```xml
```
3.属性的赋值
```xml
<item name="attr-name">value</item>
```
### Attribute的使用
使用`?attr/xxx`或者`?xxx`进行引用。这里xxx是定义的属性名(attr-name)。
```xml
```
### Attribute的获取
* 属性集的获取: 使用`context.obtainStyledAttributes`进行整体获取。
```kotlin
val array = context.obtainStyledAttributes(attrs, R.styleable.CustomTextView, defStyleAttr, defStyleRes)
size = array.getInteger(R.styleable.CustomTextView_ctv_size, size)
isPassword = array.getBoolean(R.styleable.CustomTextView_ctv_is_password, isPassword)
array.recycle()
```* 单个属性的获取: 使用`context.theme.resolveAttribute`进行获取。
```kotlin
fun Resources.Theme.resolveAttributeToDimension(@AttrRes attributeId: Int, defaultValue: Float = 0F) : Float {
val typedValue = TypedValue()
return if (resolveAttribute(attributeId, typedValue, true)) {
typedValue.getDimension(resources.displayMetrics)
} else {
defaultValue
}
}fun Context.resolveDimension(@AttrRes attributeId: Int, defaultValue: Float = 0F) : Float {
val typedArray = theme.obtainStyledAttributes(intArrayOf(attributeId))
return try {
typedArray.getDimension(0, defaultValue)
} finally {
typedArray.recycle()
}
}
```## 如果觉得项目还不错,可以考虑打赏一波
> 你的打赏是我维护的动力,我将会列出所有打赏人员的清单在下方作为凭证,打赏前请留下打赏项目的备注!
![pay.png](https://raw.githubusercontent.com/xuexiangjys/Resource/master/img/pay/pay.png)
## 联系方式
> 更多资讯内容,欢迎扫描关注我的个人微信公众号:【我的Android开源之旅】
![](https://s1.ax1x.com/2022/04/27/LbGMJH.jpg)