日期: 2021 年 4 月 23 日

Android常用控件用法–SeekBar

SeekBar
*近在开发项目时,其中用到了控件SeekBar,觉得它的用法比较多,有必要做一个记录,以备以后快速上手。

常常需要自定义已列出,直接上用法

—-1—- android:thumb:自定义滑块。
<SeekBar
android:id=”@+id/sound”
android:layout_width=”150px”
android:layout_height=”10px”
android:max=”100″ //设置拖动条*大值
android:progress=”10″ //设置拖动条当前值
android:progressDrawable=”@layout/seekbar_style” //拖动条样式
android:thumb=”@layout/thumb” /> //滑块样式

thumb.xml:

<?xml version=”1.0″ encoding=”UTF-8″?>
<selector xmlns:android=”http://schemas.android.com/apk/res/android”>
<!– 按下状态 –>
<item
android:state_pressed=”true”
android:drawable=”@drawable/thumb1″
/>

<!– 普通无焦点状态 –>
<item
android:state_focused=”false”
android:state_pressed=”false”
android:drawable=”@drawable/thumb2″
/>
</selector>
—2—–拖动条的高度—————-
设置高度的时候一定要用

android:layout_height=”wrap_content”
android:maxHeight=”6px”
android:minHeight=”6px”
—3—- 拖动条的颜色—————-
android:progressDrawable=”@layout/seekbar_style”

seekbar_style.xml

<?xml version=”1.0″ encoding=”utf-8″?>
<layer-list
xmlns:android=”http://schemas.android.com/apk/res/android”>
<!–背景–>
<item android:id=”@android:id/background” >
<shape>
<corners android:radius=”5dp” />
<solid android:color=”#ffacacac”/>
</shape>
</item>
<item android:id=”@android:id/progress” >
<clip>
<shape>
<corners android:radius=”5dp” />
<solid android:color=”#00bbff”/>
</shape>
</clip>
</item>
</layer-list>
—–4——增大拖动条的触摸范围(热区范围)——
// 增大view的可点击范围
public void addDefaultScreenArea(final View view, final int top,final int bottom,final int left,final int right) {
Log.v(“AudioSeekbarActivity2”, “—–>>>addDefaultScreenArea = “);
final View parent = (View) view.getParent();
parent.post(new Runnable() {
public void run() {
Rect bounds = new Rect();
view.setEnabled(true);
view.getHitRect(bounds);
bounds.top -= top;
bounds.bottom += bottom;
bounds.left -= left;
bounds.right += right;
TouchDelegate touchDelegate = new TouchDelegate(bounds, view);
if (View.class.isInstance(view.getParent())) {
((View) view.getParent()).setTouchDelegate(touchDelegate);
}
}
});
}

关于abiFilters的使用

前言
*近项目中遇到了要使用opencv的情况,涉及到了abi兼容的选择。因为如果全部都适配的话,包很大,这样兼容那些用户数*少的cpu就很不划算,所以我只适配了armeabi-v7a这一个。但是今天在x64-v8a的模拟器上看的时候,提示我的library.so文件找不到,我记得这个应该是向下兼容的,但是出现这种情况很奇怪,于是我就在网上找了找答案。

解决方法:abiFilters
在app的gradle的defaultConfig里面加上这么一句

ndk {
abiFilters “armeabi-v7a” // 指定要ndk需要兼容的架构(这样其他依赖包里mips,x86,armeabi,arm-v8之类的so会被过滤掉)
}

这句话的意思就是指定ndk需要兼容的架构,把除了v7a以外的兼容包都过滤掉,只剩下一个v7a的文件夹。用了这个方法之后,确实解决了问题。这就是解决方法。

具体分析
其实这个方法我开始是很奇怪的,我明明没有指定其他的兼容框架,为什么会需要一个过滤。我打来了apk的包,找到了里面的lib目录,发现里面有很多的兼容目录,然后看到里面目录里面的是一个fresco的.so文件。也就是说,fresco做了各个平台的兼容,所以它创建了各个兼容平台的目录。因为只要出现了这个目录,系统就只会在这个目录里找.so文件而不会遍历其他的目录,所以就出现了之前找不到.so文件的情况(因为其他目录没有我的.so文件)。

总结
为了决定*后适配的abi版本,我下载了排行前几名的app,然后打开之后发现,他们基本上只适配了一个armeabi,少数会再加上v7a。我了解到的情况是armeabi性能较差,但是兼容性*好,v7a对于浮点计算的cpu来说性能更好,不兼容不支持浮点运算的cpu。我想到的是目前的手机cpu*大多数应该是支持浮点运算的,而且安卓从2.2开始就支持v7a,所以v7a的兼容性应该也不是问题。(不知道对不对,谁能明确一下的,恳请指正)
无论如何,abiFilters还是应该添加的。

