网站logo怎么设置,潍坊建设网站多少钱,广州信息流推广公司,房地产销售基础知识新手必看看了我Android低代码开发 - 让IDE帮你写代码这篇文章的小伙伴#xff0c;大概都对Dora全家桶开发框架有基本的认识了吧。本篇文章将会讲解如何使用dora-studio-plugin快捷创建一个下拉刷新列表界面。
效果演示 这样直接通过图形界面的方式就创建好了下拉刷新上拉加载空态界面…看了我Android低代码开发 - 让IDE帮你写代码这篇文章的小伙伴大概都对Dora全家桶开发框架有基本的认识了吧。本篇文章将会讲解如何使用dora-studio-plugin快捷创建一个下拉刷新列表界面。
效果演示 这样直接通过图形界面的方式就创建好了下拉刷新上拉加载空态界面列表的基础代码接下来开发起来就方便了。
依赖库 DoraTitleBar建议用最新版本1.37 DoraEmptyLayout必须用1.12版本 SwipeLayout和PullableRecyclerView用1.0版本就好 IntelliJ IDEA插件1.4版本更新内容
生成布局文件的模板
/** Copyright (C) 2022 The Dora Open Source Project** Licensed under the Apache License, Version 2.0 (the License);* you may not use this file except in compliance with the License.* You may obtain a copy of the License at** http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an AS IS BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package com.dorachat.templates.recipes.app_package.res.layoutfun swipeLayoutActivityXml(packageName: String,activityClass: String
)
?xml version1.0 encodingutf-8?
layout xmlns:androidhttp://schemas.android.com/apk/res/androidxmlns:apphttp://schemas.android.com/apk/res-autoxmlns:toolshttp://schemas.android.com/toolstools:context${packageName}.${activityClass}data/dataLinearLayoutandroid:layout_widthmatch_parentandroid:layout_heightmatch_parentandroid:orientationverticaldora.widget.DoraTitleBarandroid:idid/titleBarandroid:layout_widthmatch_parentandroid:layout_height50dpapp:dview_titlestring/app_nameandroid:backgroundcolor/colorPrimary/dora.widget.DoraEmptyLayoutandroid:idid/emptyLayoutandroid:layout_widthmatch_parentandroid:layout_heightmatch_parentdora.widget.pull.SwipeLayoutandroid:idid/swipeLayoutandroid:layout_widthmatch_parentandroid:layout_heightmatch_parentinclude layoutlayout/layout_swipe_layout_header /dora.widget.pull.PullableRecyclerViewandroid:idid/recyclerViewandroid:layout_widthmatch_parentandroid:layout_heightmatch_parentandroid:backgroundcolor/colorPanelBg /include layoutlayout/layout_swipe_layout_footer //dora.widget.pull.SwipeLayout/dora.widget.DoraEmptyLayout/LinearLayout
/layout生成Java和Kotlin代码的模板
/** Copyright (C) 2022 The Dora Open Source Project** Licensed under the Apache License, Version 2.0 (the License);* you may not use this file except in compliance with the License.* You may obtain a copy of the License at** http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an AS IS BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package com.dorachat.templates.recipes.app_package.srcfun swipeLayoutActivityKt(applicationPackage: String,packageName: String,activityClass: String,bindingName: String,layoutName: String
)
package ${packageName}import android.os.Bundleimport dora.BaseActivity
import dora.widget.pull.SwipeLayoutimport ${applicationPackage}.R
import ${applicationPackage}.databinding.${bindingName}class ${activityClass} : BaseActivity${bindingName}() {override fun getLayoutId(): Int {return R.layout.${layoutName}}override fun initData(savedInstanceState: Bundle?, binding: ${bindingName}) {TODO(Not yet implemented)// For Example:// binding.swipeLayout.setOnSwipeListener(object : SwipeLayout.OnSwipeListener {//// override fun onRefresh(swipeLayout: SwipeLayout) {// }//// override fun onLoadMore(swipeLayout: SwipeLayout) {// }// })}
}
fun swipeLayoutActivity(applicationPackage: String,packageName: String,activityClass: String,bindingName: String,layoutName: String
)
package ${packageName};import android.os.Bundle;
import androidx.annotation.Nullable;import dora.BaseActivity;
import dora.widget.pull.SwipeLayout;import ${applicationPackage}.R;
import ${applicationPackage}.databinding.${bindingName};public class ${activityClass} extends BaseActivity${bindingName} {Overrideprotected int getLayoutId() {return R.layout.${layoutName};}Overridepublic void initData(Nullable Bundle savedInstanceState, ${bindingName} binding) {// TODO: Not yet implemented// For Example:// binding.swipeLayout.setOnSwipeListener(new SwipeLayout.OnSwipeListener() {//// Override// public void onRefresh(SwipeLayout swipeLayout) {// }// // Override// public void onLoadMore(SwipeLayout swipeLayout) {// }// });}
}DoraTemplateRecipe.kt新增生成代码的方法 fun RecipeExecutor.swipeLayoutActivityRecipe(moduleData: ModuleTemplateData,activityClass: String,activityTitle: String,layoutName: String,packageName: String
) {val (projectData, srcOut, resOut) moduleDatagenerateManifest(moduleData moduleData,activityClass activityClass,packageName packageName,isLauncher false,hasNoActionBar false,generateActivityTitle false)if (projectData.language Language.Kotlin) {save(swipeLayoutActivityKt(projectData.applicationPackage ?: packageName, packageName, activityClass,buildBindingName(layoutName), layoutName), srcOut.resolve(${activityClass}.${projectData.language.extension}))}if (projectData.language Language.Java) {save(swipeLayoutActivity(projectData.applicationPackage ?: packageName, packageName, activityClass,buildBindingName(layoutName), layoutName), srcOut.resolve(${activityClass}.${projectData.language.extension}))}save(swipeLayoutActivityXml(packageName, activityClass), resOut.resolve(layout/${layoutName}.xml))open(resOut.resolve(layout/${layoutName}.xml))}新增一个向导界面模板
/** Copyright (C) 2022 The Dora Open Source Project** Licensed under the Apache License, Version 2.0 (the License);* you may not use this file except in compliance with the License.* You may obtain a copy of the License at** http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an AS IS BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package com.dorachat.templates.recipesimport com.android.tools.idea.wizard.template.*
import com.android.tools.idea.wizard.template.impl.activities.common.MIN_API
import java.io.Fileobject SwipeLayoutActivityTemplate : Template {override val category: Categoryget() Category.Activityoverride val constraints: CollectionTemplateConstraintget() emptyList() // AndroidX, kotlinoverride val description: Stringget() 创建一个dora.BaseActivity来自https://github.com/dora4/doraoverride val documentationUrl: String?get() nulloverride val formFactor: FormFactorget() FormFactor.Mobileoverride val minSdk: Intget() MIN_APIoverride val name: Stringget() SwipeLayout DataBinding Activityoverride val recipe: Recipeget() {swipeLayoutActivityRecipe(it as ModuleTemplateData,activityClassInputParameter.value,activityTitleInputParameter.value,layoutNameInputParameter.value,packageName.value)}override val uiContexts: CollectionWizardUiContextget() listOf(WizardUiContext.ActivityGallery, WizardUiContext.MenuEntry, WizardUiContext.NewProject, WizardUiContext.NewModule)override val useGenericInstrumentedTests: Booleanget() falseoverride val useGenericLocalTests: Booleanget() falseoverride val widgets: CollectionWidget*get() listOf(TextFieldWidget(activityTitleInputParameter),TextFieldWidget(activityClassInputParameter),TextFieldWidget(layoutNameInputParameter),PackageNameWidget(packageName),LanguageWidget())override fun thumb(): Thumb {return Thumb { findResource(this.javaClass, File(template_activity.png)) }}val activityClassInputParameter stringParameter {name Activity Namedefault MainActivityhelp The name of the activity class to createconstraints listOf(Constraint.CLASS, Constraint.UNIQUE, Constraint.NONEMPTY)suggest { layoutToActivity(layoutNameInputParameter.value) }}var layoutNameInputParameter: StringParameter stringParameter {name Layout Namedefault activity_mainhelp The name of the layout to create for the activityconstraints listOf(Constraint.LAYOUT, Constraint.UNIQUE, Constraint.NONEMPTY)suggest { activityToLayout(activityClassInputParameter.value) }}val activityTitleInputParameter stringParameter {name Titledefault Mainhelp The name of the activity. For launcher activities, the application titlevisible { false }constraints listOf(Constraint.NONEMPTY)suggest { buildClassNameWithoutSuffix(activityClassInputParameter.value, Activity) }}val packageName defaultPackageNameParameter
}将向导界面模板添加到向导模板提供者
/** Copyright (C) 2022 The Dora Open Source Project** Licensed under the Apache License, Version 2.0 (the License);* you may not use this file except in compliance with the License.* You may obtain a copy of the License at** http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an AS IS BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package com.dorachat.templates.recipesimport com.android.tools.idea.wizard.template.WizardTemplateProviderclass DoraTemplateWizardProvider: WizardTemplateProvider() {override fun getTemplates() listOf(DataBindingActivityTemplate,DataBindingFragmentTemplate,MenuPanelActivityTemplate,SwipeLayoutActivityTemplate,MVVMActivityTemplate,MVVMFragmentTemplate)
}更新版本日志
patchPluginXml {version.set(${project.version})sinceBuild.set(213)untilBuild.set(223.*)changeNotes.set(h31.4/h3新增对SwipeLayout的支持br/h31.3/h3新增对MenuPanel的支持br/h31.2/h3新增对BaseVMActivity和BaseVMFragment的支持br/h31.1/h3initData()方法中增加databinding参数br/h31.0/h3初始版本能够创建Java和Kotlin版本的MVVM Activiy和MVVM Fragmentbr/)
}代码讲解
DoraEmptyLayout为什么可以识别SwipeLayout里面的RecyclerView?
open fun showContent() {runMain {if (contentView is RecyclerView) {if ((contentView as RecyclerView).adapter null ||(contentView as RecyclerView).adapter!!.itemCount 0) {showEmpty()returnrunMain}}// 1.12开始支持遍历容器确保一个EmptyLayout里面只能放一个RecyclerViewif (contentView is ViewGroup) {for (i in 0 until childCount) {val view getChildAt(i)if (view is RecyclerView) {if (view.adapter null ||view.adapter!!.itemCount 0) {showEmpty()returnrunMain}}}}val view showStateView(STATE_CONTENT)this.content?.invoke(view)}
}我们可以看到DoraEmptyLayout类从1.11升级到1.12版本的过程中新增了以下代码来支持SwipeLayout。
if (contentView is ViewGroup) {for (i in 0 until childCount) {val view getChildAt(i)if (view is RecyclerView) {if (view.adapter null ||view.adapter!!.itemCount 0) {showEmpty()returnrunMain}}}
} 这样就不难理解了如果遇到了刷新布局如SwipeLayout就再解析一层找RecyclerView。当然一个DoraEmptyLayout里面只能放一个RecyclerView。
SwipeLayout是何方神圣
支持暗色模式支持英语、阿拉伯语、德语、西班牙语、法语、意大利语、日语、韩语、葡萄牙语、俄语、泰语、越南语、简体中文和繁体中文等世界10几个主流语种支持自定义可拉动的内容布局支持插件创建与DoraEmptyLayout空态布局完美兼容需要使用v1.12以上版本界面丝滑
通过PullableRecyclerView源码来看怎么自定义可拉动的内容布局
package dora.widget.pullimport android.content.Context
import android.util.AttributeSet
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import dora.widget.swipelayout.Rclass PullableRecyclerView JvmOverloads constructor(context: Context, attrs: AttributeSet? null,defStyle: Int 0): RecyclerView(context, attrs, defStyle), Pullable {private var canPullDown trueprivate var canPullUp trueinit {val a context.obtainStyledAttributes(attrs, R.styleable.PullableRecyclerView, defStyle, 0)canPullDown a.getBoolean(R.styleable.PullableRecyclerView_dview_canPullDown, canPullDown)canPullUp a.getBoolean(R.styleable.PullableRecyclerView_dview_canPullUp, canPullUp)a.recycle()}fun setCanPullDown(canPullDown: Boolean) {this.canPullDown canPullDown}fun setCanPullUp(canPullUp: Boolean) {this.canPullUp canPullUp}override fun canPullDown(): Boolean {return if (canPullDown) {val layoutManager layoutManager as LinearLayoutManager?val adapter adapterif (adapter ! null) {return if (adapter.itemCount 0) {false} else layoutManager!!.findFirstVisibleItemPosition() 0 getChildAt(0).top 0}false} else {false}}override fun canPullUp(): Boolean {if (canPullUp) {val layoutManager layoutManager as LinearLayoutManagerif (adapter ! null adapter?.itemCount!! 0) {return false} else if (layoutManager.findLastVisibleItemPosition() ((adapter as Adapter).itemCount - 1)) {// 滑到底部了if (getChildAt(layoutManager.findLastVisibleItemPosition() - layoutManager.findFirstVisibleItemPosition()) ! null getChildAt(layoutManager.findLastVisibleItemPosition()- layoutManager.findFirstVisibleItemPosition()).bottom measuredHeight) {return true}}return false} else {return false}}
}它实现了一个顶层接口Pullable通过canPullDown()和canPullUp()两个方法来在运行时动态判断可不可以下拉刷新和上拉加载。
private var canPullDown true
private var canPullUp true里面提供了两个属性表示是否有下拉和上拉能力如果设置为false则无论条件达成与否都不能进行刷新和加载。
dora.widget.pull.PullableRecyclerViewandroid:idid/recyclerViewandroid:layout_widthmatch_parentandroid:layout_heightmatch_parentandroid:backgroundcolor/colorPanelBgapp:dview_canPullDowntrueapp:dview_canPullUpfalse/可以通过属性设置这两个变量比如不需要上拉加载就把上拉的设置为falseapp:dview_canPullUp“false”。
设置完成刷新和加载的监听
binding.swipeLayout.setOnSwipeListener(new SwipeLayout.OnSwipeListener() {Overridepublic void onRefresh(SwipeLayout swipeLayout) {}Overridepublic void onLoadMore(SwipeLayout swipeLayout) {}
});通过调用swipeLayout的refreshFinish(state)和loadMoreFinish(state)来结束刷新和加载状态。
const val SUCCEED 0
const val FAIL 1有成功和失败两种状态可以设置。所以你在onRefresh()或onLoadMore()的最后一行调用刷新状态即可。
源码链接
下拉刷新https://github.com/dora4/dview-swipe-layout
空态布局https://github.com/dora4/dview-empty-layout
代码生成插件https://github.com/dora4/dora-studio-plugin