原生的效果图是这样,自己写的比较粗糙

刚开始看到这的时候,我还想着自定义一个viewGroup。后来写出来感觉效果太生硬,就是根据触摸事件来移动。
然后过了一段时间,我想着看下原生的咋弄的,就用eclipse带的那个布局查看器,看了下它的布局,发现了一个weatherScrollView的自定义控件,里边就是个线性布局包裹着所有的控件了,这这和我想的差距有点大啊。。
不过仔细想想,这滑动的这部分好像也就是一个线性布局,只不过有一部分是隐藏的,慢慢放出来而已。
有了思路就好解决了。先弄几个粗的布局,如下
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:background="#1190df"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:id="@+id/rela_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout
android:id="@+id/layout_location_date"
android:layout_width="match_parent"
android:background="#1190df"
android:layout_height="100dp">
<LinearLayout
android:id="@+id/layout_location"
android:layout_centerHorizontal="true"
android:orientation="horizontal"
android:layout_above="@+id/layout_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:src="@drawable/ic_launcher_background"
android:layout_width="20dp"
android:layout_height="20dp" />
<TextView
android:id="@+id/tv_location"
android:text="静安"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:id="@+id/layout_date"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:text="4月27日,星期五 14:00"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</RelativeLayout>
<LinearLayout
android:id="@+id/layout_temperature"
android:layout_centerHorizontal="true"
android:layout_below="@+id/layout_location_date"
android:orientation="horizontal"
android:gravity="center_vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:src="@drawable/adp_global_launcher_icon"
android:layout_width="25dp"
android:layout_height="25dp" />
<TextView
android:text="26℃"
android:textSize="35sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<TextView
android:id="@+id/tv_weather"
android:layout_centerHorizontal="true"
android:layout_below="@+id/layout_temperature"
android:text="多云"
android:textSize="17sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<LinearLayout
android:id="@+id/layout_aqi"
android:layout_centerHorizontal="true"
android:layout_below="@+id/tv_weather"
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:text="AQI 103(轻度污染)"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</RelativeLayout>
<com.charliesong.demo0327.weather.WeatherScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/sv"
android:overScrollMode="never"
android:scrollbars="none"
android:layout_marginTop="180dp"
android:orientation="vertical" >
<LinearLayout
android:orientation="vertical"
android:paddingTop="180dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/layout222"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:layout_width="match_parent"
android:layout_height="20dp"
android:text="every hour" />
<ImageView
android:layout_width="match_parent"
android:adjustViewBounds="true"
android:layout_height="wrap_content"
android:src="@drawable/per_hour_temperature" />
<TextView
android:layout_width="match_parent"
android:layout_height="20dp"
android:text="every day" />
</LinearLayout>
<LinearLayout
android:id="@+id/layout333"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="@+id/tv_hidden"
android:layout_width="match_parent"
android:text="200dp是我"
android:layout_marginTop="-220dp"
android:textSize="33sp"
android:gravity="center"
android:layout_height="220dp"
android:background="@drawable/per_hour_temperature" />
<TextView
android:id="@+id/layout_show"
android:layout_width="match_parent"
android:text="100dp是我"
android:textSize="33sp"
android:gravity="center"
android:layout_height="100dp"
android:background="@drawable/day_weather" />
</LinearLayout>
<LinearLayout
android:id="@+id/layout444"
android:background="#440000ff"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:layout_width="match_parent"
android:layout_height="20dp"
android:text="layout4......." />
<ImageView
android:layout_width="match_parent"
android:adjustViewBounds="true"
android:layout_height="wrap_content"
android:src="@drawable/today_intro" />
<TextView
android:layout_width="match_parent"
android:layout_height="20dp"
android:text="layout4 last" />
</LinearLayout>
</LinearLayout>
</com.charliesong.demo0327.weather.WeatherScrollView>
</FrameLayout>
android:id="@+id/layout333" 这个里边的第一个布局tv_hidden就是默认隐藏的东西了。当然了原生的这里不是这个,我们就用个textview替代下。
核心代码如下,很简单,就是在滚动的时候修改下那个tv_hidden的marginTop
import android.content.Context
import android.graphics.Canvas
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import android.widget.LinearLayout
import android.widget.ScrollView
import com.charliesong.demo0327.R
/**
* Created by charlie.song on 2018/4/27.
*/
class WeatherScrollView:ScrollView{
constructor(context: Context?) : super(context){
initSome()
}
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs){
initSome()
}
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr){
initSome()
}
private fun initSome(){
dp220= (context.resources.displayMetrics.density*220).toInt();
}
lateinit var hiddenView: View;
var dp220=220;//这个就是那个默认隐藏的控件的高度,在xml里这个控件初始的时候设置了android:layout_marginTop="-220dp",也就是不可见的
override fun draw(canvas: Canvas?) {
super.draw(canvas) //简单看下scrollview的代码就可以知道,滚动的时候它会调用这个修改子控件的位置
if(!touch){
return
}
hiddenView=findViewById(R.id.tv_hidden) //那个默认不可见的布局,也即是marginTop为负的控件本身的高度
var result=scrollY-dp220;
if(result<=0){
var params= hiddenView.layoutParams as LinearLayout.LayoutParams
params.topMargin=result //不停的修改topMargin直到完全可见
hiddenView.layoutParams=params
}
onScrollChangeListener?.run {
onScroollY(scrollY.toFloat()) //这回掉就是为了处理下上边的动画,
}
}
var touch=false
override fun onTouchEvent(ev: MotionEvent): Boolean {
var result= super.onTouchEvent(ev)
if(ev.action==MotionEvent.ACTION_DOWN){
touch=true
}
if(ev.action==MotionEvent.ACTION_UP||ev.action==MotionEvent.ACTION_CANCEL){
touch=false
val dp180=dp220*180/220; //180是我们默认设置的滚动这部分距离最高点的padding。滚动一半我们就还原,滚动超过一半就让它滚到顶部
if(scrollY<dp180){
if(scrollY<dp180/2){
smoothScrollTo(0,0)
}else{
smoothScrollTo(0,dp180)
}
onScrollChangeListener?.run {
onScroollY(scrollY.toFloat())
}
}
}
return result
}
var onScrollChangeListener:ScrollChangeListener?=null
}
接口在这里
interface ScrollChangeListener{
abstract fun onScroollY(yScroll:Float)
}
代码中使用也简单,就是处理下动画,如果不需要处理,那java里啥也不用写了
实在懒得处理,就简单弄了下平移x和y.看下效果而已
var dp180=180f
var intervalLoation=0;
var intervalDate=0
var intervalTemperature=0
override fun onCreate(arg0: Bundle?) {
super.onCreate(arg0)
setContentView(R.layout.activity_weather2)
dp180=resources.displayMetrics.density*180
sv.onScrollChangeListener=object :ScrollChangeListener{
override fun onScroollY(yScroll: Float) {
if(intervalLoation==0){
intervalLoation=layout_location.left
intervalDate=layout_date.left
intervalTemperature=layout_temperature.left
}
if(yScroll<dp180){
layout_location.translationX=(-yScroll/dp180)*intervalLoation
layout_date.translationX=(-yScroll/dp180)*intervalDate
layout_location.translationY=(-yScroll/dp180)*40
layout_date.translationY=(-yScroll/dp180)*40
layout_temperature.translationX=200*(yScroll/dp180)
layout_temperature.translationY=(-yScroll/dp180)*80
}
}
}
}
网友评论