Android Studio gardle 配置 ndk 指定 ABI: abiFilters 详解

一、ABI 是什么
ABI 是 Application Binary Interface 的缩写。

不同 Android 手机使用不同的 CPU,因此支持不同的指令集。CPU 与指令集的每种组合都有其自己的应用二进制界面(或 ABI)。 ABI 可以非常精确地定义应用的机器代码在运行时如何与系统交互。 您必须为应用要使用的每个 CPU 架构指定 ABI。

典型的 ABI 包含以下信息:

机器代码应使用的 CPU 指令集。
运行时内存存储和加载的字节顺序。
可执行二进制文件(例如程序和共享库)的格式,以及它们支持的内容类型。
用于解析内容与系统之间数据的各种约定。这些约定包括对齐限制,以及系统如何使用堆栈和在调用函数时注册。
运行时可用于机器代码的函数符号列表 – 通常来自非常具体的库集。
二、如何在 gardle 中配置
默认情况下,cmake 会输出 4 种 ABI(”armeabi-v7a” , “arm64-v8a”, “x86”, “x86_64″),如下所示:

%title插图%num

我们也可以通过 abiFilters 来指定我们需要的 ABI:

%title插图%num

abiFilters “armeabi”, “armeabi-v7a” , “arm64-v8a”, “x86”, “x86_64”, “mips”, “mips64”

三、支持的 ABI 详解

%title插图%num

Android底部导航栏,三种风格和实现

一、效果图展示

%title插图%num

如果动图没有动的话,也可以看下面这个静态图

%title插图%num

以下挨个分析每个的实现,这里只做简单的效果展示,大家可以基于目前代码做二次开发。

二、BottomNavigationView
这是 Google 给我们提供的一个专门用于底部导航的 View,你只需要在新建 Activity 的时候选择 “Bottom Navigation Activity”,IDE 就会自动使用 BottomNavigationView 帮你生成好相应的代码了。

1. 在 xml 中使用
<android.support.design.widget.BottomNavigationView
android:id=”@+id/navigation”
android:layout_width=”0dp”
android:layout_height=”wrap_content”
android:layout_marginEnd=”0dp”
android:layout_marginStart=”0dp”
android:background=”?android:attr/windowBackground”
app:layout_constraintBottom_toBottomOf=”parent”
app:layout_constraintLeft_toLeftOf=”parent”
app:layout_constraintRight_toRightOf=”parent”
app:menu=”@menu/navigation” />
这里面唯一要注意的就是 app:menu 属性了,它指定了你的导航栏显示的页面菜单是怎样的。

2. menu 的布局文件
<?xml version=”1.0″ encoding=”utf-8″?>
<menu xmlns:android=”http://schemas.android.com/apk/res/android”>

<item
android:id=”@+id/navigation_home”
android:icon=”@drawable/ic_home_black_24dp”
android:title=”@string/title_home” />

<item
android:id=”@+id/navigation_dashboard”
android:icon=”@drawable/ic_dashboard_black_24dp”
android:title=”@string/title_dashboard” />

<item
android:id=”@+id/navigation_notifications”
android:icon=”@drawable/ic_notifications_black_24dp”
android:title=”@string/title_notifications” />

</menu>
3. 在 Activity 中调用
private TextView mTextMessage;

private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
= new BottomNavigationView.OnNavigationItemSelectedListener() {

@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.navigation_home:
mTextMessage.setText(R.string.title_home);
return true;
case R.id.navigation_dashboard:
mTextMessage.setText(R.string.title_dashboard);
return true;
case R.id.navigation_notifications:
mTextMessage.setText(R.string.title_notifications);
return true;
}
return false;
}
};

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_style1);

mTextMessage = findViewById(R.id.message);
BottomNavigationView navigation = findViewById(R.id.navigation);
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
}
这里的演示 code 都是 IDE 自动生成的,由于 BottomNavigationView 目前我还没有在项目中实际使用过,这里不做过多分析,使用起来不难,以上代码已经足以满足我们的基本使用要求了。

三、RadioGroup + ViewPager
这是一种比较常见了的,下面 4 个 tab 的导航按钮,可以切换不同的页面,这里页面使用了 ViewPager + Fragment 的组合,实现了滑动的页面效果,也可以不使用 ViewPager,这个根据产品的定义来使用即可。

1. 布局文件
<?xml version=”1.0″ encoding=”utf-8″?>
<RelativeLayout xmlns:android=”http://schemas.android.com/apk/res/android”
xmlns:tools=”http://schemas.android.com/tools”
android:layout_width=”match_parent”
android:layout_height=”match_parent”
tools:context=”.style2.Style2Activity”>

<android.support.v4.view.ViewPager
android:id=”@+id/fragment_vp”
android:layout_width=”match_parent”
android:layout_height=”match_parent”
android:layout_above=”@+id/tabs_rg” />

<RadioGroup
android:id=”@+id/tabs_rg”
android:layout_width=”match_parent”
android:layout_height=”56dp”
android:layout_alignParentBottom=”true”
android:background=”#dcdcdc”
android:orientation=”horizontal”>

<RadioButton
android:id=”@+id/today_tab”
style=”@style/Custom.TabRadioButton”
android:checked=”true”
android:drawableTop=”@drawable/tab_sign_selector”
android:text=”今日” />

<RadioButton
android:id=”@+id/record_tab”
style=”@style/Custom.TabRadioButton”
android:drawableTop=”@drawable/tab_record_selector”
android:text=”记录” />

<RadioButton
android:id=”@+id/contact_tab”
style=”@style/Custom.TabRadioButton”
android:drawableTop=”@drawable/tab_contact_selector”
android:text=”通讯录” />

<RadioButton
android:id=”@+id/settings_tab”
style=”@style/Custom.TabRadioButton”
android:drawableTop=”@drawable/tab_setting_selector”
android:text=”设置” />
</RadioGroup>
</RelativeLayout>
2. Activity 类
public class Style2Activity extends AppCompatActivity {

private ViewPager mViewPager;
private RadioGroup mTabRadioGroup;

private List<Fragment> mFragments;
private FragmentPagerAdapter mAdapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_style2);
initView();
}

private void initView() {
// find view
mViewPager = findViewById(R.id.fragment_vp);
mTabRadioGroup = findViewById(R.id.tabs_rg);
// init fragment
mFragments = new ArrayList<>(4);
mFragments.add(BlankFragment.newInstance(“今日”));
mFragments.add(BlankFragment.newInstance(“记录”));
mFragments.add(BlankFragment.newInstance(“通讯录”));
mFragments.add(BlankFragment.newInstance(“设置”));
// init view pager
mAdapter = new MyFragmentPagerAdapter(getSupportFragmentManager(), mFragments);
mViewPager.setAdapter(mAdapter);
// register listener
mViewPager.addOnPageChangeListener(mPageChangeListener);
mTabRadioGroup.setOnCheckedChangeListener(mOnCheckedChangeListener);
}

@Override
protected void onDestroy() {
super.onDestroy();
mViewPager.removeOnPageChangeListener(mPageChangeListener);
}

private ViewPager.OnPageChangeListener mPageChangeListener = new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

}

@Override
public void onPageSelected(int position) {
RadioButton radioButton = (RadioButton) mTabRadioGroup.getChildAt(position);
radioButton.setChecked(true);
}

@Override
public void onPageScrollStateChanged(int state) {

}
};

private RadioGroup.OnCheckedChangeListener mOnCheckedChangeListener = new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
for (int i = 0; i < group.getChildCount(); i++) {
if (group.getChildAt(i).getId() == checkedId) {
mViewPager.setCurrentItem(i);
return;
}
}
}
};

private class MyFragmentPagerAdapter extends FragmentPagerAdapter {

private List<Fragment> mList;

public MyFragmentPagerAdapter(FragmentManager fm, List<Fragment> list) {
super(fm);
this.mList = list;
}

@Override
public Fragment getItem(int position) {
return this.mList == null ? null : this.mList.get(position);
}

@Override
public int getCount() {
return this.mList == null ? 0 : this.mList.size();
}
}

}
这里唯一注意点的就是两个监听事件,要实现底部导航按钮和页面的联动。

四、带页面跳转功能的底部导航
很多 APP 的底部导航栏中间有一个很大的按钮,点击后通常是打开一个新的页面,这里我们要实现的就是这种底部导航。
依旧是使用 RadioGroup 来做,只不过中间一个 tab 我们先用一个空的 View 来占位,然后在这个 View 的位置放置一个较大的按钮来覆盖住。

1. 布局文件
<?xml version=”1.0″ encoding=”utf-8″?>
<RelativeLayout xmlns:android=”http://schemas.android.com/apk/res/android”
xmlns:tools=”http://schemas.android.com/tools”
android:layout_width=”match_parent”
android:layout_height=”match_parent”
tools:context=”.style3.Style3Activity”>

<FrameLayout
android:id=”@+id/fragment_container”
android:layout_width=”match_parent”
android:layout_height=”match_parent”
android:layout_above=”@+id/tabs_rg” />

<RadioGroup
android:id=”@+id/tabs_rg”
android:layout_width=”match_parent”
android:layout_height=”56dp”
android:layout_alignParentBottom=”true”
android:background=”#dcdcdc”
android:orientation=”horizontal”>

<RadioButton
android:id=”@+id/today_tab”
style=”@style/Custom.TabRadioButton”
android:checked=”true”
android:drawableTop=”@drawable/tab_sign_selector”
android:text=”今日” />

<RadioButton
android:id=”@+id/record_tab”
style=”@style/Custom.TabRadioButton”
android:drawableTop=”@drawable/tab_record_selector”
android:text=”记录” />

<View style=”@style/Custom.TabRadioButton” />

<RadioButton
android:id=”@+id/contact_tab”
style=”@style/Custom.TabRadioButton”
android:drawableTop=”@drawable/tab_contact_selector”
android:text=”通讯录” />

<RadioButton
android:id=”@+id/settings_tab”
style=”@style/Custom.TabRadioButton”
android:drawableTop=”@drawable/tab_setting_selector”
android:text=”设置” />
</RadioGroup>

<ImageView
android:id=”@+id/sign_iv”
android:layout_width=”80dp”
android:layout_height=”80dp”
android:layout_alignParentBottom=”true”
android:layout_centerHorizontal=”true”
android:background=”@android:color/transparent”
android:src=”@mipmap/sign” />
</RelativeLayout>
2. Activity 类
public class Style3Activity extends AppCompatActivity {

private RadioGroup mTabRadioGroup;
private SparseArray<Fragment> mFragmentSparseArray;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_style3);
initView();
}

private void initView() {
mTabRadioGroup = findViewById(R.id.tabs_rg);
mFragmentSparseArray = new SparseArray<>();
mFragmentSparseArray.append(R.id.today_tab, BlankFragment.newInstance(“今日”));
mFragmentSparseArray.append(R.id.record_tab, BlankFragment.newInstance(“记录”));
mFragmentSparseArray.append(R.id.contact_tab, BlankFragment.newInstance(“通讯录”));
mFragmentSparseArray.append(R.id.settings_tab, BlankFragment.newInstance(“设置”));
mTabRadioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
// 具体的fragment切换逻辑可以根据应用调整,例如使用show()/hide()
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
mFragmentSparseArray.get(checkedId)).commit();
}
});
// 默认显示*个
getSupportFragmentManager().beginTransaction().add(R.id.fragment_container,
mFragmentSparseArray.get(R.id.today_tab)).commit();
findViewById(R.id.sign_iv).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(Style3Activity.this, SignActivity.class));
}
});
}

}
注意:

如果这里你也想使用 ViewPager 来展示 Fragment 的话,一定要注意这里的 RadioGroup 中间有一个占位的 View,即两者的监听事件里,实现联动时要考虑多个这个 View 的存在。

Android EditText设置边框

Android EditText设置边框
简介
Android应用程序中给EditText设置边框。

效果图:

%title插图%num

快速开始
在res/drawable目录下新建样式文件 edit_background.xml。
<?xml version=”1.0″ encoding=”utf-8″?>
<layer-list xmlns:android=”http://schemas.android.com/apk/res/android”>

<item>
<shape
android:shape=”rectangle”>
<solid android:color=”#efefef”/>
<corners android:radius=”5dp”/>
<stroke
android:width=”1dp”
android:color=”#505050″/>
</shape>
</item>

布局文件中使用边框效果,/res/layout/activity_edit_text.xml。
android:background=”@drawable/edit_background”

<?xml version=”1.0″ encoding=”utf-8″?>
<android.support.constraint.ConstraintLayout 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=”.EditTextActivity”>

<TextView
android:id=”@+id/name_label”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:text=”账号:”
android:textSize=”18sp”
android:textColor=”#353535″
android:layout_marginTop=”60dp”
android:layout_marginStart=”60dp”
app:layout_constraintTop_toTopOf=”parent”
app:layout_constraintLeft_toLeftOf=”parent”/>

<EditText
android:id=”@+id/edit_name”
android:layout_width=”200dp”
android:layout_height=”40dp”
android:hint=”请输入账号”
android:gravity=”center”
android:inputType=”number”
android:background=”@drawable/edit_background”
android:layout_marginStart=”10dp”
app:layout_constraintTop_toTopOf=”@id/name_label”
app:layout_constraintBottom_toBottomOf=”@id/name_label”
app:layout_constraintLeft_toRightOf=”@id/name_label”/>

<TextView
android:id=”@+id/pwd_label”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:text=”密码:”
android:textSize=”18sp”
android:textColor=”#353535″
android:layout_marginTop=”40dp”
android:layout_marginStart=”60dp”
app:layout_constraintTop_toBottomOf=”@id/name_label”
app:layout_constraintLeft_toLeftOf=”parent”/>

<EditText
android:id=”@+id/edit_pwd”
android:layout_width=”200dp”
android:layout_height=”40dp”
android:hint=”请输入密码”
android:gravity=”center”
android:inputType=”textPassword”
android:background=”@drawable/edit_background”
android:layout_marginStart=”10dp”
app:layout_constraintTop_toTopOf=”@id/pwd_label”
app:layout_constraintBottom_toBottomOf=”@id/pwd_label”
app:layout_constraintLeft_toRightOf=”@id/pwd_label”/>

<Button
android:id=”@+id/btn_login”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:text=”ok”
android:layout_marginTop=”30dp”
android:layout_marginStart=”110dp”
app:layout_constraintLeft_toLeftOf=”parent”
app:layout_constraintTop_toBottomOf=”@id/pwd_label”/>

<Button
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:text=”Cancel”
android:layout_marginStart=”50dp”
app:layout_constraintTop_toTopOf=”@id/btn_login”
app:layout_constraintLeft_toRightOf=”@id/btn_login”/>

</android.support.constraint.ConstraintLayout>

 

获得“云安全联盟”STAR金牌认证,有哪些好处?

(1)访问。客户可以在CSA网站上查看认证,就像其他云服务提供商的客户一样,可以将其与其他云计算提供商区分开来,不仅可以通过CAIQ安全的云端控制台看到iland公司提供审计报告和iland的回答,也允许客户随时查看和下载这些文件。在审计时间方面,这是非常宝贵的。

(2)信心。客户可以相信,iland公司不断致力于提高云安全性,CSASTAR金牌认证证明了这一点。他们还可以随时从iland云安全控制台下载详细的文档以证明其云安全状态,并将其提供给自己的客户。这对于渠道合作伙伴或SaaS提供商尤为重要。

(3)尽职调查。CAIQ在尽职调查表中提供许多答案,如果不是*常见的问题,客户可以在iland云安全控制台上随时访问信息。这使得评估过程和审计与合规流程更加直接和高效。

(4)透明度。“安全云控制台”的CSASTAR金牌认证审核员报告将使客户不仅可以看到iland公司的实力,而且还可以看到iland有增长空间的领域。

什么是云存储,是怎么服务大家的,云存储有什么优点和缺点?

目前云存储的主要分为公有云、私有云和混合云。公有云通常指第三方提供商为用户提供的能够使用的云,公有云一般可通过互联网使用。这种云有许多实例,比如百度云盘、360云盘、OneDrive、阿里云、腾讯微云等等。私有云是为一个客户单独使用而构建的,因而提供对数据、安全性和服务质量的*有效控制。私有云可部署在企业数据中心的防火墙内,也可以将它们部署在一个安全的主机托管场所,私有云的核心属性是专有资源。私有云可以是企业提供的,也可以是自己架设的。公有云融合了公有云和私有云。私有云的安全性是超越公有云的,而公有云的计算资源又是私有云无法企及的。在这种矛与盾的情况下,混合云完美地解决了这个问题,它既可以利用私有云的安全,将内部重要数据保存在本地数据中心;同时也可以使用公有云的计算资源,更高效快捷地完成工作,相比私有云或是公有云都更完美。

说了这么多,只是说了云存储是什么玩意,它是怎么服务大家的,那云存储有什么优点和缺点呢?

云存储的优势:

1、存储管理可以实现自动化和智能化,所有的存储资源被整合到一起,客户看到的是单一存储空间。

2、提高了存储效率,通过虚拟化技术解决了存储空间的浪费,可以自动重新分配数据,提高了存储空间的利用率,同时具备负载均衡、故障冗余功能。

3、云存储能够实现规模效应和弹性扩展,降低运营成本,避免资源浪费。

隐患与缺点:

1、对于较为机密的数据,云存储服务提供商如何保证用户数据的安全性。

2、由于带宽和其他因素,云端访问性能可能比本地端储存设备的性能低。

3、当用户有特殊的数据使用记录追踪需求时(如公务部门依据规章和条例的要求,而需留存某些电磁记录时),使用云计算及云存储将使工作复杂度增加。

4、虽然可以一次提供给多人数据,或是传递数据给位于不同地方的人,但单人在转移数据的时候(例如文件由手机发送至电脑,或是由电脑发送至手机)因为需要重新“上传”与“下载”,会像是在绕远路一般,不如使用传输线的来的快。

5、传递大型数据的话,若是互联网断线或是云服务供应商出现差错,小则需要重新传输,大则有可能会导致数据上的差错或丢失。如何安全使用云存储?首先就是不要把重要数据或者涉及到个人隐私的数据放在云服务器上,毕竟没有*对安全的云存储。其次,重要的数据要做好本地备份,防止云服务中断或云数据丢失等意外情况。

再有,选择公有云的时候,要选择一些全球或比较知名的服务商,毕竟这些服务商在数据加密传输和加密储存方面都是有技术实力的。然后就是要设置强度比较高的密码,并且关闭自动登录选项,更换或者丢弃移动设备之前要清空设备保存的云服务登录密码,保证自身数据不被泄露。*后就是在使用云存储的时候避免上传一些色情元素的视频,或者敏感的信息。

PaaS建设有什么意义,能够给企业带来哪些价值?

1.实现应用运行环境的标准化,提升交付速度:通过容器的镜像技术保证开发测试和生产等诸多标准化,避免因应用运行环境不一致带来的各种故障和问题,同时,通过服务编排实现运行环境的自动化运维和快速交付,避免传统方式的应用系统运行复杂、交付周期较长等问题;

2.实现运维过程的高度自动化,降低运维成本:PaaS平台提供多种自动化运维工具管理应用集群系统,比如智能负载可以实时观测集群节点的变化并智能修改路由配置,自动伸缩可以实现不同业务负载下集群规模的自动调整等,多种管理功能的自动化减少人工运维工作量,节省运维成本;

3.有效提升基础资源的管理水平和硬件利用效率:PaaS平台资源的容器是基于操作系统的虚拟化,与IaaS基础环境实现解耦,平台自身的实现多数是应用较广的开发框架和标准API,能够有效提升资源管理水平,有效避免厂商绑定;同时,合理调整单个操作系统之上容器密度的有效部署,可以更好提升资源使用率,降低硬件采购成本;

4.有效实现软件研发的技术路径统一和把控研发质量:通过运行环境的标准化可真正做到全公司技术路线的精细把控,做到统一不同项目组的技术研发路线,通过部署工具的统一可以做到CI/CD思想的有效落地实施,有效提升软件研发过程的质量把控水平;

5.有效提升公司IT架构治理:相较于传统开发运维各司其职的模式,PaaS能有效实现devops思维的落地实施,推动企业IT流程和人员架构的企业治理,更好的提升IT部门各个研发团队的整体技术水平,从而更好的响应业务需求。

PaaS的研究过程中有哪些关键技术点和难点,一般市场是如何选择的?

PaaS作为一个综合性的平台,在以」容器+编排引擎」的基础上有诸多关键技术点和难点,本次主要以开源框架和一些市场产品为依托,主要讲述关键点的实现

1.容器技术的选择:容器技术是整个平台的基石,犹如开发web需要选择开发语言一样,目前有docker和garden两种主流技术,自研技术选择时尽量选择技术相对成熟、企业应用案例相对较多、技术生态圈发展更多的技术,一般建议选择docker,如果华为的PaaS产品初期选择garden,目前也已转向了docker,docker已经成为一种事实上的标准。

2.编排引擎的选择:编排引擎的选择一般会依赖容器技术路线的选择,比如docker容器可以选择kubernetes、swarm等框架,garden可以选择cloudfoundry,并且仅此选择。在BAT、华为、京东等互联网公司中,选择docker系的产品更多的选择了kubernetes,或许源于此框架出自google大家之手

3.元数据存储的框架选择:由于整个PaaS的元数据需要一个高可用的存储结构,以便用作服务发现或共享元数据配置的相关元数据信息。基于zookeeper的性能和复杂性等问题考虑,更多的选择etcd框架进行使用,openshift、阿里等产品均采用了此框架

4.PaaS容器网络的选择:容器的网络隔离是PaaS资源隔离的一个重要组成部分,每个容器的网络多采用内部SDN网络,SDN网络的实现技术各不相同,一般主要考虑因素是网络的性能和网络变化的灵活性等因素。开源kubernetes采用flannel框架,openshift的产品中考虑到网络性能等采用了openvswitch,京东在经过各种研究后采用了基于BGP路由方式的Calico

5.日志框架的选择:在集群环境中如何管理不同节点的日志是一个重要的问题,并且目前有一套成熟的解决方案。ElasticSearch+Logstash+Kinana(ELK)已成为一种通用解决方案

6.负载均衡的选择:负载均衡需要在容器集群的容器成员发生变化时能够自动感知和自动修改路由策略,硬件F5和软负载HAProxy、Nginx均可做负载均衡,鉴于HAProxy的灵活性,更多的产品或者企业落地均选择了HAProxy

7.域名的使用:容器集群中的某个应用可以视作一个对外提供的服务,如果采用IP,一方面不方便记忆,一方面IP有可能改变,因此PaaS产品多采用泛域名的形式,将对外提供服务的IP地址和域名关联对应,然后再提供一个route记录对外提供服务的IP地址(frontend)和内部集群IP地址(backend),这样就可以实现从外部域名到内部集群IP地址的访问。

PaaS平台的建设是一个长期的过程,需要不断持续的进行迭代优化,并且随着在PaaS之上运行应用系统的增多和使用经验的不断丰富,对PaaS平台会有更多深入的认知和体会。因此我们也希望论坛上从事这块研究和实践的朋友能够更多的进行技术交流,从而加深技术了解,让PaaS在企业内部更好的发挥其价值和优势。

【iOS】简单易用的折线图控件

先来看下效果图:

%title插图%num

基本实现以下功能:

支持自定义Y轴坐标数
支持自定义X轴显示索引
添加参考线、点击标线
支持自定义弹出说明视图
·····
Demo见github YASimpleGraph,喜欢的话请star下^_^

使用说明
YASimpleGraph 目前已经支持CocoaPods,可以在很短的时间内被添加到任何工程中。

安装
YASimpleGraph 的安装,*简单的方法是使用CocoaPods,在PodFile里添加如下:

pod ‘YASimpleGraph’, ‘~> 0.0.1’
1
或者直接将YASimpleGraphView.h和YASimpleGraphView.m两个源文件直接拖进自己的项目工程中。

集成
首先导入头文件
#import “YASimpleGraphView.h”
1
遵循相应协议
@interface ViewController () <YASimpleGraphDelegate>
1
初始化
//初始化数据源
allValues = @[@”20.00″,@”0″,@”110.00″,@”70″,@”80″,@”40″];
allDates = @[@”06/01″,@”06/02″,@”06/03″,@”06/04″,@”06/05″,@”06/06″];

//初始化折线图并设置相应属性
YASimpleGraphView *graphView = [[YASimpleGraphView alloc]init];
graphView.frame = CGRectMake(15, 200, 375-30, 200);
graphView.backgroundColor = [UIColor whiteColor];
graphView.allValues = allValues;
graphView.allDates = allDates;
graphView.defaultShowIndex = allDates.count-1;
graphView.delegate = self;
graphView.lineColor = [UIColor grayColor];
graphView.lineWidth = 1.0/[UIScreen mainScreen].scale;
graphView.lineAlpha = 1.0;
graphView.enableTouchLine = YES;
[self.view addSubview:graphView];

开始绘制
[graphView startDraw];
1
实现相应协议
//自定义X轴 显示标签索引
– (NSArray *)incrementPositionsForXAxisOnLineGraph:(YASimpleGraphView *)graph {
return @[@0,@1,@2,@3,@4,@5];
}

//Y轴坐标点数
– (NSInteger)numberOfYAxisLabelsOnLineGraph:(YASimpleGraphView *)graph {
return 5;
}

//自定义popUpView
– (UIView *)popUpViewForLineGraph:(YASimpleGraphView *)graph {

UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, 0, 0)];
label.backgroundColor = [UIColor colorWithRed:146/255.0 green:191/255.0 blue:239/255.0 alpha:1];
label.numberOfLines = 0;
label.font = [UIFont systemFontOfSize:10];
label.textAlignment = NSTextAlignmentCenter;
return label;
}

//修改相应点位弹出视图
– (void)lineGraph:(YASimpleGraphView *)graph modifyPopupView:(UIView *)popupView forIndex:(NSUInteger)index {
UILabel *label = (UILabel*)popupView;
NSString *date = [NSString stringWithFormat:@”%@”,allDates[index]];
NSString *str = [NSString stringWithFormat:@” %@ \n %@元 “,date,allValues[index]];

CGRect rect = [str boundingRectWithSize:CGSizeMake(MAXFLOAT, 40) options:NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:10]} context:nil];

[label setFrame:CGRectMake(0, 0, rect.size.width, rect.size.height)];
label.textColor = [UIColor whiteColor];
label.text = str;
}

完成上述步骤,折线图控件已经集成到我们的项目中了,当然YASimpleGraph还提供了一系列的对外属性变量,使我们可以高度自定义折线图控件,如下:

/// The line color
@property (nonatomic, strong) UIColor *lineColor;

/// The line width
@property (nonatomic, assign) CGFloat lineWidth;

/// The line alpha
@property (assign, nonatomic) float lineAlpha;

/// The Dot color
@property (nonatomic, strong) UIColor *dotColor;

/// The Dot borderColor
@property (nonatomic, strong) UIColor *dotBorderColor;

/// The Dot width
@property (nonatomic, assign) CGFloat dotWidth;

/// The Dot borderWidth
@property (nonatomic, assign) CGFloat dotBorderWidth;

/// The dashLine color
@property (nonatomic, strong) UIColor *dashLineColor;

/// The dashLine width
@property (nonatomic, assign) CGFloat dashLineWidth;

/// The bottomLine color
@property (nonatomic, strong) UIColor *bottomLineColor;

/// The bottomLine width
@property (nonatomic, assign) CGFloat bottomLineHeight;

····

等等一系列,具体可参考YASimpleGraphView.h

实现过程
实现过程大致分为以下几步:

draw 坐标轴&点、参考线
draw 数据点、折线
处理手势点击
简要列出上述3步中需要注意的一些地方:

a. 横坐标轴根据点的个数直接等分就好,纵坐标轴有点难度,这里参考了同事的纵坐标取整算法和*小值优化,实现主要如下:

– (NSInteger) calcIntegerDeltaValue:(double) maxValue minValue:(double) minValue{
NSInteger integerDetla = ceil((maxValue – minValue) / (numberOfYAxis-1));
//对得到的整数进一步取整 如: 101 -> 110, 1001 -> 1100
if (integerDetla == 0) { //值为0的水平直线则返回100一个值的间距
return 100;
}else{
return [self ajustIntegerValue:integerDetla];
}

}

– (NSInteger)ajustIntegerValue:(NSInteger) origalValue{
if (origalValue < 100) {
return origalValue;
}else{
NSInteger base = origalValue;
NSInteger round = 1;
while (origalValue > 100) {
origalValue = origalValue / 10;
round *= 10;
}
return base – base % round + round;
}
}

24
b. 折线直接连接坐标点即可,当画曲线时,为使曲线更加曲滑,采取两点之间两次二次贝塞尔,即先取中点,然后分别对起始点进行二次贝塞尔,具体实现如下:

+ (UIBezierPath *)quadCurvedPathWithPoints:(NSArray *)points {
UIBezierPath *path = [UIBezierPath bezierPath];

NSValue *value = points[0];
CGPoint p1 = [value CGPointValue];
[path moveToPoint:p1];

if (points.count == 2) {
value = points[1];
CGPoint p2 = [value CGPointValue];
[path addLineToPoint:p2];
return path;
}

for (NSUInteger i = 1; i < points.count; i++) {
value = points[i];
CGPoint p2 = [value CGPointValue];

CGPoint midPoint = midPointForPoints(p1, p2);
[path addQuadCurveToPoint:midPoint controlPoint:controlPointForPoints(midPoint, p1)];
[path addQuadCurveToPoint:p2 controlPoint:controlPointForPoints(midPoint, p2)];

p1 = p2;
}
return path;
}

static CGPoint midPointForPoints(CGPoint p1, CGPoint p2) {
return CGPointMake((p1.x + p2.x) / 2, (p1.y + p2.y) / 2);
}

static CGPoint controlPointForPoints(CGPoint p1, CGPoint p2) {
CGPoint controlPoint = midPointForPoints(p1, p2);
CGFloat diffY = fabs(p2.y – controlPoint.y);

if (p1.y < p2.y)
controlPoint.y += diffY;
else if (p1.y > p2.y)
controlPoint.y -= diffY;

return controlPoint;
}

友情链接: SITEMAP | 旋风加速器官网 | 旋风软件中心 | textarea | 黑洞加速器 | jiaohess | 老王加速器 | 烧饼哥加速器 | 小蓝鸟 | tiktok加速器 | 旋风加速度器 | 旋风加速 | quickq加速器 | 飞驰加速器 | 飞鸟加速器 | 狗急加速器 | hammer加速器 | trafficace | 原子加速器 | 葫芦加速器 | 麦旋风 | 油管加速器 | anycastly | INS加速器 | INS加速器免费版 | 免费vqn加速外网 | 旋风加速器 | 快橙加速器 | 啊哈加速器 | 迷雾通 | 优途加速器 | 海外播 | 坚果加速器 | 海外vqn加速 | 蘑菇加速器 | 毛豆加速器 | 接码平台 | 接码S | 西柚加速器 | 快柠檬加速器 | 黑洞加速 | falemon | 快橙加速器 | anycast加速器 | ibaidu | moneytreeblog | 坚果加速器 | 派币加速器 | 飞鸟加速器 | 毛豆APP | PIKPAK | 安卓vqn免费 | 一元机场加速器 | 一元机场 | 老王加速器 | 黑洞加速器 | 白石山 | 小牛加速器 | 黑洞加速 | 迷雾通官网 | 迷雾通 | 迷雾通加速器 | 十大免费加速神器 | 猎豹加速器 | 蚂蚁加速器 | 坚果加速器 | 黑洞加速 | 银河加速器 | 猎豹加速器 | 海鸥加速器 | 芒果加速器 | 小牛加速器 | 极光加速器 | 黑洞加速 | movabletype中文网 | 猎豹加速器官网 | 烧饼哥加速器官网 | 旋风加速器度器 | 哔咔漫画 | PicACG | 雷霆加速